PR c++/19733
authormmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 9 Feb 2005 02:53:41 +0000 (02:53 +0000)
committermmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 9 Feb 2005 02:53:41 +0000 (02:53 +0000)
* class.c (add_method): Don't set TYPE_HAS_DESTRUCTOR.
(check_bases): Give warnings about a base class with a
non-virtual destructor, even if it is implicit.
(finish_struct_bits): Don't copy TYPE_HAS_DESTRUCTOR.
(maybe_warn_about_overly_private_class): Don't use
TYPE_HAS_DESTRUCTOR.
(finish_struct_methods): Don't set TYPE_HAS_DESTRUCTOR.
(check_for_override): Give it external linkage.
(add_implicitly_declared_members): Generate destructors lazily.
(check_field_decls): Use TYPE_HAS_NONTRIVIAL_DESTRUCTOR, not
TYPE_HAS_DESTRUCTOR.
(check_bases_and_members): Call check_methods before
check_field_decls.
(check_bases_and_members): Use TYPE_HAS_NONTRIVIAL_DESTRUCTOR, not
TYPE_HAS_DESTRUCTOR.
(finish_struct_1): Do not use TYPE_HAS_DESTRUCTOR.
* cp-tree.def (PSEUDO_DTOR_EXPR): Document.
* cp-tree.h (TYPE_HAS_DESTRUCTOR): Remove.
(lang_type_class): Add lazy_destructor.
(CLASSTYPE_LAZY_DESTRUCTOR): New macro.
(CLASSTYPE_DESTRUCTORS): Robustify.
(TYPE_HAS_DESTRUCTOR): Remove.
(check_for_override): Declare.
(build_vbase_delete): Remove.
* cvt.c (convert_to_void): Issue errors about pseudo-destructor
expressions.
* decl.c (cxx_maybe_build_cleanup): Remove dead code.
* except.c (dtor_nothrow): Lazily create destructors if necessary.
(build_throw): Use TYPE_HAS_NONTRIVIAL_DESTRUCTOR.
* init.c (build_delete): Lazily create destructors, if necessary.
(build_vbase_delete): Remove.
* method.c (locate_dtor): Simplify.
(implicitly_declare_fn): Add support for destructors.
* parser.c (cp_parser_lookup_name): Lazily create destructors, if
necessary.
* pt.c (check_explicit_specialization): Don't use
TYPE_HAS_DESTRUCTOR.
(instantiate_class_template): Likewise.
* ptree.c (cxx_print_type): Don't print TYPE_HAS_DESTRUCTOR.
* rtti.c (emit_support_tinfos): Robustify.
* search.c (lookup_fnfields_1): Lazily create destructors.
* typeck.c (build_class_member_access_expr): Remove
PSEUDO_DTOR_EXPR handling.
(lookup_destructor): Likewise.

PR c++/19733
* g++.dg/parse/crash23.C: New test.
* g++.dg/warn/Weff1.C: New test.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@94759 138bc75d-0d04-0410-961f-82ee72b054a4

18 files changed:
gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.def
gcc/cp/cp-tree.h
gcc/cp/cvt.c
gcc/cp/decl.c
gcc/cp/except.c
gcc/cp/init.c
gcc/cp/method.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/ptree.c
gcc/cp/rtti.c
gcc/cp/search.c
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/parse/crash23.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Weff1.C [new file with mode: 0644]

