diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index fcd44f072de..be5ebea1a3d 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,16 @@ +2011-12-05 Ville Voutilainen + Pedro LamarĂ£o + + Implement C++11 delegating constructors. + * cp-tree.h (enum cpp0x_warn_str): Add CPP0X_DELEGATING_CTORS. + * error.c (maybe_warn_cpp0x): Adjust. + * parser.c (cp_parser_mem_initializer_list): Use it. Diagnose + multiple initializers if a delegating initializer is present. + * call.c (build_special_member_call): Convert an assert into an if. + * init.c (perform_target_ctor): New. + (emit_mem_initializers): Use it. + (expand_member_init, expand_default_init): Adjust. + 2011-12-05 Paolo Carlini PR c++/51404 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 93d14be257b..d8fc4f1d2d5 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -6978,8 +6978,10 @@ build_special_member_call (tree instance, tree name, VEC(tree,gc) **args, current_in_charge_parm, integer_zero_node), current_vtt_parm, vtt); - gcc_assert (BINFO_SUBVTT_INDEX (binfo)); - sub_vtt = fold_build_pointer_plus (vtt, BINFO_SUBVTT_INDEX (binfo)); + if (BINFO_SUBVTT_INDEX (binfo)) + sub_vtt = fold_build_pointer_plus (vtt, BINFO_SUBVTT_INDEX (binfo)); + else + sub_vtt = vtt; if (args == NULL) { diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 3f4f4081f38..dccf485a60f 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -404,7 +404,9 @@ typedef enum cpp0x_warn_str /* non-static data member initializers */ CPP0X_NSDMI, /* user defined literals */ - CPP0X_USER_DEFINED_LITERALS + CPP0X_USER_DEFINED_LITERALS, + /* delegating constructors */ + CPP0X_DELEGATING_CTORS } cpp0x_warn_str; /* The various kinds of operation used by composite_pointer_type. */ diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 4940a783353..21d6781567e 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -3304,6 +3304,11 @@ maybe_warn_cpp0x (cpp0x_warn_str str) "user-defined literals " "only available with -std=c++11 or -std=gnu++11"); break; + case CPP0X_DELEGATING_CTORS: + pedwarn (input_location, 0, + "delegating constructors " + "only available with -std=c++11 or -std=gnu++11"); + break; default: gcc_unreachable (); } diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 7e9ad54706f..94bd34a2ce9 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -485,6 +485,30 @@ build_value_init_noctor (tree type, tsubst_flags_t complain) return build_zero_init (type, NULL_TREE, /*static_storage_p=*/false); } +/* Initialize current class with INIT, a TREE_LIST of + arguments for a target constructor. If TREE_LIST is void_type_node, + an empty initializer list was given. */ + +static void +perform_target_ctor (tree init) +{ + tree decl = current_class_ref; + tree type = current_class_type; + + finish_expr_stmt (build_aggr_init (decl, init, LOOKUP_NORMAL, + tf_warning_or_error)); + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) + { + tree expr = build_delete (type, decl, sfk_complete_destructor, + LOOKUP_NORMAL + |LOOKUP_NONVIRTUAL + |LOOKUP_DESTRUCTOR, + 0, tf_warning_or_error); + if (expr != error_mark_node) + finish_eh_cleanup (expr); + } +} + /* Initialize MEMBER, a FIELD_DECL, with INIT, a TREE_LIST of arguments. If TREE_LIST is void_type_node, an empty initializer list was given; if NULL_TREE no initializer was given. */ @@ -988,6 +1012,16 @@ emit_mem_initializers (tree mem_inits) if (!COMPLETE_TYPE_P (current_class_type)) return; + if (mem_inits + && TYPE_P (TREE_PURPOSE (mem_inits)) + && same_type_p (TREE_PURPOSE (mem_inits), current_class_type)) + { + /* Delegating constructor. */ + gcc_assert (TREE_CHAIN (mem_inits) == NULL_TREE); + perform_target_ctor (TREE_VALUE (mem_inits)); + return; + } + if (DECL_DEFAULTED_FN (current_function_decl)) flags |= LOOKUP_DEFAULTED; @@ -1318,8 +1352,9 @@ expand_member_init (tree name) tree virtual_binfo; int i; - if (current_template_parms) - return basetype; + if (same_type_p (basetype, current_class_type) + || current_template_parms) + return basetype; class_binfo = TYPE_BINFO (current_class_type); direct_binfo = NULL_TREE; @@ -1578,13 +1613,33 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags, else parms = make_tree_vector_single (init); - if (true_exp == exp) - ctor_name = complete_ctor_identifier; - else - ctor_name = base_ctor_identifier; - - rval = build_special_member_call (exp, ctor_name, &parms, binfo, flags, - complain); + if (exp == current_class_ref && current_function_decl + && DECL_HAS_IN_CHARGE_PARM_P (current_function_decl)) + { + /* Delegating constructor. */ + tree complete; + tree base; + complete = build_special_member_call (exp, complete_ctor_identifier, + &parms, binfo, flags, + complain); + base = build_special_member_call (exp, base_ctor_identifier, + &parms, binfo, flags, + complain); + rval = build3 (COND_EXPR, TREE_TYPE (complete), + build2 (EQ_EXPR, boolean_type_node, + current_in_charge_parm, integer_zero_node), + base, + complete); + } + else + { + if (true_exp == exp) + ctor_name = complete_ctor_identifier; + else + ctor_name = base_ctor_identifier; + rval = build_special_member_call (exp, ctor_name, &parms, binfo, flags, + complain); + } if (parms != NULL) release_tree_vector (parms); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 69f1eabb940..9e7a398cb3f 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -11321,6 +11321,7 @@ static void cp_parser_mem_initializer_list (cp_parser* parser) { tree mem_initializer_list = NULL_TREE; + tree target_ctor = error_mark_node; cp_token *token = cp_lexer_peek_token (parser->lexer); /* Let the semantic analysis code know that we are starting the @@ -11358,6 +11359,27 @@ cp_parser_mem_initializer_list (cp_parser* parser) if (mem_initializer != error_mark_node) mem_initializer = make_pack_expansion (mem_initializer); } + if (target_ctor != error_mark_node + && mem_initializer != error_mark_node) + { + error ("mem-initializer for %qD follows constructor delegation", + TREE_PURPOSE (mem_initializer)); + mem_initializer = error_mark_node; + } + /* Look for a target constructor. */ + if (mem_initializer != error_mark_node + && TYPE_P (TREE_PURPOSE (mem_initializer)) + && same_type_p (TREE_PURPOSE (mem_initializer), current_class_type)) + { + maybe_warn_cpp0x (CPP0X_DELEGATING_CTORS); + if (mem_initializer_list) + { + error ("constructor delegation follows mem-initializer for %qD", + TREE_PURPOSE (mem_initializer_list)); + mem_initializer = error_mark_node; + } + target_ctor = mem_initializer; + } /* Add it to the list, unless it was erroneous. */ if (mem_initializer != error_mark_node) { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 31aa738768d..3bda000ffcc 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2011-12-05 Ville Voutilainen + Pedro LamarĂ£o + + * g++.dg/cpp0x/dc1.C: New test. + * g++.dg/cpp0x/dc2.C: New test. + * g++.dg/cpp0x/dc3.C: New test. + * g++.dg/cpp0x/dc4.C: New test. + * g++.dg/cpp0x/dc5.C: New test. + * g++.dg/template/meminit1.C: Adjust expected error. + 2011-12-05 Paolo Carlini PR c++/51404 diff --git a/gcc/testsuite/g++.dg/cpp0x/dc1.C b/gcc/testsuite/g++.dg/cpp0x/dc1.C new file mode 100644 index 00000000000..ba2e4f4fd05 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/dc1.C @@ -0,0 +1,43 @@ +// { dg-do compile } +// { dg-options --std=c++0x } + +struct B { + int i; + B (int _i) : i(_i) { } + ~B () { i = 0; } +}; + +struct A : public B { + A () : B(-1) { } + A (int i) : A() { } + A (double b) : A(static_cast(b)) { } + A (double b, double b2) : A(b2) { } + ~A () { } +}; + +void f_A () { A a(2.0, 3.0); } + +struct C { + C () { } + virtual ~C() { } + virtual int f () = 0; +}; + +struct D : public C { + int i; + D (int _i) : C(), i(_i) { } + D () : D(-1) { } + virtual ~D() { } + virtual int f () { } +}; + +void f_D () { C* c = new D(); } + +template +struct E { + T t; + E () : E(T()) { } + E (T _t) : t(_t) { } +}; + +void f_E () { E e; } diff --git a/gcc/testsuite/g++.dg/cpp0x/dc2.C b/gcc/testsuite/g++.dg/cpp0x/dc2.C new file mode 100644 index 00000000000..dda0b9fc697 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/dc2.C @@ -0,0 +1,23 @@ +// { dg-do compile } +// { dg-options --std=c++0x } + +struct A { + int i, j; + A () : A(0), j(0) { } // { dg-error "constructor delegation" } + A (int _i) : i(_i) { } +}; + +struct B { + int i, j; + B () : i(0), B(0) { } // { dg-error "constructor delegation" } + B (int _j) : j(_j) { } + +}; + +struct C {}; + +struct D : public C { + D () : C() { } + D (float) : D(), C() { } // { dg-error "constructor delegation" } + D (float, float): C(), D() { } // { dg-error "constructor delegation" } +}; diff --git a/gcc/testsuite/g++.dg/cpp0x/dc3.C b/gcc/testsuite/g++.dg/cpp0x/dc3.C new file mode 100644 index 00000000000..b411c997d8f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/dc3.C @@ -0,0 +1,63 @@ +// { dg-do compile } +// { dg-options --std=c++0x } + +struct X {}; + +struct B { + int i; + B (int _i) : i(_i) { } + ~B () { i = 0; } +}; + +template +struct A : public B { + A () : B(-1) { } + ~A () { } +}; + +template +struct A : public B { + A () : B(-1) { } + A (int i) : A() { } + A (double b) : A(static_cast(b)) { } + A (double b, double b2) : A(b2) { } + ~A () { } +}; + +void f_A () { A a(2.0, 3.0); } + +struct C { + C () { } + virtual ~C() { } + virtual int f () = 0; +}; + +template +struct D : public C { + int i; + D (int _i) : C(), i(_i) { } +}; + +template <> +struct D : public C { + int i; + D (int _i) : C(), i(_i) { } + D () : D(-1) { } + virtual ~D() { } + virtual int f () { } +}; + +void f_D () { D* d = new D(); } + +template +struct E { +}; + +template <> +struct E { + int i; + E () : E(0) { } + E (int _i) : i(_i) { } +}; + +void f_E () { E e; } diff --git a/gcc/testsuite/g++.dg/cpp0x/dc4.C b/gcc/testsuite/g++.dg/cpp0x/dc4.C new file mode 100644 index 00000000000..634b5498de8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/dc4.C @@ -0,0 +1,7 @@ +// { dg-do compile } +// { dg-options "--std=c++98" } + +struct X { + X() {} + X(int) : X() {} // { dg-warning "delegating constructors" } +}; diff --git a/gcc/testsuite/g++.dg/cpp0x/dc5.C b/gcc/testsuite/g++.dg/cpp0x/dc5.C new file mode 100644 index 00000000000..0052b321113 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/dc5.C @@ -0,0 +1,28 @@ +// { dg-do run } +// { dg-options "--std=c++0x" } + +#include + +int count = 0; +struct VB +{ + VB() {++count;} +}; + +struct B : virtual VB +{ + B() : B(42) {} + B(int) {} +}; + +struct D : B +{ + D() {} + D(int) : D() {} +}; + +int main() +{ + D d{42}; + assert(count == 1); +} diff --git a/gcc/testsuite/g++.dg/template/meminit1.C b/gcc/testsuite/g++.dg/template/meminit1.C index b1c4d424b8a..19a1e546d52 100644 --- a/gcc/testsuite/g++.dg/template/meminit1.C +++ b/gcc/testsuite/g++.dg/template/meminit1.C @@ -2,7 +2,7 @@ template struct S { - S() : S() {} // { dg-error "base" } + S() : S() {} // { dg-message "delegating constructors" } }; -S s; // { dg-message "required" } +S s;