re PR c++/7188 (Segfault with template class and recursive (incorrect) initalizer...
authorMark Mitchell <mark@codesourcery.com>
Wed, 2 Oct 2002 20:01:38 +0000 (20:01 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Wed, 2 Oct 2002 20:01:38 +0000 (20:01 +0000)
PR c++/7188.
* cp-tree.def (CTOR_INITIALIZER): Use one slot, not two.
* cp-tree.h (emit_base_init): Rename to ....
(emit_mem_initializers): ... this.
(expand_member_init): Change prototype.
* init.c (perform_member_init): Compute explicit, rather than
requiring it as a parameter.
(sort_member_init): Rename to ...
(sort_mem_initializers): ... this.  Process bases and data members
together.
(sort_base_init): Remove.
(emit_base_init): Rename to ...
(emit_mem_initializers): ... this.
(expand_aggr_vbase_init_1): Remove.
(construct_virtual_bases): Rename to ...
(construct_virtual_base): ... this.
(expand_member_init): Rework handling of base initializers.
* method.c (do_build_copy_constructor): Use
finish_mem_initializers.
* parse.y (member_init): Adjust calls to expand_member_init.
* pt.c (tsubst_expr): Simplify CTOR_INITIALIZER case.
(tsubst_initializer_list): Use expand_member_init.
* semantics.c (finish_mem_intiailizers): Simplify.

PR c++/7188.
* g++.dg/template/meminit1.C: New test.
* g++.dg/warn/Wreorder-1.C: Likewise.
* g++.old-deja/g++.mike/warn3.C: Tweak.
* lib/prune.exp: Ingore "in copy constructor".

From-SVN: r57748

13 files changed:
gcc/cp/ChangeLog
gcc/cp/cp-tree.def
gcc/cp/cp-tree.h
gcc/cp/init.c
gcc/cp/method.c
gcc/cp/parse.y
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/template/meminit1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wreorder-1.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.mike/warn3.C
gcc/testsuite/lib/prune.exp

index 16c986504dfb63d44acfed95006139b48735935a..7eb00b0e3350c2cd67ee4c329574ba3c10f17122 100644 (file)
@@ -1,3 +1,29 @@
+2002-10-02  Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/7188.
+       * cp-tree.def (CTOR_INITIALIZER): Use one slot, not two.
+       * cp-tree.h (emit_base_init): Rename to ....
+       (emit_mem_initializers): ... this.
+       (expand_member_init): Change prototype.
+       * init.c (perform_member_init): Compute explicit, rather than
+       requiring it as a parameter.
+       (sort_member_init): Rename to ...
+       (sort_mem_initializers): ... this.  Process bases and data members
+       together.
+       (sort_base_init): Remove.
+       (emit_base_init): Rename to ...
+       (emit_mem_initializers): ... this.
+       (expand_aggr_vbase_init_1): Remove.
+       (construct_virtual_bases): Rename to ...
+       (construct_virtual_base): ... this.
+       (expand_member_init): Rework handling of base initializers.
+       * method.c (do_build_copy_constructor): Use
+       finish_mem_initializers.
+       * parse.y (member_init): Adjust calls to expand_member_init.
+       * pt.c (tsubst_expr): Simplify CTOR_INITIALIZER case.
+       (tsubst_initializer_list): Use expand_member_init.
+       * semantics.c (finish_mem_intiailizers): Simplify.
+       
 2002-10-02  Roger Sayle  <roger@eyesopen.com>
 
        PR optimization/6627
index 90685af50d4007adca53c24bd4d4c573cc4943db..1aae797a4c23bfe8bfab4de439b1e733c216a073 100644 (file)
@@ -251,7 +251,7 @@ DEFTREECODE (PSEUDO_DTOR_EXPR, "pseudo_dtor_expr", 'e', 3)
 
 /* CTOR_INITIALIZER is a placeholder in template code for a call to
    setup_vtbl_pointer (and appears in all functions, not just ctors).  */
-DEFTREECODE (CTOR_INITIALIZER, "ctor_initializer", 'e', 2)
+DEFTREECODE (CTOR_INITIALIZER, "ctor_initializer", 'e', 1)
 DEFTREECODE (RETURN_INIT, "return_init", 'e', 2)
 DEFTREECODE (TRY_BLOCK, "try_block", 'e', 2)
 DEFTREECODE (EH_SPEC_BLOCK, "eh_spec_block", 'e', 2)
index db19e539da46f1539513b8c9fbc8f717b9e31dc4..5701a505f5d418100e6eb8369268cfc38f30b1a8 100644 (file)
@@ -3845,8 +3845,8 @@ extern void add_friend                          PARAMS ((tree, tree));
 extern tree do_friend                          PARAMS ((tree, tree, tree, tree, tree, enum overload_flags, tree, int));
 
 /* in init.c */
-extern void emit_base_init                     PARAMS ((tree, tree));
-extern tree expand_member_init                 PARAMS ((tree, tree, tree));
+extern tree expand_member_init                 (tree, tree);
+extern void emit_mem_initializers              (tree);
 extern tree build_aggr_init                    PARAMS ((tree, tree, int));
 extern tree build_init                         PARAMS ((tree, tree, int));
 extern int is_aggr_type                                PARAMS ((tree, int));
index ec74a25663917e68906cde122a5fb2dc868bb640..156822f40bfdf2872133441dd0e9b49239cce023 100644 (file)
@@ -34,17 +34,15 @@ Boston, MA 02111-1307, USA.  */
 #include "toplev.h"
 #include "ggc.h"
 
-static void expand_aggr_vbase_init_1 PARAMS ((tree, tree, tree, tree));
-static void construct_virtual_bases PARAMS ((tree, tree, tree, tree, tree));
+static void construct_virtual_base (tree, tree);
 static void expand_aggr_init_1 PARAMS ((tree, tree, tree, tree, int));
 static void expand_default_init PARAMS ((tree, tree, tree, tree, int));
 static tree build_vec_delete_1 PARAMS ((tree, tree, tree, special_function_kind, int));
-static void perform_member_init PARAMS ((tree, tree, int));
-static void sort_base_init PARAMS ((tree, tree, tree *, tree *));
+static void perform_member_init (tree, tree);
 static tree build_builtin_delete_call PARAMS ((tree));
 static int member_init_ok_or_else PARAMS ((tree, tree, tree));
 static void expand_virtual_init PARAMS ((tree, tree));
-static tree sort_member_init PARAMS ((tree, tree));
+static tree sort_mem_initializers (tree, tree);
 static tree initializing_context PARAMS ((tree));
 static void expand_cleanup_for_base PARAMS ((tree, tree));
 static tree get_temp_regvar PARAMS ((tree, tree));
@@ -303,16 +301,30 @@ build_default_init (type)
   return build_zero_init (type, /*static_storage_p=*/false);
 }
 
-/* Subroutine of emit_base_init.  */
+/* 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.  */
 
 static void
-perform_member_init (member, init, explicit)
-     tree member, init;
-     int explicit;
+perform_member_init (tree member, tree init)
 {
   tree decl;
   tree type = TREE_TYPE (member);
+  bool explicit;
 
+  explicit = (init != NULL_TREE);
+
+  /* Effective C++ rule 12 requires that all data members be
+     initialized.  */
+  if (warn_ecpp && !explicit && TREE_CODE (type) != ARRAY_TYPE)
+    warning ("`%D' should be initialized in the member initialization "
+            "list", 
+            member);
+
+  if (init == void_type_node)
+    init = NULL_TREE;
+
+  /* Get an lvalue for the data member.  */
   decl = build_class_member_access_expr (current_class_ref, member,
                                         /*access_path=*/NULL_TREE,
                                         /*preserve_reference=*/true);
@@ -333,11 +345,6 @@ perform_member_init (member, init, explicit)
   else if (TYPE_NEEDS_CONSTRUCTING (type)
           || (init && TYPE_HAS_CONSTRUCTOR (type)))
     {
-      /* Since `init' is already a TREE_LIST on the member_init_list,
-        only build it into one if we aren't already a list.  */
-      if (init != NULL_TREE && TREE_CODE (init) != TREE_LIST)
-       init = build_tree_list (NULL_TREE, init);
-
       if (explicit
          && TREE_CODE (type) == ARRAY_TYPE
          && init != NULL_TREE
@@ -443,79 +450,107 @@ build_field_list (t, list, uses_unions_p)
   return list;
 }
 
-/* The MEMBER_INIT_LIST is a TREE_LIST.  The TREE_PURPOSE of each list
-   gives a FIELD_DECL in T that needs initialization.  The TREE_VALUE
-   gives the initializer, or list of initializer arguments.  Sort the
-   MEMBER_INIT_LIST, returning a version that contains the same
-   information but in the order that the fields should actually be
-   initialized.  Perform error-checking in the process.  */
+/* The MEM_INITS are a TREE_LIST.  The TREE_PURPOSE of each list gives
+   a FIELD_DECL or BINFO in T that needs initialization.  The
+   TREE_VALUE gives the initializer, or list of initializer arguments.
+
+   Return a TREE_LIST containing all of the initializations required
+   for T, in the order in which they should be performed.  The output
+   list has the same format as the input.  */
 
 static tree
-sort_member_init (t, member_init_list)
-     tree t;
-     tree member_init_list;
+sort_mem_initializers (tree t, tree mem_inits)
 {
-  tree init_list;
-  tree last_field;
   tree init;
+  tree base;
+  tree sorted_inits;
+  tree next_subobject;
+  int i;
   int uses_unions_p;
 
-  /* Build up a list of the various fields, in sorted order.  */
-  init_list = nreverse (build_field_list (t, NULL_TREE, &uses_unions_p));
-
-  /* Go through the explicit initializers, adding them to the
-     INIT_LIST.  */
-  last_field = init_list;
-  for (init = member_init_list; init; init = TREE_CHAIN (init))
-    {
-      tree f;
-      tree initialized_field;
-
-      initialized_field = TREE_PURPOSE (init);
-      my_friendly_assert (TREE_CODE (initialized_field) == FIELD_DECL,
-                         20000516);
-
-      /* If the explicit initializers are in sorted order, then the
-        INITIALIZED_FIELD will be for a field following the
-        LAST_FIELD.  */
-      for (f = last_field; f; f = TREE_CHAIN (f))
-       if (TREE_PURPOSE (f) == initialized_field)
+  /* Build up a list of initializations.  The TREE_PURPOSE of entry
+     will be the subobject (a FIELD_DECL or BINFO) to initialize.  The
+     TREE_VALUE will be the constructor arguments, or NULL if no
+     explicit initialization was provided.  */
+  sorted_inits = NULL_TREE;
+  /* Process the virtual bases.  */
+  for (base = CLASSTYPE_VBASECLASSES (t); base; base = TREE_CHAIN (base))
+    sorted_inits = tree_cons (TREE_VALUE (base), NULL_TREE, sorted_inits);
+  /* Process the direct bases.  */
+  for (i = 0; i < CLASSTYPE_N_BASECLASSES (t); ++i)
+    {
+      base = BINFO_BASETYPE (TYPE_BINFO (t), i);
+      if (!TREE_VIA_VIRTUAL (base))
+       sorted_inits = tree_cons (base, NULL_TREE, sorted_inits);
+    }
+  /* Process the non-static data members.  */
+  sorted_inits = build_field_list (t, sorted_inits, &uses_unions_p);
+  /* Reverse the entire list of initializations, so that they are in
+     the order that they will actually be performed.  */
+  sorted_inits = nreverse (sorted_inits);
+
+  /* If the user presented the initializers in an order different from
+     that in which they will actually occur, we issue a warning.  Keep
+     track of the next subobject which can be explicitly initialized
+     without issuing a warning.  */
+  next_subobject = sorted_inits;
+
+  /* Go through the explicit initializers, filling in TREE_PURPOSE in
+     the SORTED_INITS.  */
+  for (init = mem_inits; init; init = TREE_CHAIN (init))
+    {
+      tree subobject;
+      tree subobject_init;
+
+      subobject = TREE_PURPOSE (init);
+
+      /* If the explicit initializers are in sorted order, then
+        SUBOBJECT will be NEXT_SUBOBJECT, or something following 
+        it.  */
+      for (subobject_init = next_subobject; 
+          subobject_init; 
+          subobject_init = TREE_CHAIN (subobject_init))
+       if (TREE_PURPOSE (subobject_init) == subobject)
          break;
 
-      /* Give a warning, if appropriate.  */
-      if (warn_reorder && !f)
+      /* Issue a warning if the explicit initializer order does not
+        match that which will actually occur.  */
+      if (warn_reorder && !subobject_init)
        {
-         cp_warning_at ("member initializers for `%#D'", 
-                        TREE_PURPOSE (last_field));
-         cp_warning_at ("  and `%#D'", initialized_field);
-         warning ("  will be re-ordered to match declaration order");
+         if (TREE_CODE (TREE_PURPOSE (next_subobject)) == FIELD_DECL)
+           cp_warning_at ("`%D' will be initialized after",
+                          TREE_PURPOSE (next_subobject));
+         else
+           warning ("base `%T' will be initialized after",
+                    TREE_PURPOSE (next_subobject));
+         if (TREE_CODE (subobject) == FIELD_DECL)
+           cp_warning_at ("  `%#D'", subobject);
+         else
+           warning ("  base `%T'", subobject);
        }
 
-      /* Look again, from the beginning of the list.  We must find the
-        field on this loop.  */
-      if (!f)
+      /* Look again, from the beginning of the list.  */
+      if (!subobject_init)
        {
-         f = init_list;
-         while (TREE_PURPOSE (f) != initialized_field)
-           f = TREE_CHAIN (f);
+         subobject_init = sorted_inits;
+         while (TREE_PURPOSE (subobject_init) != subobject)
+           subobject_init = TREE_CHAIN (subobject_init);
        }
-
-      /* If there was already an explicit initializer for this field,
-        issue an error.  */
-      if (TREE_TYPE (f))
-       error ("multiple initializations given for member `%D'",
-                 initialized_field);
-      else
+       
+      /* It is invalid to initialize the same subobject more than
+        once.  */
+      if (TREE_VALUE (subobject_init))
        {
-         /* Mark the field as explicitly initialized.  */
-         TREE_TYPE (f) = error_mark_node;
-         /* And insert the initializer.  */
-         TREE_VALUE (f) = TREE_VALUE (init);
+         if (TREE_CODE (subobject) == FIELD_DECL)
+           error ("multiple initializations given for `%D'", subobject);
+         else
+           error ("multiple initializations given for base `%T'", 
+                  subobject);
        }
 
-      /* Remember the location of the last explicitly initialized
-        field.  */
-      last_field = f;
+      /* Record the initialization.  */
+      TREE_VALUE (subobject_init) = TREE_VALUE (init);
+      next_subobject = subobject_init;
     }
 
   /* [class.base.init]
@@ -525,15 +560,16 @@ sort_member_init (t, member_init_list)
      anonymous unions), the ctor-initializer is ill-formed.  */
   if (uses_unions_p)
     {
-      last_field = NULL_TREE;
-      for (init = init_list; init; init = TREE_CHAIN (init))
+      tree last_field = NULL_TREE;
+      for (init = sorted_inits; init; init = TREE_CHAIN (init))
        {
          tree field;
          tree field_type;
          int done;
 
-         /* Skip uninitialized members.  */
-         if (!TREE_TYPE (init))
+         /* Skip uninitialized members and base classes.  */
+         if (!TREE_VALUE (init) 
+             || TREE_CODE (TREE_PURPOSE (init)) != FIELD_DECL)
            continue;
          /* See if this field is a member of a union, or a member of a
             structure contained in a union, etc.  */
@@ -600,231 +636,73 @@ sort_member_init (t, member_init_list)
        }
     }
 
-  return init_list;
+  return sorted_inits;
 }
 
-/* Like sort_member_init, but used for initializers of base classes.
-   *RBASE_PTR is filled in with the initializers for non-virtual bases;
-   vbase_ptr gets the virtual bases.  */
-
-static void
-sort_base_init (t, base_init_list, rbase_ptr, vbase_ptr)
-     tree t;
-     tree base_init_list;
-     tree *rbase_ptr, *vbase_ptr;
-{
-  tree binfos = BINFO_BASETYPES (TYPE_BINFO (t));
-  int n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-
-  int i;
-  tree x;
-  tree last;
-
-  /* For warn_reorder.  */
-  int last_pos = 0;
-  tree last_base = NULL_TREE;
-
-  tree rbases = NULL_TREE;
-  tree vbases = NULL_TREE;
-
-  /* First walk through and splice out vbase and invalid initializers.
-     Also replace types with binfos.  */
-
-  last = tree_cons (NULL_TREE, NULL_TREE, base_init_list);
-  for (x = TREE_CHAIN (last); x; x = TREE_CHAIN (x))
-    {
-      tree basetype = TREE_PURPOSE (x);
-      tree binfo = (TREE_CODE (basetype) == TREE_VEC
-                   ? basetype : binfo_or_else (basetype, t));
-      
-      if (binfo == NULL_TREE)
-       /* BASETYPE might be an inaccessible direct base (because it
-          is also an indirect base).  */
-       continue;
-
-      if (TREE_VIA_VIRTUAL (binfo))
-       {
-         /* Virtual base classes are special cases.  Their
-            initializers are recorded with this constructor, and they
-            are used when this constructor is the top-level
-            constructor called.  */
-         tree v = binfo_for_vbase (BINFO_TYPE (binfo), t);
-         vbases = tree_cons (v, TREE_VALUE (x), vbases);
-       }
-      else
-       {
-         /* Otherwise, it must be an immediate base class.  */
-         my_friendly_assert
-           (same_type_p (BINFO_TYPE (BINFO_INHERITANCE_CHAIN (binfo)),
-                         t), 20011113);
-
-         TREE_PURPOSE (x) = binfo;
-         TREE_CHAIN (last) = x;
-         last = x;
-       }
-    }
-  TREE_CHAIN (last) = NULL_TREE;
-
-  /* Now walk through our regular bases and make sure they're initialized.  */
-
-  for (i = 0; i < n_baseclasses; ++i)
-    {
-      /* The base for which we're currently initializing.  */
-      tree base_binfo = TREE_VEC_ELT (binfos, i);
-      /* The initializer for BASE_BINFO.  */
-      tree init;
-      int pos;
-
-      if (TREE_VIA_VIRTUAL (base_binfo))
-       continue;
-
-      /* We haven't found the BASE_BINFO yet.  */
-      init = NULL_TREE;
-      /* Loop through all the explicitly initialized bases, looking
-        for an appropriate initializer.  */
-      for (x = base_init_list, pos = 0; x; x = TREE_CHAIN (x), ++pos)
-       {
-         tree binfo = TREE_PURPOSE (x);
-
-         if (binfo == base_binfo && !init)
-           {
-             if (warn_reorder)
-               {
-                 if (pos < last_pos)
-                   {
-                     cp_warning_at ("base initializers for `%#T'", last_base);
-                     cp_warning_at ("  and `%#T'", BINFO_TYPE (binfo));
-                     warning ("  will be re-ordered to match inheritance order");
-                   }
-                 last_pos = pos;
-                 last_base = BINFO_TYPE (binfo);
-               }
-
-             /* Make sure we won't try to work on this init again.  */
-             TREE_PURPOSE (x) = NULL_TREE;
-             init = build_tree_list (binfo, TREE_VALUE (x));
-           }
-         else if (binfo == base_binfo)
-           {
-             error ("base class `%T' already initialized", 
-                       BINFO_TYPE (binfo));
-             break;
-           }
-       }
-
-      /* If we didn't find BASE_BINFO in the list, create a dummy entry
-        so the two lists (RBASES and the list of bases) will be
-        symmetrical.  */
-      if (!init)
-       init = build_tree_list (NULL_TREE, NULL_TREE);
-      rbases = chainon (rbases, init);
-    }
-
-  *rbase_ptr = rbases;
-  *vbase_ptr = vbases;
-}
-
-/* Perform whatever initializations have yet to be done on the base
-   class, and non-static data members, of the CURRENT_CLASS_TYPE.
-   These actions are given by the BASE_INIT_LIST and MEM_INIT_LIST,
-   respectively.
-
-   If there is a need for a call to a constructor, we must surround
-   that call with a pushlevel/poplevel pair, since we are technically
-   at the PARM level of scope.  */
+/* Initialize all bases and members of CURRENT_CLASS_TYPE.  MEM_INITS
+   is a TREE_LIST giving the explicit mem-initializer-list for the
+   constructor.  The TREE_PURPOSE of each entry is a subobject (a
+   FIELD_DECL or a BINFO) of the CURRENT_CLASS_TYPE.  The TREE_VALUE
+   is a TREE_LIST giving the arguments to the constructor or
+   void_type_node for an empty list of arguments.  */
 
 void
-emit_base_init (mem_init_list, base_init_list)
-     tree mem_init_list;
-     tree base_init_list;
+emit_mem_initializers (tree mem_inits)
 {
-  tree member;
-  tree rbase_init_list, vbase_init_list;
-  tree t = current_class_type;
-  tree t_binfo = TYPE_BINFO (t);
-  tree binfos = BINFO_BASETYPES (t_binfo);
-  int i;
-  int n_baseclasses = BINFO_N_BASETYPES (t_binfo);
-
-  mem_init_list = sort_member_init (t, mem_init_list);
-  sort_base_init (t, base_init_list, &rbase_init_list, &vbase_init_list);
-
-  /* First, initialize the virtual base classes, if we are
-     constructing the most-derived object.  */
-  if (TYPE_USES_VIRTUAL_BASECLASSES (t))
-    {
-      tree first_arg = TREE_CHAIN (DECL_ARGUMENTS (current_function_decl));
-      construct_virtual_bases (t, current_class_ref, current_class_ptr,
-                              vbase_init_list, first_arg);
-    }
-
-  /* Now, perform initialization of non-virtual base classes.  */
-  for (i = 0; i < n_baseclasses; i++)
-    {
-      tree base_binfo = TREE_VEC_ELT (binfos, i);
-      tree init = void_list_node;
-
-      if (TREE_VIA_VIRTUAL (base_binfo))
-       continue;
-
-      my_friendly_assert (BINFO_INHERITANCE_CHAIN (base_binfo) == t_binfo,
-                         999);
-
-      if (TREE_PURPOSE (rbase_init_list))
-       init = TREE_VALUE (rbase_init_list);
-      else if (TYPE_NEEDS_CONSTRUCTING (BINFO_TYPE (base_binfo)))
-       {
-         init = NULL_TREE;
-         if (extra_warnings 
-             && DECL_COPY_CONSTRUCTOR_P (current_function_decl))
-           warning ("base class `%#T' should be explicitly initialized in the copy constructor",
-                       BINFO_TYPE (base_binfo));
-       }
-
-      if (init != void_list_node)
+  /* Sort the mem-initializers into the order in which the
+     initializations should be performed.  */
+  mem_inits = sort_mem_initializers (current_class_type, mem_inits);
+
+  /* Initialize base classes.  */
+  while (mem_inits 
+        && TREE_CODE (TREE_PURPOSE (mem_inits)) != FIELD_DECL)
+    {
+      tree subobject = TREE_PURPOSE (mem_inits);
+      tree arguments = TREE_VALUE (mem_inits);
+
+      /* If these initializations are taking place in a copy
+        constructor, the base class should probably be explicitly
+        initialized.  */
+      if (extra_warnings && !arguments 
+         && DECL_COPY_CONSTRUCTOR_P (current_function_decl)
+         && TYPE_NEEDS_CONSTRUCTING (BINFO_TYPE (subobject)))
+       warning ("base class `%#T' should be explicitly initialized in the "
+                "copy constructor",
+                BINFO_TYPE (subobject));
+
+      /* If an explicit -- but empty -- initializer list was present,
+        treat it just like default initialization at this point.  */
+      if (arguments == void_type_node)
+       arguments = NULL_TREE;
+
+      /* Initialize the base.  */
+      if (TREE_VIA_VIRTUAL (subobject))
+       construct_virtual_base (subobject, arguments);
+      else
        {
-         member = build_base_path (PLUS_EXPR, current_class_ptr,
-                                   base_binfo, 1);
-         expand_aggr_init_1 (base_binfo, NULL_TREE,
-                             build_indirect_ref (member, NULL), init,
+         tree base_addr;
+         
+         base_addr = build_base_path (PLUS_EXPR, current_class_ptr,
+                                      subobject, 1);
+         expand_aggr_init_1 (subobject, NULL_TREE,
+                             build_indirect_ref (base_addr, NULL), 
+                             arguments,
                              LOOKUP_NORMAL);
+         expand_cleanup_for_base (subobject, NULL_TREE);
        }
 
-      expand_cleanup_for_base (base_binfo, NULL_TREE);
-      rbase_init_list = TREE_CHAIN (rbase_init_list);
+      mem_inits = TREE_CHAIN (mem_inits);
     }
 
-  /* Initialize the vtable pointers for the class.  */
+  /* Initialize the vptrs.  */
   initialize_vtbl_ptrs (current_class_ptr);
 
-  while (mem_init_list)
+  /* Initialize the data members.  */
+  while (mem_inits)
     {
-      tree init;
-      tree member;
-      int from_init_list;
-
-      member = TREE_PURPOSE (mem_init_list);
-
-      /* See if we had a user-specified member initialization.  */
-      if (TREE_TYPE (mem_init_list))
-       {
-         init = TREE_VALUE (mem_init_list);
-         from_init_list = 1;
-       }
-      else
-       {
-         init = DECL_INITIAL (member);
-         from_init_list = 0;
-
-         /* Effective C++ rule 12.  */
-         if (warn_ecpp && init == NULL_TREE
-             && !DECL_ARTIFICIAL (member)
-             && TREE_CODE (TREE_TYPE (member)) != ARRAY_TYPE)
-           warning ("`%D' should be initialized in the member initialization list", member);       
-       }
-
-      perform_member_init (member, init, from_init_list);
-      mem_init_list = TREE_CHAIN (mem_init_list);
+      perform_member_init (TREE_PURPOSE (mem_inits),
+                          TREE_VALUE (mem_inits));
+      mem_inits = TREE_CHAIN (mem_inits);
     }
 }
 
@@ -948,89 +826,57 @@ expand_cleanup_for_base (binfo, flag)
   finish_eh_cleanup (expr);
 }
 
-/* Subroutine of `expand_aggr_vbase_init'.
-   BINFO is the binfo of the type that is being initialized.
-   INIT_LIST is the list of initializers for the virtual baseclass.  */
+/* Construct the virtual base-class VBASE passing the ARGUMENTS to its
+   constructor.  */
 
 static void
-expand_aggr_vbase_init_1 (binfo, exp, addr, init_list)
-     tree binfo, exp, addr, init_list;
+construct_virtual_base (tree vbase, tree arguments)
 {
-  tree init = purpose_member (binfo, init_list);
-  tree ref = build_indirect_ref (addr, NULL);
-
-  if (init)
-    init = TREE_VALUE (init);
-  /* Call constructors, but don't set up vtables.  */
-  expand_aggr_init_1 (binfo, exp, ref, init, LOOKUP_COMPLAIN);
-}
-
-/* Construct the virtual base-classes of THIS_REF (whose address is
-   THIS_PTR).  The object has the indicated TYPE.  The construction
-   actually takes place only if FLAG is nonzero.  INIT_LIST is list
-   of initializations for constructors to perform.  */
-
-static void
-construct_virtual_bases (type, this_ref, this_ptr, init_list, flag)
-     tree type;
-     tree this_ref;
-     tree this_ptr;
-     tree init_list;
-     tree flag;
-{
-  tree vbases;
-
-  /* If there are no virtual baseclasses, we shouldn't even be here.  */
-  my_friendly_assert (TYPE_USES_VIRTUAL_BASECLASSES (type), 19990621);
-
-  /* Now, run through the baseclasses, initializing each.  */ 
-  for (vbases = CLASSTYPE_VBASECLASSES (type); vbases;
-       vbases = TREE_CHAIN (vbases))
-    {
-      tree inner_if_stmt;
-      tree compound_stmt;
-      tree exp;
-      tree vbase;
-
-      /* If there are virtual base classes with destructors, we need to
-        emit cleanups to destroy them if an exception is thrown during
-        the construction process.  These exception regions (i.e., the
-        period during which the cleanups must occur) begin from the time
-        the construction is complete to the end of the function.  If we
-        create a conditional block in which to initialize the
-        base-classes, then the cleanup region for the virtual base begins
-        inside a block, and ends outside of that block.  This situation
-        confuses the sjlj exception-handling code.  Therefore, we do not
-        create a single conditional block, but one for each
-        initialization.  (That way the cleanup regions always begin
-        in the outer block.)  We trust the back-end to figure out
-        that the FLAG will not change across initializations, and
-        avoid doing multiple tests.  */
-      inner_if_stmt = begin_if_stmt ();
-      finish_if_stmt_cond (flag, inner_if_stmt);
-      compound_stmt = begin_compound_stmt (/*has_no_scope=*/1);
-
-      /* Compute the location of the virtual base.  If we're
-        constructing virtual bases, then we must be the most derived
-        class.  Therefore, we don't have to look up the virtual base;
-        we already know where it is.  */
-      vbase = TREE_VALUE (vbases);
-      exp = build (PLUS_EXPR,
-                  TREE_TYPE (this_ptr),
-                  this_ptr,
-                  fold (build1 (NOP_EXPR, TREE_TYPE (this_ptr),
-                                BINFO_OFFSET (vbase))));
-      exp = build1 (NOP_EXPR, 
-                   build_pointer_type (BINFO_TYPE (vbase)), 
-                   exp);
-
-      expand_aggr_vbase_init_1 (vbase, this_ref, exp, init_list);
-      finish_compound_stmt (/*has_no_scope=*/1, compound_stmt);
-      finish_then_clause (inner_if_stmt);
-      finish_if_stmt ();
-      
-      expand_cleanup_for_base (vbase, flag);
-    }
+  tree inner_if_stmt;
+  tree compound_stmt;
+  tree exp;
+  tree flag;  
+
+  /* If there are virtual base classes with destructors, we need to
+     emit cleanups to destroy them if an exception is thrown during
+     the construction process.  These exception regions (i.e., the
+     period during which the cleanups must occur) begin from the time
+     the construction is complete to the end of the function.  If we
+     create a conditional block in which to initialize the
+     base-classes, then the cleanup region for the virtual base begins
+     inside a block, and ends outside of that block.  This situation
+     confuses the sjlj exception-handling code.  Therefore, we do not
+     create a single conditional block, but one for each
+     initialization.  (That way the cleanup regions always begin
+     in the outer block.)  We trust the back-end to figure out
+     that the FLAG will not change across initializations, and
+     avoid doing multiple tests.  */
+  flag = TREE_CHAIN (DECL_ARGUMENTS (current_function_decl));
+  inner_if_stmt = begin_if_stmt ();
+  finish_if_stmt_cond (flag, inner_if_stmt);
+  compound_stmt = begin_compound_stmt (/*has_no_scope=*/1);
+
+  /* Compute the location of the virtual base.  If we're
+     constructing virtual bases, then we must be the most derived
+     class.  Therefore, we don't have to look up the virtual base;
+     we already know where it is.  */
+  exp = build (PLUS_EXPR,
+              TREE_TYPE (current_class_ptr),
+              current_class_ptr,
+              fold (build1 (NOP_EXPR, TREE_TYPE (current_class_ptr),
+                            BINFO_OFFSET (vbase))));
+  exp = build1 (NOP_EXPR, 
+               build_pointer_type (BINFO_TYPE (vbase)), 
+               exp);
+  exp = build1 (INDIRECT_REF, BINFO_TYPE (vbase), exp);
+
+  expand_aggr_init_1 (vbase, current_class_ref, exp,
+                     arguments, LOOKUP_COMPLAIN);
+  finish_compound_stmt (/*has_no_scope=*/1, compound_stmt);
+  finish_then_clause (inner_if_stmt);
+  finish_if_stmt ();
+
+  expand_cleanup_for_base (vbase, flag);
 }
 
 /* Find the context in which this FIELD can be initialized.  */
@@ -1079,46 +925,41 @@ member_init_ok_or_else (field, type, member_name)
   return 1;
 }
 
-/* EXP is an expression of aggregate type. NAME is an IDENTIFIER_NODE
-   which names a field, or it is a _TYPE node or TYPE_DECL which names
-   a base for that type.  INIT is a parameter list for that field's or
-   base's constructor.  Check the validity of NAME, and return a
-   TREE_LIST of the base _TYPE or FIELD_DECL and the INIT. EXP is used
-   only to get its type.  If NAME is invalid, return NULL_TREE and
-   issue a diagnostic.
+/* NAME is a FIELD_DECL, an IDENTIFIER_NODE which names a field, or it
+   is a _TYPE node or TYPE_DECL which names a base for that type.
+   INIT is a parameter list for that field's or base's constructor.
+   Check the validity of NAME, and return a TREE_LIST of the base
+   _TYPE or FIELD_DECL and the INIT.  If NAME is invalid, return
+   NULL_TREE and issue a diagnostic.
 
    An old style unnamed direct single base construction is permitted,
    where NAME is NULL.  */
 
 tree
-expand_member_init (exp, name, init)
-     tree exp, name, init;
+expand_member_init (tree name, tree init)
 {
-  tree basetype = NULL_TREE, field;
-  tree type;
+  tree basetype;
+  tree field;
 
-  if (exp == NULL_TREE)
+  if (!current_class_ref)
     return NULL_TREE;
 
-  type = TYPE_MAIN_VARIANT (TREE_TYPE (exp));
-  my_friendly_assert (IS_AGGR_TYPE (type), 20011113);
-
   if (!name)
     {
       /* This is an obsolete unnamed base class initializer.  The
         parser will already have warned about its use.  */
-      switch (CLASSTYPE_N_BASECLASSES (type))
+      switch (CLASSTYPE_N_BASECLASSES (current_class_type))
        {
        case 0:
          error ("unnamed initializer for `%T', which has no base classes",
-                   type);
+                current_class_type);
          return NULL_TREE;
        case 1:
-         basetype = TYPE_BINFO_BASETYPE (type, 0);
+         basetype = TYPE_BINFO_BASETYPE (current_class_type, 0);
          break;
        default:
          error ("unnamed initializer for `%T', which uses multiple inheritance",
-                   type);
+                current_class_type);
          return NULL_TREE;
       }
     }
@@ -1129,44 +970,54 @@ expand_member_init (exp, name, init)
     }
   else if (TREE_CODE (name) == TYPE_DECL)
     basetype = TYPE_MAIN_VARIANT (TREE_TYPE (name));
+  else
+    basetype = NULL_TREE;
 
   my_friendly_assert (init != NULL_TREE, 0);
 
-  if (init == void_type_node)
-    init = NULL_TREE;
-
   if (basetype)
     {
+      tree binfo;
+
       if (current_template_parms)
-       ;
-      else if (vec_binfo_member (basetype, TYPE_BINFO_BASETYPES (type)))
-       /* A direct base.  */;
-      else if (binfo_for_vbase (basetype, type))
-       /* A virtual base.  */;
-      else
+       return build_tree_list (basetype, init);
+
+      binfo = lookup_base (current_class_type, basetype, 
+                          ba_ignore, NULL);
+      if (binfo)
+       {
+         if (TREE_VIA_VIRTUAL (binfo))
+           binfo = binfo_for_vbase (basetype, current_class_type);
+         else if (BINFO_INHERITANCE_CHAIN (binfo) 
+                  != TYPE_BINFO (current_class_type))
+           binfo = NULL_TREE;
+       }
+      if (!binfo)
        {
-         if (TYPE_USES_VIRTUAL_BASECLASSES (type))
+         if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
            error ("type `%D' is not a direct or virtual base of `%T'",
-                     name, type);
+                  name, current_class_type);
          else
            error ("type `%D' is not a direct base of `%T'",
-                     name, type);
+                  name, current_class_type);
          return NULL_TREE;
        }
 
-      init = build_tree_list (basetype, init);
+      if (binfo)
+       return build_tree_list (binfo, init);
     }
   else
     {
-      field = lookup_field (type, name, 1, 0);
-
-      if (! member_init_ok_or_else (field, type, name))
-       return NULL_TREE;
+      if (TREE_CODE (name) == IDENTIFIER_NODE)
+       field = lookup_field (current_class_type, name, 1, 0);
+      else
+       field = name;
 
-      init = build_tree_list (field, init);
+      if (member_init_ok_or_else (field, current_class_type, name))
+       return build_tree_list (field, init);
     }
 