index 39e2766..dc5609f 100644 (file)
@@ -1,3 +1,51 @@
+2005-02-08  Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/19733
+       * class.c (add_method): Don't set TYPE_HAS_DESTRUCTOR.
+       (check_bases): Give warnings about a base class with a
+       non-virtual destructor, even if it is implicit.
+       (finish_struct_bits): Don't copy TYPE_HAS_DESTRUCTOR.
+       (maybe_warn_about_overly_private_class): Don't use
+       TYPE_HAS_DESTRUCTOR.
+       (finish_struct_methods): Don't set TYPE_HAS_DESTRUCTOR.
+       (check_for_override): Give it external linkage.
+       (add_implicitly_declared_members): Generate destructors lazily.
+       (check_field_decls): Use TYPE_HAS_NONTRIVIAL_DESTRUCTOR, not
+       TYPE_HAS_DESTRUCTOR.
+       (check_bases_and_members): Call check_methods before
+       check_field_decls.
+       (check_bases_and_members): Use TYPE_HAS_NONTRIVIAL_DESTRUCTOR, not
+       TYPE_HAS_DESTRUCTOR.
+       (finish_struct_1): Do not use TYPE_HAS_DESTRUCTOR.
+       * cp-tree.def (PSEUDO_DTOR_EXPR): Document.
+       * cp-tree.h (TYPE_HAS_DESTRUCTOR): Remove.
+       (lang_type_class): Add lazy_destructor.
+       (CLASSTYPE_LAZY_DESTRUCTOR): New macro.
+       (CLASSTYPE_DESTRUCTORS): Robustify.
+       (TYPE_HAS_DESTRUCTOR): Remove.
+       (check_for_override): Declare.
+       (build_vbase_delete): Remove.
+       * cvt.c (convert_to_void): Issue errors about pseudo-destructor
+       expressions.
+       * decl.c (cxx_maybe_build_cleanup): Remove dead code.
+       * except.c (dtor_nothrow): Lazily create destructors if necessary.
+       (build_throw): Use TYPE_HAS_NONTRIVIAL_DESTRUCTOR.
+       * init.c (build_delete): Lazily create destructors, if necessary.
+       (build_vbase_delete): Remove.
+       * method.c (locate_dtor): Simplify.
+       (implicitly_declare_fn): Add support for destructors.
+       * parser.c (cp_parser_lookup_name): Lazily create destructors, if
+       necessary.
+       * pt.c (check_explicit_specialization): Don't use
+       TYPE_HAS_DESTRUCTOR.
+       (instantiate_class_template): Likewise.
+       * ptree.c (cxx_print_type): Don't print TYPE_HAS_DESTRUCTOR.
+       * rtti.c (emit_support_tinfos): Robustify.
+       * search.c (lookup_fnfields_1): Lazily create destructors.
+       * typeck.c (build_class_member_access_expr): Remove
+       PSEUDO_DTOR_EXPR handling.
+       (lookup_destructor): Likewise.
+
 2005-02-08  Kazu Hirata  <kazu@cs.umass.edu>
 
        * cxx-pretty-print.c, cxx-pretty-print.h, decl.h: Update
index 84db9e2..bfb9ee1 100644 (file)
@@ -116,7 +116,6 @@ static void modify_vtable_entry (tree, tree, tree, tree, tree *);
 static void finish_struct_bits (tree);
 static int alter_access (tree, tree, tree);
 static void handle_using_decl (tree, tree);
-static void check_for_override (tree, tree);
 static tree dfs_modify_vtables (tree, void *);
 static tree modify_all_vtables (tree, tree);
 static void determine_primary_bases (tree);
