re PR c++/33916 (Default constructor fails to initialize array members)
authorJason Merrill <jason@redhat.com>
Mon, 4 Feb 2008 03:28:53 +0000 (22:28 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 4 Feb 2008 03:28:53 +0000 (22:28 -0500)
        PR c++/33916
        * cp/init.c (build_value_init_1): New function.
        (build_value_init): New function.
        * cp/typeck2.c (build_functional_cast): Call it.
        * cp/cp-gimplify.c (cp_gimplify_init_expr): Handle its output.

        * cp/cp-tree.h (TYPE_HAS_USER_CONSTRUCTOR): Rename from
        TYPE_HAS_CONSTRUCTOR.
        * cp/class.c (finish_struct_bits, maybe_warn_about_overly_private_class,
        add_implicitly_declared_members): Adjust.
        (check_field_decls): Adjust. Remove warnings about reference/const
        in class without constructor.
        (check_bases_and_members): Adjust.  Give those warnings here instead.
        * cp/decl.c (fixup_anonymous_aggr): Adjust.
        (check_initializer): Adjust, clarify logic slightly.
        (grok_special_member_properties): Adjust, only set if user-provided.
        * cp/rtti.c (create_tinfo_types): Don't set.
        * cp/cvt.c (ocp_convert): Remove exception for vtable_entry_type et al.
        Use same_type_ignoring_top_level_qualifiers_p.
        * cp/pt.c (check_explicit_specialization): Adjust.
        (instantiate_class_template): Adjust.

        * print-tree.c (print_node) [CONSTRUCTOR]: Print elements.

Co-Authored-By: Mark Mitchell <mark@codesourcery.com>
From-SVN: r132088

16 files changed:
gcc/ChangeLog
gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-gimplify.c
gcc/cp/cp-tree.h
gcc/cp/cvt.c
gcc/cp/decl.c
gcc/cp/init.c
gcc/cp/pt.c
gcc/cp/rtti.c
gcc/cp/typeck2.c
gcc/print-tree.c
gcc/testsuite/g++.dg/init/ctor8.C
gcc/testsuite/g++.dg/init/value1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wextra-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wextra-2.C [new file with mode: 0644]

index 8426d4153bc5f42726dfadd72b0965fc30e3596e..089f82f239dd0ea6765274a056c5ef87d266a2ba 100644 (file)
@@ -1,3 +1,7 @@
+2008-02-03  Jason Merrill  <jason@redhat.com>
+
+       * print-tree.c (print_node) [CONSTRUCTOR]: Print elements.
+
 2008-02-04  Ralf Wildenhues  <Ralf.Wildenhues@gmx.de>
 
        PR other/29972
index 5b4cc3bb49b5bafda5e14609a8a7f926f1d8d022..3504769f1bbdc9dfd9e7051d36e4c060cec5add5 100644 (file)
@@ -1,3 +1,28 @@
+2008-02-02  Jason Merrill  <jason@redhat.com>
+           Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/33916
+       * init.c (build_value_init_1): New function.
+       (build_value_init): New function.
+       * typeck2.c (build_functional_cast): Call it.
+       * cp-gimplify.c (cp_gimplify_init_expr): Handle its output.
+
+       * cp-tree.h (TYPE_HAS_USER_CONSTRUCTOR): Rename from 
+       TYPE_HAS_CONSTRUCTOR.
+       * class.c (finish_struct_bits, maybe_warn_about_overly_private_class,
+       add_implicitly_declared_members): Adjust.
+       (check_field_decls): Adjust. Remove warnings about reference/const
+       in class without constructor.
+       (check_bases_and_members): Adjust.  Give those warnings here instead.
+       * decl.c (fixup_anonymous_aggr): Adjust.
+       (check_initializer): Adjust, clarify logic slightly.
+       (grok_special_member_properties): Adjust, only set if user-provided.
+       * rtti.c (create_tinfo_types): Don't set.
+       * cvt.c (ocp_convert): Remove exception for vtable_entry_type et al.
+       Use same_type_ignoring_top_level_qualifiers_p.
+       * pt.c (check_explicit_specialization): Adjust.
+       (instantiate_class_template): Adjust.
+
 2008-01-31  Douglas Gregor  <doug.gregor@gmail.com>
            Jakub Jelinek  <jakub@redhat.com>
 
index 7560dbe3da754f76ef47ec843bb8333955af95d4..a5456c23324c67a2d744e176ac99fc680d78cd7c 100644 (file)
@@ -955,7 +955,7 @@ add_method (tree type, tree method, tree using_decl)
       CLASSTYPE_METHOD_VEC (type) = method_vec;
     }
 