-  return init;
+  return NULL_TREE;
 }
 
 /* This is like `expand_member_init', only it stores one aggregate
index 6b4b79524fbc048347389440c7c762059387f9e3..065818132e9d0fa61ada2b2e9fd1c9ca7694f97e 100644 (file)
@@ -536,7 +536,6 @@ do_build_copy_constructor (fndecl)
       int n_bases = CLASSTYPE_N_BASECLASSES (current_class_type);
       tree binfos = TYPE_BINFO_BASETYPES (current_class_type);
       tree member_init_list = NULL_TREE;
-      tree base_init_list = NULL_TREE;
       int cvquals = cp_type_quals (TREE_TYPE (parm));
       int i;
 
@@ -550,10 +549,12 @@ do_build_copy_constructor (fndecl)
        {
          tree binfo = TREE_VALUE (t);
          
-         base_init_list = tree_cons (binfo,
-                                     build_base_path (PLUS_EXPR, parm,
-                                                      binfo, 1),
-                                     base_init_list);
+         member_init_list 
+           = tree_cons (binfo,
+                        build_tree_list (NULL_TREE,
+                                         build_base_path (PLUS_EXPR, parm,
+                                                          binfo, 1)),
+                        member_init_list);
        }
 
       for (i = 0; i < n_bases; ++i)
@@ -562,10 +563,12 @@ do_build_copy_constructor (fndecl)
          if (TREE_VIA_VIRTUAL (binfo))
            continue; 
 
-         base_init_list = tree_cons (binfo,
-                                     build_base_path (PLUS_EXPR, parm,
-                                                      binfo, 1),
-                                     base_init_list);
+         member_init_list 
+           = tree_cons (binfo,
+                        build_tree_list (NULL_TREE,
+                                         build_base_path (PLUS_EXPR, parm,
+                                                          binfo, 1)),
+                        member_init_list);
        }
 
       for (; fields; fields = TREE_CHAIN (fields))
@@ -609,9 +612,7 @@ do_build_copy_constructor (fndecl)
          member_init_list
            = tree_cons (field, init, member_init_list);
        }
-      member_init_list = nreverse (member_init_list);
-      base_init_list = nreverse (base_init_list);
-      emit_base_init (member_init_list, base_init_list);
+      finish_mem_initializers (member_init_list);
     }
 }
 
index 8cce99bd5c01b5e26edd9cbb9febb36b682f6e56..b404e6a2fdaa3a89301588fd9bc735adb8ba80fa 100644 (file)
@@ -981,31 +981,27 @@ member_init:
                {
                  if (current_class_name)
                    pedwarn ("anachronistic old style base class initializer");
-                 $$ = expand_member_init (current_class_ref, NULL_TREE, $2);
+                 $$ = expand_member_init (NULL_TREE, $2);
                }
        | LEFT_RIGHT
                {
                  if (current_class_name)
                    pedwarn ("anachronistic old style base class initializer");
-                 $$ = expand_member_init (current_class_ref,
-                                          NULL_TREE,
+                 $$ = expand_member_init (NULL_TREE,
                                           void_type_node);
                }
        | notype_identifier '(' nonnull_exprlist ')'
-               { $$ = expand_member_init (current_class_ref, $1, $3); }
+               { $$ = expand_member_init ($1, $3); }
        | notype_identifier LEFT_RIGHT
-               { $$ = expand_member_init (current_class_ref, $1,
-                                          void_type_node); }
+               { $$ = expand_member_init ($1, void_type_node); }
        | nonnested_type '(' nonnull_exprlist ')'
-               { $$ = expand_member_init (current_class_ref, $1, $3); }
+               { $$ = expand_member_init ($1, $3); }
        | nonnested_type LEFT_RIGHT
-               { $$ = expand_member_init (current_class_ref, $1,
-                                          void_type_node); }
+               { $$ = expand_member_init ($1, void_type_node); }
        | typename_sub '(' nonnull_exprlist ')'
-               { $$ = expand_member_init (current_class_ref, $1, $3); }
+               { $$ = expand_member_init ($1, $3); }
        | typename_sub LEFT_RIGHT
-               { $$ = expand_member_init (current_class_ref, $1,
-                                          void_type_node); }
+               { $$ = expand_member_init ($1, void_type_node); }
         | error
                 { $$ = NULL_TREE; }
        ;
index 47421a0b09d642dd3600205105616f9d7ba46622..6d8ec065a9e517b2fcf6bcedaeb1b785cd76147e 100644 (file)
@@ -7369,18 +7369,10 @@ tsubst_expr (t, args, complain, in_decl)
       break;
 
     case CTOR_INITIALIZER:
-      {
-       tree member_init_list;
-       tree base_init_list;
-
-       prep_stmt (t);
-       member_init_list
-         = tsubst_initializer_list (TREE_OPERAND (t, 0), args);
-       base_init_list
-         = tsubst_initializer_list (TREE_OPERAND (t, 1), args);
-       emit_base_init (member_init_list, base_init_list);
-       break;
-      }
+      prep_stmt (t);
+      finish_mem_initializers (tsubst_initializer_list 
+                              (TREE_OPERAND (t, 0), args));
+      break;
 
     case RETURN_STMT:
       prep_stmt (t);
@@ -10293,8 +10285,7 @@ static tree
 tsubst_initializer_list (t, argvec)
      tree t, argvec;
 {
-  tree first = NULL_TREE;
-  tree *p = &first;
+  tree inits = NULL_TREE;
 
   for (; t; t = TREE_CHAIN (t))
     {
@@ -10312,13 +10303,17 @@ tsubst_initializer_list (t, argvec)
       else if (TREE_CODE (init) == TREE_LIST)
        for (val = init; val; val = TREE_CHAIN (val))
          TREE_VALUE (val) = convert_from_reference (TREE_VALUE (val));
-      else
+      else if (init != void_type_node)
        init = convert_from_reference (init);
 
-      *p = build_tree_list (decl, init);
-      p = &TREE_CHAIN (*p);
+      init = expand_member_init (decl, init);
+      if (init)
+       {
+         TREE_CHAIN (init) = inits;
+         inits = init;
+       }
     }
-  return first;
+  return inits;
 }
 
 /* Set CURRENT_ACCESS_SPECIFIER based on the protection of DECL.  */
