]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Implement C++11 non-static data member initializers.
authorJason Merrill <jason@redhat.com>
Sun, 25 Sep 2011 02:25:52 +0000 (22:25 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Sun, 25 Sep 2011 02:25:52 +0000 (22:25 -0400)
* 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.

From-SVN: r179155

17 files changed:
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/error.c
gcc/cp/init.c
gcc/cp/method.c
gcc/cp/parser.c
gcc/cp/semantics.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/nsdmi1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/nsdmi2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/nsdmi3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/nsdmi4.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.other/init4.C

index 76000170a49b1c0a6f153e5c7269ca75aee94994..7881e1fef5e4b1622c85b82961b635a78ffa7f40 100644 (file)
@@ -1,3 +1,23 @@
+2011-09-24  Jason Merrill  <jason@redhat.com>
+
+       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  <paolo.carlini@oracle.com>
 
        PR c++/44267
index 8c99f7a5440abe6540231bd0546408d3855abfe7..6a7dfd398741b19c2ed626e4acf3838b23c21461 100644 (file)
@@ -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)
index acfe3f23afae60d561c77b23ee6cc4c28c29ebdf..a7d8218055facebf3b35cbad149337b11cafa55a 100644 (file)
@@ -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 %<operator=(const %T&)%>", 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;
index f2c921192beb372ccef7775291288c4791d5fa3b..2f93bbac8375c6200e2962398a0b93dde491a495 100644 (file)
@@ -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. */
index 495d8a059d7504c76f56efde76be3a95df622749..661cc5ea113e984c9bc40ae56a63636fdabb4012 100644 (file)
@@ -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,
index 68e9b9b7bac8035aa23a2ccb76ee8a5c36d1aa82..1e06280b26c74389a62ba8d9c63b0a806a9ea8c1 100644 (file)
@@ -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;
 
index 598ddf10e5de7d28e357cb461ad386ab8a4b8c4f..392f304ef92ca1eb5090c6b51f7c5d7e28c4d392 100644 (file)
@@ -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();
       }
index ac3221e30d0b74d7af365e1b81a11e274e0d193b..f5904d5ddc2d1535865fdd8a57c9613603cbd010 100644 (file)
@@ -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)
index 88bb2a9ef21cffb561ca60c6bc10369b45ee0e34..734c23b0d6c3cc81113ae493a000660017a0829d 100644 (file)
@@ -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;
index 228331243303af6ec0b9b34079f3c7d3ec4f7194..bd46af38cb00085c2d8c3e5acb9de7fa039b04d2 100644 (file)
@@ -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;
index 0662b29b61f514d8d8738b726bfa1ee2060c3bf9..19ecbee4d8ad416a2261562d57477ec23621a932 100644 (file)
@@ -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);
index 940c3d840b54dec2c9abc39443617676ffb05b76..795ac70ce3b498460d4e533d422a73c094db4faa 100644 (file)
@@ -1,3 +1,11 @@
+2011-09-24  Jason Merrill  <jason@redhat.com>
+
+       * 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  <paolo.carlini@oracle.com>
 
        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 (file)
index 0000000..f6381d0
--- /dev/null
@@ -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 <class T, T t>
+struct C
+{
+  T m = t;
+};
+
+template <class T, T t>
+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<int,3> c1;
+  if (c1.m != 3) return 5;
+  C<int,3> c2 { 5 };
+  if (c2.m != 5) return 6;
+
+  D<int,3> d1;
+  if (d1.m != 3) return 7;
+  D<int,3> 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 (file)
index 0000000..9636bed
--- /dev/null
@@ -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 (file)
index 0000000..73b2bc2
--- /dev/null
@@ -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 (file)
index 0000000..db365cb
--- /dev/null
@@ -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();
+}
index 92562ef5845c22b4ff6d335bb65cdba4f19da81a..f8246d68f0ed37ea01c20054ba8740d8aacb0ab6 100644 (file)
@@ -1,4 +1,4 @@
-// { dg-options -std=c++98 }
+// { dg-options "-std=c++98 -pedantic-errors" }
 // { dg-do assemble  }
 
 class error {