-  /* Maintain TYPE_HAS_CONSTRUCTOR, etc.  */
+  /* Maintain TYPE_HAS_USER_CONSTRUCTOR, etc.  */
   grok_special_member_properties (method);
 
   /* Constructors and destructors go in special slots.  */
@@ -1451,7 +1451,7 @@ finish_struct_bits (tree t)
     {
       /* These fields are in the _TYPE part of the node, not in
         the TYPE_LANG_SPECIFIC component, so they are not shared.  */
-      TYPE_HAS_CONSTRUCTOR (variants) = TYPE_HAS_CONSTRUCTOR (t);
+      TYPE_HAS_USER_CONSTRUCTOR (variants) = TYPE_HAS_USER_CONSTRUCTOR (t);
       TYPE_NEEDS_CONSTRUCTING (variants) = TYPE_NEEDS_CONSTRUCTING (t);
       TYPE_HAS_NONTRIVIAL_DESTRUCTOR (variants)
        = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t);
@@ -1596,7 +1596,8 @@ maybe_warn_about_overly_private_class (tree t)
       return;
     }
 
-  if (TYPE_HAS_CONSTRUCTOR (t)
+  /* Warn about classes that have private constructors and no friends.  */
+  if (TYPE_HAS_USER_CONSTRUCTOR (t)
       /* Implicitly generated constructors are always public.  */
       && (!CLASSTYPE_LAZY_DEFAULT_CTOR (t)
          || !CLASSTYPE_LAZY_COPY_CTOR (t)))
@@ -2602,20 +2603,25 @@ add_implicitly_declared_members (tree t,
        }
     }
 
-  /* Default constructor.  */
-  if (! TYPE_HAS_CONSTRUCTOR (t))
+  /* [class.ctor]
+
+     If there is no user-declared constructor for a class, a default
+     constructor is implicitly declared.  */
+  if (! TYPE_HAS_USER_CONSTRUCTOR (t))
     {
       TYPE_HAS_DEFAULT_CONSTRUCTOR (t) = 1;
       CLASSTYPE_LAZY_DEFAULT_CTOR (t) = 1;
     }
 