@@ -893,13 +892,16 @@ add_method (tree type, tree method)
   else if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (method))
     {
       slot = CLASSTYPE_DESTRUCTOR_SLOT;
-      TYPE_HAS_DESTRUCTOR (type) = 1;
       
       if (TYPE_FOR_JAVA (type))
-       error (DECL_ARTIFICIAL (method)
-              ? "Java class %qT cannot have an implicit non-trivial destructor"
-              : "Java class %qT cannot have a destructor",
-              DECL_CONTEXT (method));
+       {
+         if (!DECL_ARTIFICIAL (method))
+           error ("Java class %qT cannot have a destructor", type);
+         else if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
+           error ("Java class %qT cannot have an implicit non-trivial "
+                  "destructor",
+                  type);
+       }
     }
   else
     {
@@ -1203,8 +1205,7 @@ check_bases (tree t,
       /* Effective C++ rule 14.  We only need to check TYPE_POLYMORPHIC_P
         here because the case of virtual functions but non-virtual
         dtor is handled in finish_struct_1.  */
-      if (warn_ecpp && ! TYPE_POLYMORPHIC_P (basetype)
-         && TYPE_HAS_DESTRUCTOR (basetype))
+      if (warn_ecpp && ! TYPE_POLYMORPHIC_P (basetype))
        warning ("base class %q#T has a non-virtual destructor", basetype);
 
       /* If the base class doesn't have copy constructors or
@@ -1406,7 +1407,6 @@ 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_DESTRUCTOR (variants) = TYPE_HAS_DESTRUCTOR (t);
       TYPE_NEEDS_CONSTRUCTING (variants) = TYPE_NEEDS_CONSTRUCTING (t);
       TYPE_HAS_NONTRIVIAL_DESTRUCTOR (variants) 
        = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t);
@@ -1540,8 +1540,8 @@ maybe_warn_about_overly_private_class (tree t)
   /* Even if some of the member functions are non-private, the class
      won't be useful for much if all the constructors or destructors
      are private: such an object can never be created or destroyed.  */
-  if (TYPE_HAS_DESTRUCTOR (t)
-      && TREE_PRIVATE (CLASSTYPE_DESTRUCTORS (t)))
+  fn = CLASSTYPE_DESTRUCTORS (t);
+  if (fn && TREE_PRIVATE (fn))
     {
       warning ("%q#T only defines a private destructor and has no friends",
               t);
@@ -1693,11 +1693,6 @@ finish_struct_methods (tree t)
        fn_fields = TREE_CHAIN (fn_fields))
     DECL_IN_AGGR_P (fn_fields) = 0;
 
-  if (TYPE_HAS_DESTRUCTOR (t) && !CLASSTYPE_DESTRUCTORS (t))
-    /* We thought there was a destructor, but there wasn't.  Some
-       parse errors cause this anomalous situation.  */
-    TYPE_HAS_DESTRUCTOR (t) = 0;
-    
   /* Issue warnings about private constructors and such.  If there are
      no methods, then some public defaults are generated.  */
   maybe_warn_about_overly_private_class (t);
@@ -2284,7 +2279,7 @@ get_basefndecls (tree name, tree t)
    a method declared virtual in the base class, then
    mark this field as being virtual as well.  */
 
-static void
+void
 check_for_override (tree decl, tree ctype)
 {
   if (TREE_CODE (decl) == TEMPLATE_DECL)
@@ -2465,8 +2460,7 @@ maybe_add_class_template_decl_list (tree type, tree t, int friend_p)
    CANT_HAVE_CONST_ASSIGNMENT are nonzero if, for whatever reason, the
    class cannot have a default constructor, copy constructor taking a
    const reference argument, or an assignment operator taking a const
-   reference, respectively.  If a virtual destructor is created, its
-   DECL is returned; otherwise the return value is NULL_TREE.  */
+   reference, respectively.  */
 
 static void
 add_implicitly_declared_members (tree t, 
@@ -2474,26 +2468,53 @@ add_implicitly_declared_members (tree t,
                                 int cant_have_const_cctor,
                                 int cant_have_const_assignment)
 {
-  tree default_fn;
-  tree implicit_fns = NULL_TREE;
-  tree virtual_dtor = NULL_TREE;
-  tree *f;
-
   /* Destructor.  */
-  if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) && !TYPE_HAS_DESTRUCTOR (t))
+  if (!CLASSTYPE_DESTRUCTORS (t))
     {
-      default_fn = implicitly_declare_fn (sfk_destructor, t, /*const_p=*/0);
-      check_for_override (default_fn, t);
+      /* In general, we create destructors lazily.  */
+      CLASSTYPE_LAZY_DESTRUCTOR (t) = 1;
+      /* However, if the implicit destructor is non-trivial
+        destructor, we sometimes have to create it at this point.  */
+      if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t))
+       {
+         bool lazy_p = true;
 
-      TREE_CHAIN (default_fn) = implicit_fns;
-      implicit_fns = default_fn;
-      
-      if (DECL_VINDEX (default_fn))
-       virtual_dtor = default_fn;
+         if (TYPE_FOR_JAVA (t))
+           /* If this a Java class, any non-trivial destructor is
+              invalid, even if compiler-generated.  Therefore, if the
+              destructor is non-trivial we create it now.  */
+           lazy_p = false;
+         else
+           {
+             tree binfo;
+             tree base_binfo;
+             int ix;
+
+             /* If the implicit destructor will be virtual, then we must
+                generate it now because (unfortunately) we do not
+                generate virtual tables lazily.  */
+             binfo = TYPE_BINFO (t);
+             for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++)
+               {
+                 tree base_type;
+                 tree dtor;
+
+                 base_type = BINFO_TYPE (base_binfo);
+                 dtor = CLASSTYPE_DESTRUCTORS (base_type);
+                 if (dtor && DECL_VIRTUAL_P (dtor))
+                   {
+                     lazy_p = false;
+                     break;
+                   }
+               }
+           }
+
+         /* If we can't get away with being lazy, generate the destructor
+            now.  */ 
+         if (!lazy_p)
+           lazily_declare_fn (sfk_destructor, t);
+       }
     }
-  else
-    /* Any non-implicit destructor is non-trivial.  */
-    TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) |= TYPE_HAS_DESTRUCTOR (t);
 
   /* Default constructor.  */
   if (! TYPE_HAS_CONSTRUCTOR (t) && ! cant_have_default_ctor)
@@ -2521,29 +2542,6 @@ add_implicitly_declared_members (tree t,
       TYPE_HAS_CONST_ASSIGN_REF (t) = !cant_have_const_assignment;
       CLASSTYPE_LAZY_ASSIGNMENT_OP (t) = 1;
     }
