re PR c++/19733 (ICE on invalid destructor call)

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.

From-SVN: r94759
This commit is contained in:
Mark Mitchell 2005-02-09 02:53:41 +00:00 committed by Mark Mitchell
parent ec2cd8b20c
commit 9f4faeaee1
18 changed files with 234 additions and 138 deletions

View 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> 2005-02-08 Kazu Hirata <kazu@cs.umass.edu>
* cxx-pretty-print.c, cxx-pretty-print.h, decl.h: Update * cxx-pretty-print.c, cxx-pretty-print.h, decl.h: Update

View File

@ -116,7 +116,6 @@ static void modify_vtable_entry (tree, tree, tree, tree, tree *);
static void finish_struct_bits (tree); static void finish_struct_bits (tree);
static int alter_access (tree, tree, tree); static int alter_access (tree, tree, tree);
static void handle_using_decl (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 dfs_modify_vtables (tree, void *);
static tree modify_all_vtables (tree, tree); static tree modify_all_vtables (tree, tree);
static void determine_primary_bases (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)) else if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (method))
{ {
slot = CLASSTYPE_DESTRUCTOR_SLOT; slot = CLASSTYPE_DESTRUCTOR_SLOT;
TYPE_HAS_DESTRUCTOR (type) = 1;
if (TYPE_FOR_JAVA (type)) if (TYPE_FOR_JAVA (type))
error (DECL_ARTIFICIAL (method) {
? "Java class %qT cannot have an implicit non-trivial destructor" if (!DECL_ARTIFICIAL (method))
: "Java class %qT cannot have a destructor", error ("Java class %qT cannot have a destructor", type);
DECL_CONTEXT (method)); else if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
error ("Java class %qT cannot have an implicit non-trivial "
"destructor",
type);
}
} }
else else
{ {
@ -1203,8 +1205,7 @@ check_bases (tree t,
/* Effective C++ rule 14. We only need to check TYPE_POLYMORPHIC_P /* Effective C++ rule 14. We only need to check TYPE_POLYMORPHIC_P
here because the case of virtual functions but non-virtual here because the case of virtual functions but non-virtual
dtor is handled in finish_struct_1. */ dtor is handled in finish_struct_1. */
if (warn_ecpp && ! TYPE_POLYMORPHIC_P (basetype) if (warn_ecpp && ! TYPE_POLYMORPHIC_P (basetype))
&& TYPE_HAS_DESTRUCTOR (basetype))
warning ("base class %q#T has a non-virtual destructor", basetype); warning ("base class %q#T has a non-virtual destructor", basetype);
/* If the base class doesn't have copy constructors or /* 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 /* These fields are in the _TYPE part of the node, not in
the TYPE_LANG_SPECIFIC component, so they are not shared. */ the TYPE_LANG_SPECIFIC component, so they are not shared. */
TYPE_HAS_CONSTRUCTOR (variants) = TYPE_HAS_CONSTRUCTOR (t); 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_NEEDS_CONSTRUCTING (variants) = TYPE_NEEDS_CONSTRUCTING (t);
TYPE_HAS_NONTRIVIAL_DESTRUCTOR (variants) TYPE_HAS_NONTRIVIAL_DESTRUCTOR (variants)
= TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t); = 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 /* Even if some of the member functions are non-private, the class
won't be useful for much if all the constructors or destructors won't be useful for much if all the constructors or destructors
are private: such an object can never be created or destroyed. */ are private: such an object can never be created or destroyed. */
if (TYPE_HAS_DESTRUCTOR (t) fn = CLASSTYPE_DESTRUCTORS (t);
&& TREE_PRIVATE (CLASSTYPE_DESTRUCTORS (t))) if (fn && TREE_PRIVATE (fn))
{ {
warning ("%q#T only defines a private destructor and has no friends", warning ("%q#T only defines a private destructor and has no friends",
t); t);
@ -1693,11 +1693,6 @@ finish_struct_methods (tree t)
fn_fields = TREE_CHAIN (fn_fields)) fn_fields = TREE_CHAIN (fn_fields))
DECL_IN_AGGR_P (fn_fields) = 0; 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 /* Issue warnings about private constructors and such. If there are
no methods, then some public defaults are generated. */ no methods, then some public defaults are generated. */
maybe_warn_about_overly_private_class (t); 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 a method declared virtual in the base class, then
mark this field as being virtual as well. */ mark this field as being virtual as well. */
static void void
check_for_override (tree decl, tree ctype) check_for_override (tree decl, tree ctype)
{ {
if (TREE_CODE (decl) == TEMPLATE_DECL) 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 CANT_HAVE_CONST_ASSIGNMENT are nonzero if, for whatever reason, the
class cannot have a default constructor, copy constructor taking a class cannot have a default constructor, copy constructor taking a
const reference argument, or an assignment operator taking a const const reference argument, or an assignment operator taking a const
reference, respectively. If a virtual destructor is created, its reference, respectively. */
DECL is returned; otherwise the return value is NULL_TREE. */
static void static void
add_implicitly_declared_members (tree t, 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_cctor,
int cant_have_const_assignment) int cant_have_const_assignment)
{ {
tree default_fn;
tree implicit_fns = NULL_TREE;
tree virtual_dtor = NULL_TREE;
tree *f;
/* Destructor. */ /* 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); /* In general, we create destructors lazily. */
check_for_override (default_fn, t); 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; if (TYPE_FOR_JAVA (t))
implicit_fns = default_fn; /* If this a Java class, any non-trivial destructor is
invalid, even if compiler-generated. Therefore, if the
if (DECL_VINDEX (default_fn)) destructor is non-trivial we create it now. */
virtual_dtor = default_fn; 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. */ /* Default constructor. */
if (! TYPE_HAS_CONSTRUCTOR (t) && ! cant_have_default_ctor) 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; TYPE_HAS_CONST_ASSIGN_REF (t) = !cant_have_const_assignment;
CLASSTYPE_LAZY_ASSIGNMENT_OP (t) = 1; 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 /* 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 if (warn_ecpp
&& has_pointers && has_pointers
&& TYPE_HAS_CONSTRUCTOR (t) && TYPE_HAS_CONSTRUCTOR (t)
&& TYPE_HAS_DESTRUCTOR (t) && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
&& !(TYPE_HAS_INIT_REF (t) && TYPE_HAS_ASSIGN_REF (t))) && !(TYPE_HAS_INIT_REF (t) && TYPE_HAS_ASSIGN_REF (t)))
{ {
warning ("%q#T has pointer data members", t); warning ("%q#T has pointer data members", t);
@ -3660,6 +3658,9 @@ check_methods (tree t)
if (DECL_PURE_VIRTUAL_P (x)) if (DECL_PURE_VIRTUAL_P (x))
VEC_safe_push (tree, CLASSTYPE_PURE_VIRTUALS (t), 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, check_bases (t, &cant_have_default_ctor, &cant_have_const_ctor,
&no_const_asn_ref); &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, check_field_decls (t, &access_decls,
&cant_have_default_ctor, &cant_have_default_ctor,
&cant_have_const_ctor, &cant_have_const_ctor,
&no_const_asn_ref); &no_const_asn_ref);
/* Check all the method declarations. */
check_methods (t);
/* A nearly-empty class has to be vptr-containing; a nearly empty /* A nearly-empty class has to be vptr-containing; a nearly empty
class contains just a vptr. */ class contains just a vptr. */
if (!TYPE_CONTAINS_VPTR_P (t)) if (!TYPE_CONTAINS_VPTR_P (t))
@ -4057,7 +4061,8 @@ check_bases_and_members (tree t)
CLASSTYPE_NON_AGGREGATE (t) CLASSTYPE_NON_AGGREGATE (t)
|= (TYPE_HAS_CONSTRUCTOR (t) || TYPE_POLYMORPHIC_P (t)); |= (TYPE_HAS_CONSTRUCTOR (t) || TYPE_POLYMORPHIC_P (t));
CLASSTYPE_NON_POD_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_ASSIGN_REF (t));
TYPE_HAS_COMPLEX_ASSIGN_REF (t) TYPE_HAS_COMPLEX_ASSIGN_REF (t)
|= TYPE_HAS_ASSIGN_REF (t) || TYPE_CONTAINS_VPTR_P (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 the VTT for T. */
build_vtt (t); build_vtt (t);
if (warn_nonvdtor && TYPE_POLYMORPHIC_P (t) && TYPE_HAS_DESTRUCTOR (t) if (warn_nonvdtor && TYPE_POLYMORPHIC_P (t))
&& !DECL_VINDEX (CLASSTYPE_DESTRUCTORS (t)))
{ {
tree dtor = CLASSTYPE_DESTRUCTORS (t); tree dtor;
/* Warn only if the dtor is non-private or the class has friends */ dtor = CLASSTYPE_DESTRUCTORS (t);
if (!TREE_PRIVATE (dtor) || /* Warn only if the dtor is non-private or the class has
(CLASSTYPE_FRIEND_CLASSES (t) || friends. */
DECL_FRIENDLIST (TYPE_MAIN_DECL (t)))) if (/* An implicitly declared destructor is always public. And,
warning ("%q#T has virtual functions but non-virtual destructor", t); 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); complete_vars (t);

View 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. */ the original name, and the parameter is the FUNCTION_DECL. */
DEFTREECODE (OVERLOAD, "overload", tcc_exceptional, 0) 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 /* A whole bunch of tree codes for the initial, superficial parsing of
templates. */ templates. */
DEFTREECODE (MODOP_EXPR, "modop_expr", tcc_expression, 3) 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 (DYNAMIC_CAST_EXPR, "dynamic_cast_expr", tcc_unary, 1)
DEFTREECODE (DOTSTAR_EXPR, "dotstar_expr", tcc_expression, 2) DEFTREECODE (DOTSTAR_EXPR, "dotstar_expr", tcc_expression, 2)
DEFTREECODE (TYPEID_EXPR, "typeid_expr", tcc_expression, 1) 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 /* A placeholder for an expression that is not type-dependent, but
does occur in a template. When an expression that is not does occur in a template. When an expression that is not

View File

@ -80,7 +80,7 @@ struct diagnostic_context;
Usage of TYPE_LANG_FLAG_?: Usage of TYPE_LANG_FLAG_?:
0: TYPE_DEPENDENT_P 0: TYPE_DEPENDENT_P
1: TYPE_HAS_CONSTRUCTOR. 1: TYPE_HAS_CONSTRUCTOR.
2: TYPE_HAS_DESTRUCTOR. 2: Unused
3: TYPE_FOR_JAVA. 3: TYPE_FOR_JAVA.
4: TYPE_HAS_NONTRIVIAL_DESTRUCTOR 4: TYPE_HAS_NONTRIVIAL_DESTRUCTOR
5: IS_AGGR_TYPE. 5: IS_AGGR_TYPE.
@ -1035,8 +1035,9 @@ struct lang_type_class GTY(())
unsigned lazy_default_ctor : 1; unsigned lazy_default_ctor : 1;
unsigned lazy_copy_ctor : 1; unsigned lazy_copy_ctor : 1;
unsigned lazy_assignment_op : 1; unsigned lazy_assignment_op : 1;
unsigned lazy_destructor : 1;
unsigned has_const_init_ref : 1; unsigned has_const_init_ref : 1;
unsigned has_complex_init_ref : 1; unsigned has_complex_init_ref : 1;
unsigned has_complex_assign_ref : 1; unsigned has_complex_assign_ref : 1;
unsigned non_aggregate : 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 /* 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 of this by updating the size of this bitfield whenever you add or
remove a flag. */ remove a flag. */
unsigned dummy : 12; unsigned dummy : 11;
tree primary_base; tree primary_base;
VEC (tree_pair_s) *vcall_indices; VEC (tree_pair_s) *vcall_indices;
@ -1153,6 +1154,11 @@ struct lang_type GTY(())
#define CLASSTYPE_LAZY_ASSIGNMENT_OP(NODE) \ #define CLASSTYPE_LAZY_ASSIGNMENT_OP(NODE) \
(LANG_TYPE_CLASS_CHECK (NODE)->lazy_assignment_op) (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&). */ /* Nonzero means that this _CLASSTYPE node overloads operator=(X&). */
#define TYPE_HAS_ASSIGN_REF(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->has_assign_ref) #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)) (VEC_index (tree, CLASSTYPE_METHOD_VEC (NODE), CLASSTYPE_CONSTRUCTOR_SLOT))
/* A FUNCTION_DECL for the destructor for NODE. These are the /* 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) \ #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) /* A dictionary of the nested user-defined-types (class-types, or enums)
found within this class. This table includes nested member class found within this class. This table includes nested member class
@ -2412,9 +2422,6 @@ struct lang_decl GTY(())
&& CONSTRUCTOR_ELTS (NODE) == NULL_TREE \ && CONSTRUCTOR_ELTS (NODE) == NULL_TREE \
&& ! TREE_HAS_CONSTRUCTOR (NODE)) && ! 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 /* Nonzero means that an object of this type can not be initialized using
an initializer list. */ an initializer list. */
#define CLASSTYPE_NON_AGGREGATE(NODE) \ #define CLASSTYPE_NON_AGGREGATE(NODE) \
@ -3721,6 +3728,7 @@ extern void debug_thunks (tree);
extern tree cp_fold_obj_type_ref (tree, tree); extern tree cp_fold_obj_type_ref (tree, tree);
extern void set_linkage_according_to_type (tree, tree); extern void set_linkage_according_to_type (tree, tree);
extern void determine_key_method (tree); extern void determine_key_method (tree);
extern void check_for_override (tree, tree);
/* in cvt.c */ /* in cvt.c */
extern tree convert_to_reference (tree, tree, int, int, tree); 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_x_delete (tree, int, tree);
extern tree build_delete (tree, tree, special_function_kind, int, int); extern tree build_delete (tree, tree, special_function_kind, int, int);
extern void push_base_cleanups (void); 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 build_vec_delete (tree, tree, special_function_kind, int);
extern tree create_temporary_var (tree); extern tree create_temporary_var (tree);
extern void initialize_vtbl_ptrs (tree); extern void initialize_vtbl_ptrs (tree);

View File

@ -793,6 +793,11 @@ convert_to_void (tree expr, const char *implicit)
return expr; return expr;
if (invalid_nonstatic_memfn_p (expr)) if (invalid_nonstatic_memfn_p (expr))
return error_mark_node; 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))) if (VOID_TYPE_P (TREE_TYPE (expr)))
return expr; return expr;
switch (TREE_CODE (expr)) switch (TREE_CODE (expr))

View File

@ -10929,9 +10929,6 @@ cxx_maybe_build_cleanup (tree decl)
rval = build_delete (TREE_TYPE (rval), rval, rval = build_delete (TREE_TYPE (rval), rval,
sfk_complete_destructor, flags, 0); 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 rval;
} }
return NULL_TREE; return NULL_TREE;

View File

@ -182,9 +182,12 @@ dtor_nothrow (tree type)
if (type == NULL_TREE) if (type == NULL_TREE)
return 0; return 0;
if (! TYPE_HAS_DESTRUCTOR (type)) if (!CLASS_TYPE_P (type))
return 1; return 1;
if (CLASSTYPE_LAZY_DESTRUCTOR (type))
lazily_declare_fn (sfk_destructor, type);
return TREE_NOTHROW (CLASSTYPE_DESTRUCTORS (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))); 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)), cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
complete_dtor_identifier, 0); complete_dtor_identifier, 0);