-  /* Copy constructor.  */
+  /* [class.ctor]
+
+     If a class definition does not explicitly declare a copy
+     constructor, one is declared implicitly.  */
   if (! TYPE_HAS_INIT_REF (t) && ! TYPE_FOR_JAVA (t))
     {
       TYPE_HAS_INIT_REF (t) = 1;
       TYPE_HAS_CONST_INIT_REF (t) = !cant_have_const_cctor;
       CLASSTYPE_LAZY_COPY_CTOR (t) = 1;
-      TYPE_HAS_CONSTRUCTOR (t) = 1;
     }
 
   /* If there is no assignment operator, one will be created if and
@@ -2937,8 +2943,7 @@ check_field_decls (tree t, tree *access_decls,
       if (TREE_PRIVATE (x) || TREE_PROTECTED (x))
        CLASSTYPE_NON_AGGREGATE (t) = 1;
 
-      /* If this is of reference type, check if it needs an init.
-        Also do a little ANSI jig if necessary.  */
+      /* If this is of reference type, check if it needs an init.  */
       if (TREE_CODE (type) == REFERENCE_TYPE)
        {
          CLASSTYPE_NON_POD_P (t) = 1;
@@ -2950,10 +2955,6 @@ check_field_decls (tree t, tree *access_decls,
             only way to initialize nonstatic const and reference
             members.  */
          TYPE_HAS_COMPLEX_ASSIGN_REF (t) = 1;
-
-         if (! TYPE_HAS_CONSTRUCTOR (t) && CLASSTYPE_NON_AGGREGATE (t)
-             && extra_warnings)
-           warning (OPT_Wextra, "non-static reference %q+#D in class without a constructor", x);
        }
 
       type = strip_array_types (type);
@@ -3028,10 +3029,6 @@ check_field_decls (tree t, tree *access_decls,
             only way to initialize nonstatic const and reference
             members.  */
          TYPE_HAS_COMPLEX_ASSIGN_REF (t) = 1;
-
-         if (! TYPE_HAS_CONSTRUCTOR (t) && CLASSTYPE_NON_AGGREGATE (t)
-             && extra_warnings)
-           warning (OPT_Wextra, "non-static const member %q+#D in class without a constructor", x);
        }
       /* A field that is pseudo-const makes the structure likewise.  */
       else if (CLASS_TYPE_P (type))
@@ -3045,7 +3042,8 @@ check_field_decls (tree t, tree *access_decls,
       /* Core issue 80: A nonstatic data member is required to have a
         different name from the class iff the class has a
         user-defined constructor.  */
-      if (constructor_name_p (DECL_NAME (x), t) && TYPE_HAS_CONSTRUCTOR (t))
+      if (constructor_name_p (DECL_NAME (x), t)
+         && TYPE_HAS_USER_CONSTRUCTOR (t))
        pedwarn ("field %q+#D with same name as class", x);
 
       /* We set DECL_C_BIT_FIELD in grokbitfield.
@@ -3073,7 +3071,7 @@ check_field_decls (tree t, tree *access_decls,
      This seems enough for practical purposes.  */
   if (warn_ecpp
       && has_pointers
-      && TYPE_HAS_CONSTRUCTOR (t)
+      && TYPE_HAS_USER_CONSTRUCTOR (t)
       && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
       && !(TYPE_HAS_INIT_REF (t) && TYPE_HAS_ASSIGN_REF (t)))
     {
@@ -4158,10 +4156,22 @@ check_bases_and_members (tree t)
      declared member functions.  */
   TYPE_HAS_COMPLEX_INIT_REF (t)
     |= (TYPE_HAS_INIT_REF (t) || TYPE_CONTAINS_VPTR_P (t));
+  /* We need to call a constructor for this class if it has a
+     user-declared constructor, or if the default constructor is going
+     to initialize the vptr.  (This is not an if-and-only-if;
+     TYPE_NEEDS_CONSTRUCTING is set elsewhere if bases or members
+     themselves need constructing.)  */
   TYPE_NEEDS_CONSTRUCTING (t)
-    |= (TYPE_HAS_CONSTRUCTOR (t) || TYPE_CONTAINS_VPTR_P (t));
+    |= (TYPE_HAS_USER_CONSTRUCTOR (t) || TYPE_CONTAINS_VPTR_P (t));
+  /* [dcl.init.aggr]
+
+     An aggregate is an arry or a class with no user-declared
+     constructors ... and no virtual functions.  
+
+     Again, other conditions for being an aggregate are checked
+     elsewhere.  */
   CLASSTYPE_NON_AGGREGATE (t)
-    |= (TYPE_HAS_CONSTRUCTOR (t) || TYPE_POLYMORPHIC_P (t));
+    |= (TYPE_HAS_USER_CONSTRUCTOR (t) || TYPE_POLYMORPHIC_P (t));
   CLASSTYPE_NON_POD_P (t)
     |= (CLASSTYPE_NON_AGGREGATE (t)
        || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
@@ -4171,6 +4181,38 @@ check_bases_and_members (tree t)
   TYPE_HAS_COMPLEX_DFLT (t)
     |= (TYPE_HAS_DEFAULT_CONSTRUCTOR (t) || TYPE_CONTAINS_VPTR_P (t));
 
+  /* If the class has no user-declared constructor, but does have
+     non-static const or reference data members that can never be
+     initialized, issue a warning.  */
+  if (extra_warnings
+      /* Classes with user-declared constructors are presumed to
+        initialize these members.  */
+      && !TYPE_HAS_USER_CONSTRUCTOR (t)
+      /* Aggregates can be initialized with brace-enclosed
+        initializers.  */
+      && CLASSTYPE_NON_AGGREGATE (t))
+    {
+      tree field;
+
+      for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field))
+       {
+         tree type;
+
+         if (TREE_CODE (field) != FIELD_DECL)
+           continue;
+
+         type = TREE_TYPE (field);
+         if (TREE_CODE (type) == REFERENCE_TYPE)
+           warning (OPT_Wextra, "non-static reference %q+#D in class "
+                    "without a constructor", field);
+         else if (CP_TYPE_CONST_P (type)
+                  && (!CLASS_TYPE_P (type)
+                      || !TYPE_HAS_DEFAULT_CONSTRUCTOR (type)))
+           warning (OPT_Wextra, "non-static const member %q+#D in class "
+                    "without a constructor", field);
+       }
+    }
+
   /* Synthesize any needed methods.  */
   add_implicitly_declared_members (t,
                                   cant_have_const_ctor,
index f9d800ea388bf88c4cacf54222fc5000060a51e6..50b40484413d6f574487ff701f6ee3ea0e10b407 100644 (file)
@@ -387,35 +387,56 @@ cp_gimplify_init_expr (tree *expr_p, tree *pre_p, tree *post_p)
 {
   tree from = TREE_OPERAND (*expr_p, 1);
   tree to = TREE_OPERAND (*expr_p, 0);
-  tree sub;
+  tree t;
+  tree slot = NULL_TREE;
 
   /* What about code that pulls out the temp and uses it elsewhere?  I
      think that such code never uses the TARGET_EXPR as an initializer.  If
      I'm wrong, we'll abort because the temp won't have any RTL.  In that
      case, I guess we'll need to replace references somehow.  */
   if (TREE_CODE (from) == TARGET_EXPR)
-    from = TARGET_EXPR_INITIAL (from);
+    {
+      slot = TARGET_EXPR_SLOT (from);
+      from = TARGET_EXPR_INITIAL (from);
+    }
 
   /* Look through any COMPOUND_EXPRs, since build_compound_expr pushes them
      inside the TARGET_EXPR.  */
-  sub = expr_last (from);
+  for (t = from; t; )
+    {
+      tree sub = TREE_CODE (t) == COMPOUND_EXPR ? TREE_OPERAND (t, 0) : t;
 
-  /* If we are initializing from an AGGR_INIT_EXPR, drop the INIT_EXPR and
-     replace the slot operand with our target.
+      /* If we are initializing from an AGGR_INIT_EXPR, drop the INIT_EXPR and
+        replace the slot operand with our target.
 
-     Should we add a target parm to gimplify_expr instead?  No, as in this
-     case we want to replace the INIT_EXPR.  */
-  if (TREE_CODE (sub) == AGGR_INIT_EXPR)
-    {
-      gimplify_expr (&to, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
-      AGGR_INIT_EXPR_SLOT (sub) = to;
-      *expr_p = from;
-
-      /* The initialization is now a side-effect, so the container can
-        become void.  */
-      if (from != sub)
-       TREE_TYPE (from) = void_type_node;
+        Should we add a target parm to gimplify_expr instead?  No, as in this
+        case we want to replace the INIT_EXPR.  */
+      if (TREE_CODE (sub) == AGGR_INIT_EXPR)
+       {
+         gimplify_expr (&to, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
+         AGGR_INIT_EXPR_SLOT (sub) = to;
+         *expr_p = from;
+
+         /* The initialization is now a side-effect, so the container can
+            become void.  */
+         if (from != sub)
+           TREE_TYPE (from) = void_type_node;
+       }
+      else if (TREE_CODE (sub) == INIT_EXPR
+              && TREE_OPERAND (sub, 0) == slot)
+       {
+         /* An INIT_EXPR under TARGET_EXPR created by build_value_init,
+            will be followed by an AGGR_INIT_EXPR.  */
+         gimplify_expr (&to, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
+         TREE_OPERAND (sub, 0) = to;
+       }
+
+      if (t == sub)
+       break;
+      else
+       t = TREE_OPERAND (t, 1);
     }
+
 }
 
 /* Gimplify a MUST_NOT_THROW_EXPR.  */
index e6aba2fe2c4f3351e275d24f9ace3d999830f229..549625c513885926f40cf9d16787965ef4aea1a3 100644 (file)
@@ -91,7 +91,7 @@ struct diagnostic_info;
 
    Usage of TYPE_LANG_FLAG_?:
    0: TYPE_DEPENDENT_P
-   1: TYPE_HAS_CONSTRUCTOR.
+   1: TYPE_HAS_USER_CONSTRUCTOR.
    2: Unused
    3: TYPE_FOR_JAVA.
    4: TYPE_HAS_NONTRIVIAL_DESTRUCTOR
@@ -2709,7 +2709,7 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
 
 /* Nonzero for a class type means that the class type has a
    user-declared constructor.  */
-#define TYPE_HAS_CONSTRUCTOR(NODE) (TYPE_LANG_FLAG_1 (NODE))
+#define TYPE_HAS_USER_CONSTRUCTOR(NODE) (TYPE_LANG_FLAG_1 (NODE))
 
 /* When appearing in an INDIRECT_REF, it means that the tree structure
    underneath is actually a call to a constructor.  This is needed
@@ -4346,6 +4346,7 @@ extern tree build_aggr_init                       (tree, tree, int);
 extern int is_aggr_type                                (tree, int);
 extern tree get_type_value                     (tree);
 extern tree build_zero_init                    (tree, tree, bool);
+extern tree build_value_init                   (tree);
 extern tree build_offset_ref                   (tree, tree, bool);
 extern tree build_new                          (tree, tree, tree, tree, int);
 extern tree build_vec_init                     (tree, tree, tree, bool, int);
index ebfc7d05d98bdd2f2ed92e6eadba1fc3ef638e98..5f48cc525e8870eeeaec732c01f6eeeb7ef150ae 100644 (file)
@@ -596,13 +596,9 @@ ocp_convert (tree type, tree expr, int convtype, int flags)
 
   e = integral_constant_value (e);
 
-  if (IS_AGGR_TYPE (type) && (convtype & CONV_FORCE_TEMP)
-      /* Some internal structures (vtable_entry_type, sigtbl_ptr_type)
-        don't go through finish_struct, so they don't have the synthesized
-        constructors.  So don't force a temporary.  */
-      && TYPE_HAS_CONSTRUCTOR (type))
+  if (IS_AGGR_TYPE (type) && (convtype & CONV_FORCE_TEMP))
     /* We need a new temporary; don't take this shortcut.  */;
-  else if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (e)))
+  else if (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (e)))
     {
       if (same_type_p (type, TREE_TYPE (e)))
        /* The call to fold will not always remove the NOP_EXPR as
@@ -619,10 +615,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags)
       else if (TREE_CODE (e) == TARGET_EXPR)
        {
          /* Don't build a NOP_EXPR of class type.  Instead, change the
-            type of the temporary.  Only allow this for cv-qual changes,
-            though.  */
-         gcc_assert (same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (e)),
-                                  TYPE_MAIN_VARIANT (type)));
+            type of the temporary.  */
          TREE_TYPE (e) = TREE_TYPE (TARGET_EXPR_SLOT (e)) = type;
          return e;
        }
index 21db36e2095d2135a0c216759f3c1d65bcdf45ae..93baa7db83adb625f011116664598fe628ef7111 100644 (file)
@@ -3689,7 +3689,7 @@ fixup_anonymous_aggr (tree t)
   tree *q;
 
   /* Wipe out memory of synthesized methods.  */
-  TYPE_HAS_CONSTRUCTOR (t) = 0;
+  TYPE_HAS_USER_CONSTRUCTOR (t) = 0;
   TYPE_HAS_DEFAULT_CONSTRUCTOR (t) = 0;
   TYPE_HAS_INIT_REF (t) = 0;
   TYPE_HAS_CONST_INIT_REF (t) = 0;
@@ -4993,11 +4993,11 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup)
       if (type == error_mark_node)
        return NULL_TREE;
 