index 7edfa98fd6f1562d24934df31a63f3f80f1cef04..27fa97a4332f31f2b1244831f8ba2e14083f0c29 100644 (file)
@@ -1094,67 +1094,21 @@ begin_mem_initializers ()
     error ("only constructors take base initializers");
 }
 
-/* The INIT_LIST is a list of mem-initializers, in the order they were
-   written by the user.  The TREE_VALUE of each node is a list of
-   initializers for a particular subobject.  The TREE_PURPOSE is a
-   FIELD_DECL is the initializer is for a non-static data member, and
-   a class type if the initializer is for a base class.  */
+/* The MEM_INITS is a list of mem-initializers, in reverse of the
+   order they were written by the user.  Each node is as for
+   emit_mem_initializers.  */
 
 void
-finish_mem_initializers (init_list)
-     tree init_list;
+finish_mem_initializers (tree mem_inits)
 {
-  tree member_init_list;
-  tree base_init_list;
-  tree last_base_warned_about;
-  tree next; 
-  tree init;
-
-  member_init_list = NULL_TREE;
-  base_init_list = NULL_TREE;
-  last_base_warned_about = NULL_TREE;
-
-  for (init = init_list; init; init = next)
-    {
-      next = TREE_CHAIN (init);
-      if (TREE_CODE (TREE_PURPOSE (init)) == FIELD_DECL)
-       {
-         TREE_CHAIN (init) = member_init_list;
-         member_init_list = init;
-
-         /* We're running through the initializers from right to left
-            as we process them here.  So, if we see a data member
-            initializer after we see a base initializer, that
-            actually means that the base initializer preceded the
-            data member initializer.  */
-         if (warn_reorder && last_base_warned_about != base_init_list)
-           {
-             tree base;
-
-             for (base = base_init_list; 
-                  base != last_base_warned_about; 
-                  base = TREE_CHAIN (base))
-               {
-                 warning ("base initializer for `%T'",
-                             TREE_PURPOSE (base));
-                 warning ("   will be re-ordered to precede member initializations");
-               }
-
-             last_base_warned_about = base_init_list;
-           }
-       }
-      else
-       {
-         TREE_CHAIN (init) = base_init_list;
-         base_init_list = init;
-       }
-    }
+  /* Reorder the MEM_INITS so that they are in the order they appeared
+     in the source program.  */
+  mem_inits = nreverse (mem_inits);
 
   if (processing_template_decl)
-    add_stmt (build_min_nt (CTOR_INITIALIZER,
-                           member_init_list, base_init_list));
+    add_stmt (build_min_nt (CTOR_INITIALIZER, mem_inits));
   else
-    emit_base_init (member_init_list, base_init_list);
+    emit_mem_initializers (mem_inits);
 }
 
 /* Returns the stack of SCOPE_STMTs for the current function.  */