-  
-  /* Now, hook all of the new functions on to TYPE_METHODS,
-     and add them to the CLASSTYPE_METHOD_VEC.  */
-  for (f = &implicit_fns; *f; f = &TREE_CHAIN (*f))
-    {
-      add_method (t, *f);
-      maybe_add_class_template_decl_list (current_class_type, *f, /*friend_p=*/0);
-    }
-  if (abi_version_at_least (2))
-    /* G++ 3.2 put the implicit destructor at the *beginning* of the
-       list, which cause the destructor to be emitted in an incorrect
-       location in the vtable.  */
-    TYPE_METHODS (t) = chainon (TYPE_METHODS (t), implicit_fns);
-  else
-    {
-      if (warn_abi && virtual_dtor)
-       warning ("vtable layout for class %qT may not be ABI-compliant "
-                "and may change in a future version of GCC due to implicit "
-                "virtual destructor",
-                t);
-      *f = TYPE_METHODS (t);
-      TYPE_METHODS (t) = implicit_fns;
-    }
 }
 
 /* Subroutine of finish_struct_1.  Recursively count the number of fields
@@ -3012,7 +3010,7 @@ check_field_decls (tree t, tree *access_decls,
     if (warn_ecpp
        && has_pointers
        && TYPE_HAS_CONSTRUCTOR (t)
-       && TYPE_HAS_DESTRUCTOR (t)
+       && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
        && !(TYPE_HAS_INIT_REF (t) && TYPE_HAS_ASSIGN_REF (t)))
     {
       warning ("%q#T has pointer data members", t);
@@ -3660,6 +3658,9 @@ check_methods (tree t)
          if (DECL_PURE_VIRTUAL_P (x))
            VEC_safe_push (tree, CLASSTYPE_PURE_VIRTUALS (t), x);
        }
+      /* All user-declared destructors are non-trivial.  */
+      if (DECL_DESTRUCTOR_P (x))
+       TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = 1;
     }
 }
 
@@ -4034,15 +4035,18 @@ check_bases_and_members (tree t)
   check_bases (t, &cant_have_default_ctor, &cant_have_const_ctor,
               &no_const_asn_ref);
 
-  /* Check all the data member declarations.  */
+  /* Check all the method declarations.  */
+  check_methods (t);
+
+  /* Check all the data member declarations.  We cannot call
+     check_field_decls until we have called check_bases check_methods,
+     as check_field_decls depends on TYPE_HAS_NONTRIVIAL_DESTRUCTOR
+     being set appropriately.  */
   check_field_decls (t, &access_decls,
                     &cant_have_default_ctor,
                     &cant_have_const_ctor,
                     &no_const_asn_ref);
 
-  /* Check all the method declarations.  */
-  check_methods (t);
-
   /* A nearly-empty class has to be vptr-containing; a nearly empty
      class contains just a vptr.  */
   if (!TYPE_CONTAINS_VPTR_P (t))
@@ -4057,7 +4061,8 @@ check_bases_and_members (tree t)
   CLASSTYPE_NON_AGGREGATE (t)
     |= (TYPE_HAS_CONSTRUCTOR (t) || TYPE_POLYMORPHIC_P (t));
   CLASSTYPE_NON_POD_P (t)