-      if (TYPE_HAS_CONSTRUCTOR (type) || TYPE_NEEDS_CONSTRUCTING (type))
+      if (TREE_CODE (type) == ARRAY_TYPE && TYPE_NEEDS_CONSTRUCTING (type))
+       goto initialize_aggr;
+      else if (CLASS_TYPE_P (type))
        {
-         if (TREE_CODE (type) == ARRAY_TYPE)
-           goto initialize_aggr;
-         else if (TREE_CODE (init) == CONSTRUCTOR)
+         if (TREE_CODE (init) == CONSTRUCTOR)
            {
              if (TYPE_NON_AGGREGATE_CLASS (type))
                {
@@ -9582,7 +9582,8 @@ move_fn_p (const_tree d)
 
 /* Remember any special properties of member function DECL.  */
 
-void grok_special_member_properties (tree decl)
+void
+grok_special_member_properties (tree decl)
 {
   tree class_type;
 
@@ -9594,7 +9595,8 @@ void grok_special_member_properties (tree decl)
     {
       int ctor = copy_fn_p (decl);
 
-      TYPE_HAS_CONSTRUCTOR (class_type) = 1;
+      if (!DECL_ARTIFICIAL (decl))
+       TYPE_HAS_USER_CONSTRUCTOR (class_type) = 1;
 
       if (ctor > 0)
        {
index a6da19f193304b2636d1f02360cd39b95062bae5..ec59207716da42025f636c8ca2e490707bd8d763 100644 (file)
@@ -152,7 +152,7 @@ build_zero_init (tree type, tree nelts, bool static_storage_p)
 
   /* [dcl.init]
 
-     To zero-initialization storage for an object of type T means:
+     To zero-initialize an object of type T means:
 
      -- if T is a scalar type, the storage is set to the value of zero
        converted to T.
@@ -209,8 +209,8 @@ build_zero_init (tree type, tree nelts, bool static_storage_p)
            break;
        }
 
-       /* Build a constructor to contain the initializations.  */
-       init = build_constructor (type, v);
+      /* Build a constructor to contain the initializations.  */
+      init = build_constructor (type, v);
     }
   else if (TREE_CODE (type) == ARRAY_TYPE)
     {
@@ -315,6 +315,153 @@ build_default_init (tree type, tree nelts)
   return build_zero_init (type, nelts, /*static_storage_p=*/false);
 }
 
+/* Return a suitable initializer for value-initializing an object of type
+   TYPE, as described in [dcl.init].  If HAVE_CTOR is true, the initializer
+   for an enclosing object is already calling the constructor for this
+   object.  */
+
+static tree
+build_value_init_1 (tree type, bool have_ctor)
+{
+  /* [dcl.init]
+
+     To value-initialize an object of type T means:
+
+     - if T is a class type (clause 9) with a user-provided constructor
+       (12.1), then the default constructor for T is called (and the
+       initialization is ill-formed if T has no accessible default
+       constructor);
+
+     - if T is a non-union class type without a user-provided constructor,
+       then every non-static data member and base-class component of T is
+       value-initialized;92)
+
+     - if T is an array type, then each element is value-initialized;
+
+     - otherwise, the object is zero-initialized.
+
+     A program that calls for default-initialization or
+     value-initialization of an entity of reference type is ill-formed.
+
+     92) Value-initialization for such a class object may be implemented by
+     zero-initializing the object and then calling the default
+     constructor.  */
+
+  if (CLASS_TYPE_P (type))
+    {
+      if (TYPE_HAS_USER_CONSTRUCTOR (type) && !have_ctor)
+       return build_cplus_new
+         (type,
+          build_special_member_call (NULL_TREE, complete_ctor_identifier,
+                                     NULL_TREE, type, LOOKUP_NORMAL));
+      else if (TREE_CODE (type) != UNION_TYPE)
+       {
+         tree field, init;
+         VEC(constructor_elt,gc) *v = NULL;
+         bool call_ctor = !have_ctor && TYPE_NEEDS_CONSTRUCTING (type);
+
+         /* Iterate over the fields, building initializations.  */
+         for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+           {
+             tree ftype, value;
+
+             if (TREE_CODE (field) != FIELD_DECL)
+               continue;
+
+             ftype = TREE_TYPE (field);
+
+             if (TREE_CODE (ftype) == REFERENCE_TYPE)
+               error ("value-initialization of reference");
+
+             /* We could skip vfields and fields of types with
+                user-defined constructors, but I think that won't improve
+                performance at all; it should be simpler in general just
+                to zero out the entire object than try to only zero the
+                bits that actually need it.  */
+
+             /* Note that for class types there will be FIELD_DECLs
+                corresponding to base classes as well.  Thus, iterating
+                over TYPE_FIELDs will result in correct initialization of
+                all of the subobjects.  */
+             value = build_value_init_1 (ftype, have_ctor || call_ctor);
+
+             if (value)
+               CONSTRUCTOR_APPEND_ELT(v, field, value);
+           }
+
+         /* Build a constructor to contain the zero- initializations.  */
+         init = build_constructor (type, v);
+         if (call_ctor)
+           {
+             /* This is a class that needs constructing, but doesn't have
+                a user-defined constructor.  So we need to zero-initialize
+                the object and then call the implicitly defined ctor.
+                Implement this by sticking the zero-initialization inside
+                the TARGET_EXPR for the constructor call;
+                cp_gimplify_init_expr will know how to handle it.  */
+             tree ctor = build_special_member_call
+               (NULL_TREE, complete_ctor_identifier,
+                NULL_TREE, type, LOOKUP_NORMAL);
+
+             ctor = build_cplus_new (type, ctor);
+             init = build2 (INIT_EXPR, void_type_node,
+                            TARGET_EXPR_SLOT (ctor), init);
+             init = build2 (COMPOUND_EXPR, void_type_node, init,
+                            TARGET_EXPR_INITIAL (ctor));
+             TARGET_EXPR_INITIAL (ctor) = init;
+             return ctor;
+           }
+         return init;
+       }
+    }
+  else if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      VEC(constructor_elt,gc) *v = NULL;
+
+      /* Iterate over the array elements, building initializations.  */
+      tree max_index = array_type_nelts (type);
+
+      /* If we have an error_mark here, we should just return error mark
+        as we don't know the size of the array yet.  */
+      if (max_index == error_mark_node)
+       return error_mark_node;
+      gcc_assert (TREE_CODE (max_index) == INTEGER_CST);
+
+      /* A zero-sized array, which is accepted as an extension, will
+        have an upper bound of -1.  */
+      if (!tree_int_cst_equal (max_index, integer_minus_one_node))
+       {
+         constructor_elt *ce;
+
+         v = VEC_alloc (constructor_elt, gc, 1);
+         ce = VEC_quick_push (constructor_elt, v, NULL);
+
+         /* If this is a one element array, we just use a regular init.  */
+         if (tree_int_cst_equal (size_zero_node, max_index))
+           ce->index = size_zero_node;
+         else
+           ce->index = build2 (RANGE_EXPR, sizetype, size_zero_node,
+                               max_index);
+
+         ce->value = build_value_init_1 (TREE_TYPE (type), have_ctor);
+       }
+
+      /* Build a constructor to contain the initializations.  */
+      return build_constructor (type, v);
+    }
+
+  return build_zero_init (type, NULL_TREE, /*static_storage_p=*/false);
+}
+
+/* Return a suitable initializer for value-initializing an object of type
+   TYPE, as described in [dcl.init].  */
+
+tree
+build_value_init (tree type)
+{
+  return build_value_init_1 (type, false);
+}
+
 /* 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.  */
index b5caf5c7cb29092a07b4c58e627ced35aa7c2bb3..2b996d41ae1b4b4621ab86f27779ecae04e0b1b0 100644 (file)
@@ -2091,7 +2091,7 @@ check_explicit_specialization (tree declarator,
            {
              int is_constructor = DECL_CONSTRUCTOR_P (decl);
 
-             if (is_constructor ? !TYPE_HAS_CONSTRUCTOR (ctype)
+             if (is_constructor ? !TYPE_HAS_USER_CONSTRUCTOR (ctype)
                  : !CLASSTYPE_DESTRUCTORS (ctype))
                {
                  /* From [temp.expl.spec]:
@@ -6818,7 +6818,7 @@ instantiate_class_template (tree type)
   input_location = DECL_SOURCE_LOCATION (typedecl);
   in_system_header = DECL_IN_SYSTEM_HEADER (typedecl);
 
-  TYPE_HAS_CONSTRUCTOR (type) = TYPE_HAS_CONSTRUCTOR (pattern);
+  TYPE_HAS_USER_CONSTRUCTOR (type) = TYPE_HAS_USER_CONSTRUCTOR (pattern);
   TYPE_HAS_NEW_OPERATOR (type) = TYPE_HAS_NEW_OPERATOR (pattern);
   TYPE_HAS_ARRAY_NEW_OPERATOR (type) = TYPE_HAS_ARRAY_NEW_OPERATOR (pattern);
   TYPE_GETS_DELETE (type) = TYPE_GETS_DELETE (pattern);
index 6cac0efc1f855e1d22546e5c6ff4bcbcd2624d0a..1925d04fbc5fa5e268032edbde6fddc14d299759 100644 (file)
@@ -1318,7 +1318,6 @@ create_tinfo_types (void)
     ti->name = NULL_TREE;
     finish_builtin_struct (ti->type, "__type_info_pseudo",
                           fields, NULL_TREE);
-    TYPE_HAS_CONSTRUCTOR (ti->type) = 1;
   }
 
   /* Fundamental type_info */
@@ -1357,7 +1356,6 @@ create_tinfo_types (void)
     ti->name = NULL_TREE;
     finish_builtin_struct (ti->type, "__base_class_type_info_pseudo",
                           fields, NULL_TREE);
-    TYPE_HAS_CONSTRUCTOR (ti->type) = 1;
   }
 
   /* Pointer type_info. Adds two fields, qualification mask
index adbe9de75413e3b5411d481cfe5cdc514b11aa35..66c35d44e43e28fb312b0f3c2a85d9bb296f437f 100644 (file)
@@ -1310,6 +1310,8 @@ build_functional_cast (tree exp, tree parms)
 {
   /* This is either a call to a constructor,
      or a C cast in C++'s `functional' notation.  */
+
+  /* The type to which we are casting.  */
   tree type;
 
   if (exp == error_mark_node || parms == error_mark_node)
@@ -1350,20 +1352,31 @@ build_functional_cast (tree exp, tree parms)
   if (abstract_virtuals_error (NULL_TREE, type))
     return error_mark_node;
 
+  /* [expr.type.conv]
+
+     If the expression list is a single-expression, the type
+     conversion is equivalent (in definedness, and if defined in
+     meaning) to the corresponding cast expression.  */
   if (parms && TREE_CHAIN (parms) == NULL_TREE)
     return build_c_cast (type, TREE_VALUE (parms));
 
-  /* We need to zero-initialize POD types.  */
-  if (parms == NULL_TREE 
-      && !CLASSTYPE_NON_POD_P (type)
-      && TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
+  /* [expr.type.conv]
+
+     The expression T(), where T is a simple-type-specifier for a
+     non-array complete object type or the (possibly cv-qualified)
+     void type, creates an rvalue of the specified type, which is
+     value-initialized.  */
+
+  if (parms == NULL_TREE
+      /* If there's a user-defined constructor, value-initialization is
+        just calling the constructor, so fall through.  */
+      && !TYPE_HAS_USER_CONSTRUCTOR (type))
     {
-      exp = build_zero_init (type, 
-                            /*nelts=*/NULL_TREE,
-                            /*static_storage_p=*/false);
+      exp = build_value_init (type);
       return get_target_expr (exp);
     }
 
+  /* Call the constructor.  */
   exp = build_special_member_call (NULL_TREE, complete_ctor_identifier, parms,
                                   type, LOOKUP_NORMAL);
 
index 37c100786029a2cd3957dff5bd3fdb40485544cc..8f2ca7555c866a1619b472f6db5611863df65365 100644 (file)
@@ -851,6 +851,21 @@ print_node (FILE *file, const char *prefix, tree node, int indent)
              }
          break;
 
+       case CONSTRUCTOR:
+         {
+           unsigned HOST_WIDE_INT cnt;
+           tree index, value;
+           len = VEC_length (constructor_elt, CONSTRUCTOR_ELTS (node));
+           fprintf (file, " lngt %d", len);
+           FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (node),
+                                     cnt, index, value)
+             {
+               print_node (file, "idx", index, indent + 4);
+               print_node (file, "val", value, indent + 4);
+             }
+         }
+         break;
+
        case STATEMENT_LIST:
          dump_addr (file, " head ", node->stmt_list.head);
          dump_addr (file, " tail ", node->stmt_list.tail);
index beb92ef8519887d5c726027f91b6b80051d9ca12..3491f6a1d2cf07ab92ae25843e332b6388f92ec7 100644 (file)
@@ -1,9 +1,9 @@
 // PR c++/29039
 
-typedef struct S { // { dg-error "reference" }
+typedef struct S {
   int &r; 
 }; // { dg-warning "'typedef' was ignored" }
 
 S f () {
-  return S (); // { dg-error "synthesized" }
+  return S (); // { dg-error "reference" }
 }
diff --git a/gcc/testsuite/g++.dg/init/value1.C b/gcc/testsuite/g++.dg/init/value1.C
new file mode 100644 (file)
index 0000000..9dbc2e0
--- /dev/null
@@ -0,0 +1,22 @@
+// Test that with value-initialization, i is initialized to 0
+// and the vtable pointer is properly initialized.
+
+// { dg-do run }
+
+struct A
+{
+  int i;
+  virtual void f() {}
+};
+
+void f (A& a)
+{
+  a.f();
+}
+
+int main()
+{
+  A a = A();
+  f (a);
+  return a.i;
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wextra-1.C b/gcc/testsuite/g++.dg/warn/Wextra-1.C
new file mode 100644 (file)
index 0000000..c75a6b0
--- /dev/null
@@ -0,0 +1,12 @@
+// { dg-options "-Wextra" }
+
+struct T {
+  // If the implicitly-declared default constructor for "T" is
+  // required, an error will be issued because "i" cannot be
+  // initialized.  And, this class is not an aggregate, so it cannot
+  // be brace-initialized.  Thus, there is no way to create an object
+  // of this class.  We issue a warning with -Wextra.
+  const int i;                 // { dg-warning "const" }
+private:
+  int j;
+};
diff --git a/gcc/testsuite/g++.dg/warn/Wextra-2.C b/gcc/testsuite/g++.dg/warn/Wextra-2.C
new file mode 100644 (file)
index 0000000..5ca41c3
--- /dev/null
@@ -0,0 +1,15 @@
+// { dg-options "-Wextra" } 
+
+struct S {
+  S();
+};
+
+struct T {
+private:
+  int i;
+public:
+  // There should be no warning about this data member because the
+  // default constructor for "T" will invoke the default constructor
+  // for "S", even though "S" is "const".
+  const S s; // { dg-bogus "const" }
+};