View File

@ -2796,7 +2796,8 @@ build_delete (tree type, tree addr, special_function_kind auto_delete,
tree do_delete = NULL_TREE; tree do_delete = NULL_TREE;
tree ifexp; 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 /* For `::delete x', we must not use the deleting destructor
since then we would not be sure to get the global `operator 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. /* Build a C++ vector delete expression.
MAXINDEX is the number of elements to be deleted. MAXINDEX is the number of elements to be deleted.
ELT_SIZE is the nominal size of each element in the vector. ELT_SIZE is the nominal size of each element in the vector.

View File

@ -823,9 +823,7 @@ synthesize_exception_spec (tree type, tree (*extractor) (tree, void*),
static tree static tree
locate_dtor (tree type, void *client ATTRIBUTE_UNUSED) locate_dtor (tree type, void *client ATTRIBUTE_UNUSED)
{ {
return (CLASSTYPE_METHOD_VEC (type) return CLASSTYPE_DESTRUCTORS (type);
? CLASSTYPE_DESTRUCTORS (type)
: NULL_TREE);
} }
/* Locate the default ctor of 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_DECLARED_INLINE_P (fn) = 1;
DECL_INLINE (fn) = 1; DECL_INLINE (fn) = 1;
gcc_assert (!TREE_USED (fn)); gcc_assert (!TREE_USED (fn));
return fn; return fn;
} }
@ -1060,24 +1058,46 @@ lazily_declare_fn (special_function_kind sfk, tree type)
const_p = false; const_p = false;
/* Declare the function. */ /* Declare the function. */
fn = implicitly_declare_fn (sfk, type, const_p); 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 it to CLASSTYPE_METHOD_VEC. */
add_method (type, fn); add_method (type, fn);
/* Add it to TYPE_METHODS. */ /* Add it to TYPE_METHODS. */
TREE_CHAIN (fn) = TYPE_METHODS (type); if (sfk == sfk_destructor
TYPE_METHODS (type) = fn; && 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); 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. */ /* Remember that the function has been created. */
if (sfk == sfk_constructor) if (sfk == sfk_constructor)
CLASSTYPE_LAZY_DEFAULT_CTOR (type) = 0; CLASSTYPE_LAZY_DEFAULT_CTOR (type) = 0;
else else if (sfk == sfk_copy_constructor)
CLASSTYPE_LAZY_COPY_CTOR (type) = 0; CLASSTYPE_LAZY_COPY_CTOR (type) = 0;
else if (sfk == sfk_destructor)
CLASSTYPE_LAZY_DESTRUCTOR (type) = 0;
/* Create appropriate clones. */ /* Create appropriate clones. */
clone_function_decl (fn, /*update_method_vec=*/true); clone_function_decl (fn, /*update_method_vec=*/true);
} }
else if (sfk == sfk_assignment_operator)
CLASSTYPE_LAZY_ASSIGNMENT_OP (type) = 0;
return fn; return fn;
} }

