===================================================================
@@ -5359,7 +5359,7 @@ extern tree do_friend (tree, tree, tree, tree,
/* in init.c */
extern tree expand_member_init (tree);
extern void emit_mem_initializers (tree);
-extern tree build_aggr_init (tree, tree, int,
+extern tree build_aggr_init (tree, tree, int, bool,
tsubst_flags_t);
extern int is_class_type (tree, int);
extern tree get_type_value (tree);
===================================================================
@@ -5539,7 +5539,8 @@ build_aggr_init_full_exprs (tree decl, tree init,
{
gcc_assert (stmts_are_full_exprs_p ());
- return build_aggr_init (decl, init, flags, tf_warning_or_error);
+ return build_aggr_init (decl, init, flags, /*delegating_cons_p=*/false,
+ tf_warning_or_error);
}
/* Verify INIT (the initializer for DECL), and record the
===================================================================
@@ -32,8 +32,10 @@ along with GCC; see the file COPYING3. If not see
static bool begin_init_stmts (tree *, tree *);
static tree finish_init_stmts (bool, tree, tree);
static void construct_virtual_base (tree, tree);
-static void expand_aggr_init_1 (tree, tree, tree, tree, int, tsubst_flags_t);
-static void expand_default_init (tree, tree, tree, tree, int, tsubst_flags_t);
+static void expand_aggr_init_1 (tree, tree, tree, tree, int, bool,
+ tsubst_flags_t);
+static void expand_default_init (tree, tree, tree, tree, int, bool,
+ tsubst_flags_t);
static void perform_member_init (tree, tree);
static tree build_builtin_delete_call (tree);
static int member_init_ok_or_else (tree, tree, tree);
@@ -501,7 +503,8 @@ perform_target_ctor (tree init)
tree type = current_class_type;
finish_expr_stmt (build_aggr_init (decl, init, LOOKUP_NORMAL,
- tf_warning_or_error));
+ /*delegating_cons_p=*/true,
+ tf_warning_or_error));
if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
{
tree expr = build_delete (type, decl, sfk_complete_destructor,
@@ -693,6 +696,7 @@ perform_member_init (tree member, tree init)
"uninitialized member %qD with %<const%> type %qT",
member, type);
finish_expr_stmt (build_aggr_init (decl, init, flags,
+ /*delegating_cons_p=*/false,
tf_warning_or_error));
}
}
@@ -1076,6 +1080,7 @@ emit_mem_initializers (tree mem_inits)
tf_warning_or_error),
arguments,
flags,
+ /*delegating_cons_p=*/false,
tf_warning_or_error);
expand_cleanup_for_base (subobject, NULL_TREE);
}
@@ -1242,7 +1247,7 @@ construct_virtual_base (tree vbase, tree arguments
exp = convert_to_base_statically (current_class_ref, vbase);
expand_aggr_init_1 (vbase, current_class_ref, exp, arguments,
- 0, tf_warning_or_error);
+ 0, /*delegating_cons_p=*/false, tf_warning_or_error);
finish_then_clause (inner_if_stmt);
finish_if_stmt (inner_if_stmt);
@@ -1448,7 +1453,8 @@ expand_member_init (tree name)
perform the initialization, but not both, as it would be ambiguous. */
tree
-build_aggr_init (tree exp, tree init, int flags, tsubst_flags_t complain)
+build_aggr_init (tree exp, tree init, int flags, bool delegating_cons_p,
+ tsubst_flags_t complain)
{
tree stmt_expr;
tree compound_stmt;
@@ -1513,7 +1519,7 @@ tree
destroy_temps = stmts_are_full_exprs_p ();
current_stmt_tree ()->stmts_are_full_exprs_p = 0;
expand_aggr_init_1 (TYPE_BINFO (type), exp, exp,
- init, LOOKUP_NORMAL|flags, complain);
+ init, LOOKUP_NORMAL|flags, delegating_cons_p, complain);
stmt_expr = finish_init_stmts (is_global, stmt_expr, compound_stmt);
current_stmt_tree ()->stmts_are_full_exprs_p = destroy_temps;
TREE_READONLY (exp) = was_const;
@@ -1524,7 +1530,7 @@ tree
static void
expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
- tsubst_flags_t complain)
+ bool delegating_cons_p, tsubst_flags_t complain)
{
tree type = TREE_TYPE (exp);
tree ctor_name;
@@ -1641,6 +1647,14 @@ expand_default_init (tree binfo, tree true_exp, tr
complete = build_special_member_call (exp, complete_ctor_identifier,
&parms2, binfo, flags,
complain);
+
+ if ((complain & tf_error)
+ && delegating_cons_p
+ && TREE_CODE (complete) == CALL_EXPR
+ && (DECL_ABSTRACT_ORIGIN (TREE_OPERAND (CALL_EXPR_FN (complete), 0))
+ == current_function_decl))
+ error ("constructor delegates to itself");
+
complete = fold_build_cleanup_point_expr (void_type_node, complete);
release_tree_vector (parms2);
@@ -1662,8 +1676,16 @@ expand_default_init (tree binfo, tree true_exp, tr
ctor_name = base_ctor_identifier;
rval = build_special_member_call (exp, ctor_name, &parms, binfo, flags,
complain);
- }
+ if ((complain & tf_error)
+ && delegating_cons_p
+ && ctor_name == complete_ctor_identifier
+ && TREE_CODE (rval) == CALL_EXPR
+ && (DECL_ABSTRACT_ORIGIN (TREE_OPERAND (CALL_EXPR_FN (rval), 0))
+ == current_function_decl))
+ error ("constructor delegates to itself");
+ }
+
if (parms != NULL)
release_tree_vector (parms);
@@ -1705,7 +1727,7 @@ expand_default_init (tree binfo, tree true_exp, tr
static void
expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags,
- tsubst_flags_t complain)
+ bool delegating_cons_p, tsubst_flags_t complain)
{
tree type = TREE_TYPE (exp);
@@ -1762,7 +1784,8 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tre
/* We know that expand_default_init can handle everything we want
at this point. */
- expand_default_init (binfo, true_exp, exp, init, flags, complain);
+ expand_default_init (binfo, true_exp, exp, init, flags, delegating_cons_p,
+ complain);
}
/* Report an error if TYPE is not a user-defined, class type. If
@@ -3497,7 +3520,9 @@ build_vec_init (tree base, tree maxindex, tree ini
if (digested)
one_init = build2 (INIT_EXPR, type, baseref, elt);
else if (MAYBE_CLASS_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
- one_init = build_aggr_init (baseref, elt, 0, complain);
+ one_init = build_aggr_init (baseref, elt, 0,
+ /*delegating_cons_p=*/false,
+ complain);
else
one_init = cp_build_modify_expr (baseref, NOP_EXPR,
elt, complain);
@@ -3632,7 +3657,9 @@ build_vec_init (tree base, tree maxindex, tree ini
elt_init = cp_build_modify_expr (to, NOP_EXPR, from,
complain);
else if (type_build_ctor_call (type))
- elt_init = build_aggr_init (to, from, 0, complain);
+ elt_init = build_aggr_init (to, from, 0,
+ /*delegating_cons_p=*/false,
+ complain);
else if (from)
elt_init = cp_build_modify_expr (to, NOP_EXPR, from,
complain);
@@ -3659,7 +3686,9 @@ build_vec_init (tree base, tree maxindex, tree ini
{
gcc_assert (type_build_ctor_call (type) || init);
if (CLASS_TYPE_P (type))
- elt_init = build_aggr_init (to, init, 0, complain);
+ elt_init = build_aggr_init (to, init, 0,
+ /*delegating_cons_p=*/false,
+ complain);
else
{
if (TREE_CODE (init) == TREE_LIST)
===================================================================
@@ -3777,6 +3777,7 @@ simplify_aggr_init_expr (tree *tp)
push_deferring_access_checks (dk_no_check);
call_expr = build_aggr_init (slot, call_expr,
DIRECT_BIND | LOOKUP_ONLYCONVERTING,
+ /*delegating_cons_p=*/false,
tf_warning_or_error);
pop_deferring_access_checks ();
call_expr = build2 (COMPOUND_EXPR, TREE_TYPE (slot), call_expr, slot);
===================================================================
@@ -0,0 +1,66 @@
+// PR c++/51424
+// { dg-do compile { target c++11 } }
+
+template <class T >
+struct S
+{
+ S() : S() {} // { dg-error "delegates to itself" }
+ S(int x) : S(x) {} // { dg-error "delegates to itself" }
+};
+
+struct B1
+{
+ B1() : B1() {} // { dg-error "delegates to itself" }
+ B1(int y) : B1(y) {} // { dg-error "delegates to itself" }
+};
+
+struct V1 : virtual B1
+{
+ V1() : B1() {}
+ V1(int x) : B1(x) {}
+};
+
+struct B2
+{
+ B2() : B2() {} // { dg-error "delegates to itself" }
+ B2(int y) : B2(y) {} // { dg-error "delegates to itself" }
+};
+
+struct V2 : virtual B2
+{
+ V2() : V2() {} // { dg-error "delegates to itself" }
+ V2(int x) : V2(x) {} // { dg-error "delegates to itself" }
+};
+
+struct B3
+{
+ B3() {}
+ B3(int y) {}
+};
+
+struct V3 : virtual B3
+{
+ V3() : V3() {} // { dg-error "delegates to itself" }
+ V3(int x) : V3(x) {} // { dg-error "delegates to itself" }
+};
+
+struct CE1
+{
+ constexpr CE1() : CE1() {} // { dg-error "delegates to itself" }
+ constexpr CE1(int x) : CE1(x) {} // { dg-error "delegates to itself" }
+};
+
+struct CEB2
+{
+ constexpr CEB2() : CEB2() {} // { dg-error "delegates to itself" }
+ constexpr CEB2(int x) : CEB2(x) {} // { dg-error "delegates to itself" }
+};
+
+struct CE2 : CEB2
+{
+ constexpr CE2() : CEB2() {}
+ constexpr CE2(int x) : CEB2(x) {}
+};
+
+S<int> s1;
+S<int> s2(1);
===================================================================
@@ -3,6 +3,6 @@ template <class T >
struct S
{
S() : S() {} // { dg-message "delegating constructors" }
-};
+}; // { dg-error "delegates to itself" "" { target *-*-* } 5 }
S<int> s;