index d7459cf97abac1e55eb5eb3a11d41f1ab7e76d76..412533c7d300f20a1b477e20ddfe3d67c83fa813 100644 (file)
@@ -1,3 +1,11 @@
+2002-10-02  Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/7188.
+       * g++.dg/template/meminit1.C: New test.
+       * g++.dg/warn/Wreorder-1.C: Likewise.
+       * g++.old-deja/g++.mike/warn3.C: Tweak.
+       * lib/prune.exp: Ingore "in copy constructor".
+
 2002-10-02  Andreas Jaeger  <aj@suse.de>
 
        * gcc.dg/20020919-1.c, gcc.dg/inline-2.c, gcc.dg/980211-1.c,
diff --git a/gcc/testsuite/g++.dg/template/meminit1.C b/gcc/testsuite/g++.dg/template/meminit1.C
new file mode 100644 (file)
index 0000000..90b0d7d
--- /dev/null
@@ -0,0 +1,7 @@
+template <class T >
+struct S
+{
+  S() : S() {} // { dg-error "base" }
+};
+
+S<int> s; // { dg-error "instantiated" }
diff --git a/gcc/testsuite/g++.dg/warn/Wreorder-1.C b/gcc/testsuite/g++.dg/warn/Wreorder-1.C
new file mode 100644 (file)
index 0000000..bd8113a
--- /dev/null
@@ -0,0 +1,14 @@
+// { dg-options "-Wreorder -W" }
+
+struct S {
+  S ();
+};
+
+struct T {
+  T ();
+};
+
+struct U : virtual public S, virtual public T {
+  U () : T (), S () {}     // { dg-warning "" }
+  U (const U&) : S () {}   // { dg-warning "copy" }
+};
index 7adc8a1c37f161fbbce478b7c08958b403fefc0f..d5ed38371d7ede8f07d4f3a52b4340b084bfa2bc 100644 (file)
@@ -7,6 +7,6 @@ public:
 };
 
 class D : public B {
-  int member;
+  int member;                          // WARNING - reordered
   D() : member(0), B(member) { }       // WARNING - reordered
 };
index 38b24e0ca426c4d1e336aeefbf3ba727db3efd22..5a3609493c8c123d3261c12a943dc81c76ce4129 100644 (file)
@@ -1,4 +1,4 @@
-#   Copyright (C) 1997, 1999, 2000 Free Software Foundation, Inc.
+#   Copyright (C) 1997, 1999, 2000, 2002 Free Software Foundation, Inc.
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@
 proc prune_gcc_output { text } {
     #send_user "Before:$text\n"
 
-    regsub -all "(^|\n)\[^\n\]*: In (function|member|method|constructor|instantiation|program|subroutine|block-data) \[^\n\]*" $text "" text
+    regsub -all "(^|\n)\[^\n\]*: In (function|member|method|(copy )?constructor|instantiation|program|subroutine|block-data) \[^\n\]*" $text "" text
     regsub -all "(^|\n)\[^\n\]*: At (top level|global scope):\[^\n\]*" $text "" text
     regsub -all "(^|\n)collect2: ld returned \[^\n\]*" $text "" text
     regsub -all "(^|\n)Please submit.*instructions\[^\n\]*" $text "" text