View 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 that's not a class type, there is no destructor. */
if (!type || !CLASS_TYPE_P (type)) if (!type || !CLASS_TYPE_P (type))
return error_mark_node; return error_mark_node;
if (CLASSTYPE_LAZY_DESTRUCTOR (type))
lazily_declare_fn (sfk_destructor, type);
if (!CLASSTYPE_DESTRUCTORS (type)) if (!CLASSTYPE_DESTRUCTORS (type))
return error_mark_node; return error_mark_node;
/* If it was a class type, return the destructor. */ /* If it was a class type, return the destructor. */

View File

@ -1932,7 +1932,7 @@ check_explicit_specialization (tree declarator,
int is_constructor = DECL_CONSTRUCTOR_P (decl); int is_constructor = DECL_CONSTRUCTOR_P (decl);
if (is_constructor ? !TYPE_HAS_CONSTRUCTOR (ctype) if (is_constructor ? !TYPE_HAS_CONSTRUCTOR (ctype)
: !TYPE_HAS_DESTRUCTOR (ctype)) : !CLASSTYPE_DESTRUCTORS (ctype))
{ {
/* From [temp.expl.spec]: /* From [temp.expl.spec]:
@ -5541,7 +5541,6 @@ instantiate_class_template (tree type)
input_location = DECL_SOURCE_LOCATION (TYPE_NAME (pattern)); input_location = DECL_SOURCE_LOCATION (TYPE_NAME (pattern));
TYPE_HAS_CONSTRUCTOR (type) = TYPE_HAS_CONSTRUCTOR (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_NEW_OPERATOR (type) = TYPE_HAS_NEW_OPERATOR (pattern);
TYPE_HAS_ARRAY_NEW_OPERATOR (type) = TYPE_HAS_ARRAY_NEW_OPERATOR (pattern); TYPE_HAS_ARRAY_NEW_OPERATOR (type) = TYPE_HAS_ARRAY_NEW_OPERATOR (pattern);
TYPE_GETS_DELETE (type) = TYPE_GETS_DELETE (pattern); TYPE_GETS_DELETE (type) = TYPE_GETS_DELETE (pattern);

View File

@ -100,8 +100,6 @@ cxx_print_type (FILE *file, tree node, int indent)
fputs ( "needs-constructor", file); fputs ( "needs-constructor", file);
if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (node)) if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (node))
fputs (" needs-destructor", file); fputs (" needs-destructor", file);
if (TYPE_HAS_DESTRUCTOR (node))
fputs (" ~X()", file);
if (TYPE_HAS_DEFAULT_CONSTRUCTOR (node)) if (TYPE_HAS_DEFAULT_CONSTRUCTOR (node))
fputs (" X()", file); fputs (" X()", file);
if (TYPE_HAS_CONVERSION (node)) if (TYPE_HAS_CONVERSION (node))

View File

@ -1342,7 +1342,7 @@ emit_support_tinfos (void)
if (!COMPLETE_TYPE_P (bltn_type)) if (!COMPLETE_TYPE_P (bltn_type))
return; return;
dtor = CLASSTYPE_DESTRUCTORS (bltn_type); dtor = CLASSTYPE_DESTRUCTORS (bltn_type);
if (DECL_EXTERNAL (dtor)) if (!dtor || DECL_EXTERNAL (dtor))
return; return;
doing_runtime = 1; doing_runtime = 1;
for (ix = 0; fundamentals[ix]; ix++) for (ix = 0; fundamentals[ix]; ix++)

View File

@ -1367,6 +1367,12 @@ lookup_fnfields_1 (tree type, tree name)
else if (name == ansi_assopname(NOP_EXPR) else if (name == ansi_assopname(NOP_EXPR)
&& CLASSTYPE_LAZY_ASSIGNMENT_OP (type)) && CLASSTYPE_LAZY_ASSIGNMENT_OP (type))
lazily_declare_fn (sfk_assignment_operator, 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); method_vec = CLASSTYPE_METHOD_VEC (type);

View File

@ -1577,9 +1577,6 @@ build_class_member_access_expr (tree object, tree member,
if (object == error_mark_node || member == error_mark_node) if (object == error_mark_node || member == error_mark_node)
return error_mark_node; return error_mark_node;
if (TREE_CODE (member) == PSEUDO_DTOR_EXPR)
return member;
gcc_assert (DECL_P (member) || BASELINK_P (member)); gcc_assert (DECL_P (member) || BASELINK_P (member));
/* [expr.ref] /* [expr.ref]
@ -1822,9 +1819,6 @@ lookup_destructor (tree object, tree scope, tree dtor_name)
TYPE_MAIN_VARIANT (object_type), dtor_type); TYPE_MAIN_VARIANT (object_type), dtor_type);
return error_mark_node; 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, expr = lookup_member (dtor_type, complete_dtor_identifier,
/*protect=*/1, /*want_type=*/false); /*protect=*/1, /*want_type=*/false);
expr = (adjust_result_of_qualified_name_lookup expr = (adjust_result_of_qualified_name_lookup

View 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> 2005-02-09 Joseph S. Myers <joseph@codesourcery.com>
* gcc.dg/20050209-1.c: New test. * gcc.dg/20050209-1.c: New test.

View File

@ -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 "" }
}

View File

@ -0,0 +1,5 @@
// { dg-options "-Weffc++" }
struct S {};
/* Base classes should have virtual destructors. */
struct T : public S {}; // { dg-warning "" }