From ed36f1cf5a66a3774386a4b6ac54a360d813654a Mon Sep 17 00:00:00 2001 From: mmitchel Date: Wed, 9 Feb 2005 02:53:41 +0000 Subject: [PATCH] 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. 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 --- gcc/cp/ChangeLog | 48 +++++++++++ gcc/cp/class.c | 160 +++++++++++++++++++---------------- gcc/cp/cp-tree.def | 13 ++- gcc/cp/cp-tree.h | 25 ++++-- gcc/cp/cvt.c | 5 ++ gcc/cp/decl.c | 3 - gcc/cp/except.c | 7 +- gcc/cp/init.c | 31 +------ gcc/cp/method.c | 40 ++++++--- gcc/cp/parser.c | 2 + gcc/cp/pt.c | 3 +- gcc/cp/ptree.c | 2 - gcc/cp/rtti.c | 2 +- gcc/cp/search.c | 6 ++ gcc/cp/typeck.c | 6 -- gcc/testsuite/ChangeLog | 6 ++ gcc/testsuite/g++.dg/parse/crash23.C | 12 +++ gcc/testsuite/g++.dg/warn/Weff1.C | 5 ++ 18 files changed, 236 insertions(+), 140 deletions(-) create mode 100644 gcc/testsuite/g++.dg/parse/crash23.C create mode 100644 gcc/testsuite/g++.dg/warn/Weff1.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 39e2766..dc5609f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,51 @@ +2005-02-08 Mark Mitchell + + 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 * cxx-pretty-print.c, cxx-pretty-print.h, decl.h: Update diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 84db9e2..bfb9ee1 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -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); diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index 74f0d37..bc606db 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -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 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 58e0fa8..0b4959b 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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); diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 9bc86b2..32dc96d 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -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)) diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 9be5adf..4d8059f 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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; diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 649fab7..44521e3 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -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); diff --git a/gcc/cp/init.c b/gcc/cp/init.c index eb73980..4ad5e62 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -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. diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 09317a7..fadbf39 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -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; } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 54e330f..6e79753 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -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. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index d0cd229..dbe560b 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -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); diff --git a/gcc/cp/ptree.c b/gcc/cp/ptree.c index 3168241..d33ad9f 100644 --- a/gcc/cp/ptree.c +++ b/gcc/cp/ptree.c @@ -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)) diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index 2d0569b..a08a3ee 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -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++) diff --git a/gcc/cp/search.c b/gcc/cp/search.c index 8d5ae65..a0cb0ff 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -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); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index b35ae97..2badcc2 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 180e1ed..0067f19 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2005-02-08 Mark Mitchell + + PR c++/19733 + * g++.dg/parse/crash23.C: New test. + * g++.dg/warn/Weff1.C: New test. + 2005-02-09 Joseph S. Myers * 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 index 0000000..19ad70a --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/crash23.C @@ -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 index 0000000..a00dc29 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Weff1.C @@ -0,0 +1,5 @@ +// { dg-options "-Weffc++" } + +struct S {}; +/* Base classes should have virtual destructors. */ +struct T : public S {}; // { dg-warning "" } -- 2.7.4