-    |= (CLASSTYPE_NON_AGGREGATE (t) || TYPE_HAS_DESTRUCTOR (t) 
+    |= (CLASSTYPE_NON_AGGREGATE (t) 
+       || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
        || TYPE_HAS_ASSIGN_REF (t));
   TYPE_HAS_COMPLEX_ASSIGN_REF (t)
     |= TYPE_HAS_ASSIGN_REF (t) || TYPE_CONTAINS_VPTR_P (t);
@@ -5007,17 +5012,22 @@ finish_struct_1 (tree t)
   /* Build the VTT for T.  */
   build_vtt (t);
 
-  if (warn_nonvdtor && TYPE_POLYMORPHIC_P (t) && TYPE_HAS_DESTRUCTOR (t)
-      && !DECL_VINDEX (CLASSTYPE_DESTRUCTORS (t)))
-
-    {
-      tree dtor = CLASSTYPE_DESTRUCTORS (t);
-
-      /* Warn only if the dtor is non-private or the class has friends */
-      if (!TREE_PRIVATE (dtor) ||
-         (CLASSTYPE_FRIEND_CLASSES (t) ||
-          DECL_FRIENDLIST (TYPE_MAIN_DECL (t))))
-       warning ("%q#T has virtual functions but non-virtual destructor", t);
+  if (warn_nonvdtor && TYPE_POLYMORPHIC_P (t))
+    {
+      tree dtor;
+
+      dtor = CLASSTYPE_DESTRUCTORS (t);
+      /* Warn only if the dtor is non-private or the class has
+        friends.  */
+      if (/* An implicitly declared destructor is always public.  And,
+            if it were virtual, we would have created it by now.  */
+         !dtor
+         || (!DECL_VINDEX (dtor)
+             && (!TREE_PRIVATE (dtor) 
+                 || CLASSTYPE_FRIEND_CLASSES (t) 
+                 || DECL_FRIENDLIST (TYPE_MAIN_DECL (t)))))
+       warning ("%q#T has virtual functions but non-virtual destructor", 
+                t);
     }
 
   complete_vars (t);
index 74f0d37..bc606db 100644 (file)
@@ -222,6 +222,18 @@ DEFTREECODE (TEMPLATE_ID_EXPR, "template_id_expr", tcc_expression, 2)
    the original name, and the parameter is the FUNCTION_DECL.  */
 DEFTREECODE (OVERLOAD, "overload", tcc_exceptional, 0)
 
+/* A pseudo-destructor, of the form "OBJECT.~DESTRUCTOR" or
+   "OBJECT.SCOPE::~DESTRUCTOR.  The first operand is the OBJECT.  The
+   second operand (if non-NULL) is the SCOPE.  The third operand is
+   the TYPE node corresponding to the DESTRUCTOR.  The type of the
+   first operand will always be a scalar type. 
+
+   The type of a PSEUDO_DTOR_EXPR is always "void", even though it can
+   be used as if it were a zero-argument function.  We handle the
+   function-call case specially, and giving it "void" type prevents it
+   being used in expressions in ways that are not permitted.  */  
+DEFTREECODE (PSEUDO_DTOR_EXPR, "pseudo_dtor_expr", tcc_expression, 3)
+
 /* A whole bunch of tree codes for the initial, superficial parsing of
    templates.  */
 DEFTREECODE (MODOP_EXPR, "modop_expr", tcc_expression, 3)
@@ -232,7 +244,6 @@ DEFTREECODE (STATIC_CAST_EXPR, "static_cast_expr", tcc_unary, 1)
 DEFTREECODE (DYNAMIC_CAST_EXPR, "dynamic_cast_expr", tcc_unary, 1)
 DEFTREECODE (DOTSTAR_EXPR, "dotstar_expr", tcc_expression, 2)
 DEFTREECODE (TYPEID_EXPR, "typeid_expr", tcc_expression, 1)
-DEFTREECODE (PSEUDO_DTOR_EXPR, "pseudo_dtor_expr", tcc_expression, 3)
 
 /* A placeholder for an expression that is not type-dependent, but
    does occur in a template.  When an expression that is not
index 58e0fa8..0b4959b 100644 (file)
@@ -80,7 +80,7 @@ struct diagnostic_context;
    Usage of TYPE_LANG_FLAG_?:
    0: TYPE_DEPENDENT_P
    1: TYPE_HAS_CONSTRUCTOR.
-   2: TYPE_HAS_DESTRUCTOR.
+   2: Unused
    3: TYPE_FOR_JAVA.
    4: TYPE_HAS_NONTRIVIAL_DESTRUCTOR
    5: IS_AGGR_TYPE.
@@ -1035,8 +1035,9 @@ struct lang_type_class GTY(())
   unsigned lazy_default_ctor : 1;
   unsigned lazy_copy_ctor : 1;
   unsigned lazy_assignment_op : 1;
+  unsigned lazy_destructor : 1;
+
   unsigned has_const_init_ref : 1;
-  
   unsigned has_complex_init_ref : 1;
   unsigned has_complex_assign_ref : 1;
   unsigned non_aggregate : 1;
@@ -1049,7 +1050,7 @@ struct lang_type_class GTY(())
   /* There are some bits left to fill out a 32-bit word.  Keep track
      of this by updating the size of this bitfield whenever you add or
      remove a flag.  */
-  unsigned dummy : 12;
+  unsigned dummy : 11;
 
   tree primary_base;
   VEC (tree_pair_s) *vcall_indices;
@@ -1153,6 +1154,11 @@ struct lang_type GTY(())
 #define CLASSTYPE_LAZY_ASSIGNMENT_OP(NODE) \
   (LANG_TYPE_CLASS_CHECK (NODE)->lazy_assignment_op)
 
+/* Nonzero means that NODE (a class type) has a destructor -- but that
+   it has not yet been declared.  */
+#define CLASSTYPE_LAZY_DESTRUCTOR(NODE) \
+  (LANG_TYPE_CLASS_CHECK (NODE)->lazy_destructor)
 /* Nonzero means that this _CLASSTYPE node overloads operator=(X&).  */
 #define TYPE_HAS_ASSIGN_REF(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->has_assign_ref)
 
@@ -1236,9 +1242,13 @@ struct lang_type GTY(())
   (VEC_index (tree, CLASSTYPE_METHOD_VEC (NODE), CLASSTYPE_CONSTRUCTOR_SLOT))
 
 /* A FUNCTION_DECL for the destructor for NODE.  These are the
-   destructors that take an in-charge parameter.  */
+   destructors that take an in-charge parameter.  If
+   CLASSTYPE_LAZY_DESTRUCTOR is true, then this entry will be NULL
+   until the destructor is created with lazily_declare_fn.  */
 #define CLASSTYPE_DESTRUCTORS(NODE) \
-  (VEC_index (tree, CLASSTYPE_METHOD_VEC (NODE), CLASSTYPE_DESTRUCTOR_SLOT))
+  (CLASSTYPE_METHOD_VEC (NODE)                                               \
+   ? VEC_index (tree, CLASSTYPE_METHOD_VEC (NODE), CLASSTYPE_DESTRUCTOR_SLOT) \
+   : NULL_TREE)
 
 /* A dictionary of the nested user-defined-types (class-types, or enums)
    found within this class.  This table includes nested member class
@@ -2412,9 +2422,6 @@ struct lang_decl GTY(())
                                   && CONSTRUCTOR_ELTS (NODE) == NULL_TREE \
                                   && ! TREE_HAS_CONSTRUCTOR (NODE))
 
-/* Nonzero for _TYPE means that the _TYPE defines a destructor.  */
-#define TYPE_HAS_DESTRUCTOR(NODE) (TYPE_LANG_FLAG_2 (NODE))
-
 /* Nonzero means that an object of this type can not be initialized using
    an initializer list.  */
 #define CLASSTYPE_NON_AGGREGATE(NODE) \
@@ -3721,6 +3728,7 @@ extern void debug_thunks                  (tree);
 extern tree cp_fold_obj_type_ref               (tree, tree);
 extern void set_linkage_according_to_type       (tree, tree);
 extern void determine_key_method                (tree);
+extern void check_for_override                  (tree, tree);
 
 /* in cvt.c */
 extern tree convert_to_reference (tree, tree, int, int, tree);
@@ -3924,7 +3932,6 @@ extern tree build_vec_init                        (tree, tree, tree, int);
 extern tree build_x_delete                     (tree, int, tree);
 extern tree build_delete                       (tree, tree, special_function_kind, int, int);
 extern void push_base_cleanups                 (void);
-extern tree build_vbase_delete                 (tree, tree);
 extern tree build_vec_delete                   (tree, tree, special_function_kind, int);
 extern tree create_temporary_var                (tree);
 extern void initialize_vtbl_ptrs                (tree);
index 9bc86b2..32dc96d 100644 (file)
@@ -793,6 +793,11 @@ convert_to_void (tree expr, const char *implicit)
     return expr;
   if (invalid_nonstatic_memfn_p (expr))
     return error_mark_node;
+  if (TREE_CODE (expr) == PSEUDO_DTOR_EXPR)
+    {
+      error ("pseudo-destructor is not called");
+      return error_mark_node;
+    }
   if (VOID_TYPE_P (TREE_TYPE (expr)))
     return expr;
   switch (TREE_CODE (expr))
index 9be5adf..4d8059f 100644 (file)
@@ -10929,9 +10929,6 @@ cxx_maybe_build_cleanup (tree decl)
       rval = build_delete (TREE_TYPE (rval), rval,
                           sfk_complete_destructor, flags, 0);
 
-      if (has_vbases && !TYPE_HAS_DESTRUCTOR (type))
-       rval = build_compound_expr (rval, build_vbase_delete (type, decl));
-
       return rval;
     }
   return NULL_TREE;
index 649fab7..44521e3 100644 (file)
@@ -182,9 +182,12 @@ dtor_nothrow (tree type)
   if (type == NULL_TREE)
     return 0;
 
-  if (! TYPE_HAS_DESTRUCTOR (type))
+  if (!CLASS_TYPE_P (type))
     return 1;
 
+  if (CLASSTYPE_LAZY_DESTRUCTOR (type))
+    lazily_declare_fn (sfk_destructor, type);
+
   return TREE_NOTHROW (CLASSTYPE_DESTRUCTORS (type));
 }
 
