diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 76000170a49..7881e1fef5e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,23 @@ +2011-09-24 Jason Merrill + + Implement C++11 non-static data member initializers. + * cp-tree.h (enum cpp_warn_str): Add CPP0X_NSDMI. + * error.c (maybe_warn_cpp0x): Handle it. + * call.c (convert_like_real) [ck_user]: Don't complain about + using an explicit constructor for direct-initialization. + * class.c (check_field_decl): Fix ancient typo. + (check_field_decls): NSDMIs make the default ctor non-trivial. + * decl.c (cp_finish_decl): Record NSDMI. + (grokdeclarator): Allow NSDMI. + * decl2.c (grokfield): Allow NSDMI. Correct LOOKUP flags. + * init.c (perform_member_init): Use NSDMI. + * method.c (walk_field_subobs): Check for NSDMI. + * parser.c (cp_parser_member_declaration): Parse { } init. + * semantics.c (register_constexpr_fundef): Don't talk about + a return statement in a constexpr constructor. + (cxx_eval_call_expression): Check DECL_INITIAL instead of + DECL_SAVED_TREE. + 2011-09-24 Paolo Carlini PR c++/44267 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 8c99f7a5440..6a7dfd39874 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -5648,6 +5648,9 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, /* When converting from an init list we consider explicit constructors, but actually trying to call one is an error. */ if (DECL_NONCONVERTING_P (convfn) && DECL_CONSTRUCTOR_P (convfn) + /* Unless this is for direct-list-initialization. */ + && !(BRACE_ENCLOSED_INITIALIZER_P (expr) + && CONSTRUCTOR_IS_DIRECT_INIT (expr)) /* Unless we're calling it for value-initialization from an empty list, since that is handled separately in 8.5.4. */ && cand->num_convs > 0) diff --git a/gcc/cp/class.c b/gcc/cp/class.c index acfe3f23afa..a7d8218055f 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -2958,7 +2958,7 @@ check_field_decl (tree field, { /* `build_class_init_list' does not recognize non-FIELD_DECLs. */ - if (TREE_CODE (t) == UNION_TYPE && any_default_members != 0) + if (TREE_CODE (t) == UNION_TYPE && *any_default_members != 0) error ("multiple fields in union %qT initialized", t); *any_default_members = 1; } @@ -3256,6 +3256,14 @@ check_field_decls (tree t, tree *access_decls, " but does not override %", t); } + /* Non-static data member initializers make the default constructor + non-trivial. */ + if (any_default_members) + { + TYPE_NEEDS_CONSTRUCTING (t) = true; + TYPE_HAS_COMPLEX_DFLT (t) = true; + } + /* If any of the fields couldn't be packed, unset TYPE_PACKED. */ if (cant_pack) TYPE_PACKED (t) = 0; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f2c921192be..2f93bbac837 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -394,7 +394,9 @@ typedef enum cpp0x_warn_str /* inline namespaces */ CPP0X_INLINE_NAMESPACES, /* override controls, override/final */ - CPP0X_OVERRIDE_CONTROLS + CPP0X_OVERRIDE_CONTROLS, + /* non-static data member initializers */ + CPP0X_NSDMI } cpp0x_warn_str; /* The various kinds of operation used by composite_pointer_type. */ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 495d8a059d7..661cc5ea113 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -6075,6 +6075,10 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, return; } + /* Just store non-static data member initializers for later. */ + if (init && TREE_CODE (decl) == FIELD_DECL) + DECL_INITIAL (decl) = digest_init_flags (TREE_TYPE (decl), init, flags); + /* Take care of TYPE_DECLs up front. */ if (TREE_CODE (decl) == TYPE_DECL) { @@ -10087,36 +10091,6 @@ grokdeclarator (const cp_declarator *declarator, if (decl == NULL_TREE) { - if (initialized) - { - if (!staticp) - { - /* An attempt is being made to initialize a non-static - member. But, from [class.mem]: - - 4 A member-declarator can contain a - constant-initializer only if it declares a static - member (_class.static_) of integral or enumeration - type, see _class.static.data_. - - This used to be relatively common practice, but - the rest of the compiler does not correctly - handle the initialization unless the member is - static so we make it static below. */ - if (cxx_dialect >= cxx0x) - { - sorry ("non-static data member initializers"); - } - else - { - permerror (input_location, "ISO C++ forbids initialization of member %qD", - unqualified_id); - permerror (input_location, "making %qD static", unqualified_id); - staticp = 1; - } - } - } - if (staticp) { /* C++ allows static class members. All other work @@ -10157,6 +10131,11 @@ grokdeclarator (const cp_declarator *declarator, DECL_MUTABLE_P (decl) = 1; storage_class = sc_none; } + + if (initialized) + /* An attempt is being made to initialize a non-static + member. This is new in C++11. */ + maybe_warn_cpp0x (CPP0X_NSDMI); } bad_specifiers (decl, BSP_FIELD, virtualp, diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 68e9b9b7bac..1e06280b26c 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -795,7 +795,7 @@ grokfield (const cp_declarator *declarator, { tree value; const char *asmspec = 0; - int flags = LOOKUP_ONLYCONVERTING; + int flags; tree name; if (init @@ -919,9 +919,10 @@ grokfield (const cp_declarator *declarator, value); } } - else if (pedantic && TREE_CODE (value) != VAR_DECL) - /* Already complained in grokdeclarator. */ - init = NULL_TREE; + else if (TREE_CODE (value) == FIELD_DECL) + /* C++11 NSDMI, keep going. */; + else if (TREE_CODE (value) != VAR_DECL) + gcc_unreachable (); else if (!processing_template_decl) { if (TREE_CODE (init) == CONSTRUCTOR) @@ -955,6 +956,12 @@ grokfield (const cp_declarator *declarator, if (attrlist) cplus_decl_attributes (&value, attrlist, 0); + if (init && BRACE_ENCLOSED_INITIALIZER_P (init) + && CONSTRUCTOR_IS_DIRECT_INIT (init)) + flags = LOOKUP_NORMAL; + else + flags = LOOKUP_IMPLICIT; + switch (TREE_CODE (value)) { case VAR_DECL: @@ -969,7 +976,6 @@ grokfield (const cp_declarator *declarator, init = error_mark_node; cp_finish_decl (value, init, /*init_const_expr_p=*/false, NULL_TREE, flags); - DECL_INITIAL (value) = init; DECL_IN_AGGR_P (value) = 1; return value; diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 598ddf10e5d..392f304ef92 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -3236,6 +3236,11 @@ maybe_warn_cpp0x (cpp0x_warn_str str) "override controls (override/final) " "only available with -std=c++0x or -std=gnu++0x"); break; + case CPP0X_NSDMI: + pedwarn (input_location, 0, + "non-static data member initializers " + "only available with -std=c++0x or -std=gnu++0x"); + break; default: gcc_unreachable(); } diff --git a/gcc/cp/init.c b/gcc/cp/init.c index ac3221e30d0..f5904d5ddc2 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -493,6 +493,11 @@ perform_member_init (tree member, tree init) tree decl; tree type = TREE_TYPE (member); + /* Use the non-static data member initializer if there was no + mem-initializer for this field. */ + if (init == NULL_TREE) + init = break_out_target_exprs (DECL_INITIAL (member)); + /* Effective C++ rule 12 requires that all data members be initialized. */ if (warn_ecpp && init == NULL_TREE && TREE_CODE (type) != ARRAY_TYPE) diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 88bb2a9ef21..734c23b0d6c 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1036,10 +1036,20 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, if (bad && deleted_p) *deleted_p = true; + if (DECL_INITIAL (field)) + { + if (msg && DECL_INITIAL (field) == error_mark_node) + inform (0, "initializer for %q+#D is invalid", field); + if (trivial_p) + *trivial_p = false; + + /* Don't do the normal processing. */ + continue; + } + /* For an implicitly-defined default constructor to be constexpr, - every member must have a user-provided default constructor. */ - /* FIXME will need adjustment for non-static data member - initializers. */ + every member must have a user-provided default constructor or + an explicit initializer. */ if (constexpr_p && !CLASS_TYPE_P (mem_type)) { *constexpr_p = false; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 22833124330..bd46af38cb0 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -18202,6 +18202,12 @@ cp_parser_member_declaration (cp_parser* parser) /* Parse the initializer. */ initializer = cp_parser_constant_initializer (parser); } + else if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE) + && !function_declarator_p (declarator)) + { + bool x; + initializer = cp_parser_initializer (parser, &x, &x); + } /* Otherwise, there is no initializer. */ else initializer = NULL_TREE; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 0662b29b61f..19ecbee4d8a 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -5826,8 +5826,8 @@ register_constexpr_fundef (tree fun, tree body) body = massage_constexpr_body (fun, body); if (body == NULL_TREE || body == error_mark_node) { - error ("body of constexpr function %qD not a return-statement", fun); - DECL_DECLARED_CONSTEXPR_P (fun) = false; + if (!DECL_CONSTRUCTOR_P (fun)) + error ("body of constexpr function %qD not a return-statement", fun); return NULL; } @@ -6245,7 +6245,7 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t, { if (!allow_non_constant) { - if (DECL_SAVED_TREE (fun)) + if (DECL_INITIAL (fun)) { /* The definition of fun was somehow unsuitable. */ error_at (loc, "%qD called in a constant expression", fun); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 940c3d840b5..795ac70ce3b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2011-09-24 Jason Merrill + + * g++.dg/cpp0x/nsdmi1.C: New. + * g++.dg/cpp0x/nsdmi2.C: New. + * g++.dg/cpp0x/nsdmi3.C: New. + * g++.dg/cpp0x/nsdmi4.C: New. + * g++.old-deja/g++.other/init4.C: New. + 2011-09-24 Paolo Carlini PR c++/44267 diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi1.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi1.C new file mode 100644 index 00000000000..f6381d0fdb4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi1.C @@ -0,0 +1,53 @@ +// { dg-do run } +// { dg-options -std=c++0x } + +struct A +{ + int i = 42; +}; + +struct B +{ + int i = 42; + B() { } + B(int i): i(i) { } +}; + +template +struct C +{ + T m = t; +}; + +template +struct D +{ + T m = t; + D() { } + D(T m):m(m) { } +}; + +int main() +{ + A a1; + if (a1.i != 42) return 1; + A a2 = { 24 }; + if (a2.i != 24) return 2; + A a3[1]; + if (a3[0].i != 42) return 3; + + B b1; + if (b1.i != 42) return 3; + B b2 (24); + if (b2.i != 24) return 4; + + C c1; + if (c1.m != 3) return 5; + C c2 { 5 }; + if (c2.m != 5) return 6; + + D d1; + if (d1.m != 3) return 7; + D d2 (5) ; + if (d2.m != 5) return 8; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi2.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi2.C new file mode 100644 index 00000000000..9636bed8820 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi2.C @@ -0,0 +1,21 @@ +// { dg-options -std=c++0x } + +struct A +{ + int i; + constexpr A(int i): i(i) {} +}; + +struct B +{ + A a1 = 1; + A a2 { 2 }; + A a3 = { 3 }; +}; + +#define SA(X) static_assert(X,#X) + +constexpr B b; +SA(b.a1.i == 1); +SA(b.a2.i == 2); +SA(b.a3.i == 3); diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi3.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi3.C new file mode 100644 index 00000000000..73b2bc2e1ac --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi3.C @@ -0,0 +1,18 @@ +// { dg-options -std=c++0x } + +struct A +{ + int i; + explicit constexpr A(int i): i(i) {} +}; + +struct B +{ + A a1 = 1; // { dg-error "" } + A a2 { 2 }; + A a3 = { 3 }; // { dg-error "" } +}; + +constexpr B b; // { dg-error "B::B" } + +// { dg-message "a1. is invalid" "" { target *-*-* } 11 } diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi4.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi4.C new file mode 100644 index 00000000000..db365cb55e5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi4.C @@ -0,0 +1,24 @@ +// { dg-do run } +// { dg-options -std=c++0x } + +int c; + +struct A +{ + A() { } + A(const A&) { } +}; + +A f() { ++c; return A(); } + +struct B +{ + A a = f(); +}; + +int main() +{ + B b1, b2; + if (c != 2) + __builtin_abort(); +} diff --git a/gcc/testsuite/g++.old-deja/g++.other/init4.C b/gcc/testsuite/g++.old-deja/g++.other/init4.C index 92562ef5845..f8246d68f0e 100644 --- a/gcc/testsuite/g++.old-deja/g++.other/init4.C +++ b/gcc/testsuite/g++.old-deja/g++.other/init4.C @@ -1,4 +1,4 @@ -// { dg-options -std=c++98 } +// { dg-options "-std=c++98 -pedantic-errors" } // { dg-do assemble } class error {