@@ -709,7 +712,7 @@ build_throw (tree exp)
 
       throw_type = build_eh_type_type (prepare_eh_type (TREE_TYPE (object)));
 
-      if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
+      if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (object)))
        {
          cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
                                     complete_dtor_identifier, 0);
index eb73980..4ad5e62 100644 (file)
@@ -2796,7 +2796,8 @@ build_delete (tree type, tree addr, special_function_kind auto_delete,
       tree do_delete = NULL_TREE;
       tree ifexp;
 
-      gcc_assert (TYPE_HAS_DESTRUCTOR (type));
+      if (CLASSTYPE_LAZY_DESTRUCTOR (type))
+       lazily_declare_fn (sfk_destructor, type);
 
       /* For `::delete x', we must not use the deleting destructor
         since then we would not be sure to get the global `operator
@@ -2935,34 +2936,6 @@ push_base_cleanups (void)
     }
 }
 
-/* For type TYPE, delete the virtual baseclass objects of DECL.  */
-
-tree
-build_vbase_delete (tree type, tree decl)
-{
-  unsigned ix;
-  tree binfo;
-  tree result;
-  VEC (tree) *vbases;
-  tree addr = build_unary_op (ADDR_EXPR, decl, 0);
-
-  gcc_assert (addr != error_mark_node);
-
-  result = convert_to_void (integer_zero_node, NULL);
-  for (vbases = CLASSTYPE_VBASECLASSES (type), ix = 0;
-       VEC_iterate (tree, vbases, ix, binfo); ix++)
-    {
-      tree base_addr = convert_force
-       (build_pointer_type (BINFO_TYPE (binfo)), addr, 0);
-      tree base_delete = build_delete
-       (TREE_TYPE (base_addr), base_addr, sfk_base_destructor,
-        LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0);
-      
-      result = build_compound_expr (result, base_delete);
-    }
-  return result;
-}
-
 /* Build a C++ vector delete expression.
    MAXINDEX is the number of elements to be deleted.
    ELT_SIZE is the nominal size of each element in the vector.
index 09317a7..fadbf39 100644 (file)
@@ -823,9 +823,7 @@ synthesize_exception_spec (tree type, tree (*extractor) (tree, void*),
 static tree
 locate_dtor (tree type, void *client ATTRIBUTE_UNUSED)
 {
-  return (CLASSTYPE_METHOD_VEC (type) 
-         ? CLASSTYPE_DESTRUCTORS (type) 
-         : NULL_TREE);
+  return CLASSTYPE_DESTRUCTORS (type);
 }
 
 /* Locate the default ctor of TYPE.  */
@@ -1035,7 +1033,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
   DECL_DECLARED_INLINE_P (fn) = 1;
   DECL_INLINE (fn) = 1;
   gcc_assert (!TREE_USED (fn));
-  
+
   return fn;
 }
 
@@ -1060,24 +1058,46 @@ lazily_declare_fn (special_function_kind sfk, tree type)
     const_p = false;
   /* Declare the function.  */
   fn = implicitly_declare_fn (sfk, type, const_p);
+  /* A destructor may be virtual.  */
+  if (sfk == sfk_destructor)
+    check_for_override (fn, type);
   /* Add it to CLASSTYPE_METHOD_VEC.  */
   add_method (type, fn);
   /* Add it to TYPE_METHODS.  */
-  TREE_CHAIN (fn) = TYPE_METHODS (type);
-  TYPE_METHODS (type) = fn;
+  if (sfk == sfk_destructor 
+      && DECL_VIRTUAL_P (fn)
+      && abi_version_at_least (2))
+    /* The ABI requires that a virtual destructor go at the end of the
+       vtable.  */
+    TYPE_METHODS (type) = chainon (TYPE_METHODS (type), fn);
+  else
+    {
+      /* G++ 3.2 put the implicit destructor at the *beginning* of the
+        TYPE_METHODS list, which cause the destructor to be emitted
+        in an incorrect location in the vtable.  */ 
+      if (warn_abi && DECL_VIRTUAL_P (fn))
+       warning ("vtable layout for class %qT may not be ABI-compliant"
+                "and may change in a future version of GCC due to "
+                "implicit virtual destructor",
+                type);
+      TREE_CHAIN (fn) = TYPE_METHODS (type);
+      TYPE_METHODS (type) = fn;
+    }
   maybe_add_class_template_decl_list (type, fn, /*friend_p=*/0);
-  if (sfk == sfk_constructor || sfk == sfk_copy_constructor)
+  if (sfk == sfk_assignment_operator)
+    CLASSTYPE_LAZY_ASSIGNMENT_OP (type) = 0;
+  else
     {
       /* Remember that the function has been created.  */
       if (sfk == sfk_constructor)
        CLASSTYPE_LAZY_DEFAULT_CTOR (type) = 0;
-      else
+      else if (sfk == sfk_copy_constructor)
        CLASSTYPE_LAZY_COPY_CTOR (type) = 0;
+      else if (sfk == sfk_destructor)
+       CLASSTYPE_LAZY_DESTRUCTOR (type) = 0;
       /* Create appropriate clones.  */
       clone_function_decl (fn, /*update_method_vec=*/true);
     }
-  else if (sfk == sfk_assignment_operator)
-    CLASSTYPE_LAZY_ASSIGNMENT_OP (type) = 0;
 
   return fn;
 }
index 54e330f..6e79753 100644 (file)
@@ -14252,6 +14252,8 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
       /* If that's not a class type, there is no destructor.  */
       if (!type || !CLASS_TYPE_P (type))
        return error_mark_node;
+      if (CLASSTYPE_LAZY_DESTRUCTOR (type))
+       lazily_declare_fn (sfk_destructor, type);
       if (!CLASSTYPE_DESTRUCTORS (type))
          return error_mark_node;
       /* If it was a class type, return the destructor.  */
index d0cd229..dbe560b 100644 (file)
@@ -1932,7 +1932,7 @@ check_explicit_specialization (tree declarator,
              int is_constructor = DECL_CONSTRUCTOR_P (decl);
              
              if (is_constructor ? !TYPE_HAS_CONSTRUCTOR (ctype)
-                 : !TYPE_HAS_DESTRUCTOR (ctype))
+                 : !CLASSTYPE_DESTRUCTORS (ctype))
                {
                  /* From [temp.expl.spec]:
                       
@@ -5541,7 +5541,6 @@ instantiate_class_template (tree type)
   input_location = DECL_SOURCE_LOCATION (TYPE_NAME (pattern));
 
   TYPE_HAS_CONSTRUCTOR (type) = TYPE_HAS_CONSTRUCTOR (pattern);
-  TYPE_HAS_DESTRUCTOR (type) = TYPE_HAS_DESTRUCTOR (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 3168241..d33ad9f 100644 (file)
@@ -100,8 +100,6 @@ cxx_print_type (FILE *file, tree node, int indent)
     fputs ( "needs-constructor", file);
   if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (node))
     fputs (" needs-destructor", file);
-  if (TYPE_HAS_DESTRUCTOR (node))
-    fputs (" ~X()", file);
   if (TYPE_HAS_DEFAULT_CONSTRUCTOR (node))
     fputs (" X()", file);
   if (TYPE_HAS_CONVERSION (node))
index 2d0569b..a08a3ee 100644 (file)
@@ -1342,7 +1342,7 @@ emit_support_tinfos (void)
   if (!COMPLETE_TYPE_P (bltn_type))
     return;
   dtor = CLASSTYPE_DESTRUCTORS (bltn_type);
-  if (DECL_EXTERNAL (dtor))
+  if (!dtor || DECL_EXTERNAL (dtor))
     return;
   doing_runtime = 1;
   for (ix = 0; fundamentals[ix]; ix++)
index 8d5ae65..a0cb0ff 100644 (file)
@@ -1367,6 +1367,12 @@ lookup_fnfields_1 (tree type, tree name)
       else if (name == ansi_assopname(NOP_EXPR)
               && CLASSTYPE_LAZY_ASSIGNMENT_OP (type))
        lazily_declare_fn (sfk_assignment_operator, type);
+      else if ((name == dtor_identifier
+               || name == base_dtor_identifier
+               || name == complete_dtor_identifier
+               || name == deleting_dtor_identifier)
+              && CLASSTYPE_LAZY_DESTRUCTOR (type))
+       lazily_declare_fn (sfk_destructor, type);
     }
 
   method_vec = CLASSTYPE_METHOD_VEC (type);
index b35ae97..2badcc2 100644 (file)
@@ -1577,9 +1577,6 @@ build_class_member_access_expr (tree object, tree member,
   if (object == error_mark_node || member == error_mark_node)
     return error_mark_node;
 
-  if (TREE_CODE (member) == PSEUDO_DTOR_EXPR)
-    return member;
-
   gcc_assert (DECL_P (member) || BASELINK_P (member));
 
   /* [expr.ref]
@@ -1822,9 +1819,6 @@ lookup_destructor (tree object, tree scope, tree dtor_name)
             TYPE_MAIN_VARIANT (object_type), dtor_type);
       return error_mark_node;
     }
-  if (!TYPE_HAS_DESTRUCTOR (dtor_type))
-    return build3 (PSEUDO_DTOR_EXPR, void_type_node, object, scope,
-                  dtor_type);
   expr = lookup_member (dtor_type, complete_dtor_identifier,
                        /*protect=*/1, /*want_type=*/false);
   expr = (adjust_result_of_qualified_name_lookup
index 180e1ed..0067f19 100644 (file)
@@ -1,3 +1,9 @@
+2005-02-08  Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/19733
+       * g++.dg/parse/crash23.C: New test.
+       * g++.dg/warn/Weff1.C: New test.
+
 2005-02-09  Joseph S. Myers  <joseph@codesourcery.com>
 
        * gcc.dg/20050209-1.c: New test.
diff --git a/gcc/testsuite/g++.dg/parse/crash23.C b/gcc/testsuite/g++.dg/parse/crash23.C
new file mode 100644 (file)
index 0000000..19ad70a
--- /dev/null
@@ -0,0 +1,12 @@
+// PR c++/19733
+
+struct A {};
+typedef int I;
+void foo() {
+  A().~A; // { dg-error "" }
+  A().A::~A; // { dg-error "" }
+  (int().I::~I, 3); // { dg-error "" }
+  int().I::~I; // { dg-error "" }
+}
+
+  
diff --git a/gcc/testsuite/g++.dg/warn/Weff1.C b/gcc/testsuite/g++.dg/warn/Weff1.C
new file mode 100644 (file)
index 0000000..a00dc29
--- /dev/null
@@ -0,0 +1,5 @@
+// { dg-options "-Weffc++" }
+
+struct S {};
+/* Base classes should have virtual destructors.  */
+struct T : public S {}; // { dg-warning "" }