Commit 9f4faeae by Mark Mitchell Committed by Mark Mitchell

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
parent ec2cd8b2
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
......
......@@ -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
......
......@@ -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);
......
......@@ -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))
......
......@@ -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;
......
......@@ -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);
......
......@@ -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.
......
......@@ -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;
}
......
......@@ -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. */
......
......@@ -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);
......
......@@ -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))
......
......@@ -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++)
......
......@@ -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);
......
......@@ -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
......
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.
......
// 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 "" }
}
// { dg-options "-Weffc++" }
struct S {};
/* Base classes should have virtual destructors. */
struct T : public S {}; // { dg-warning "" }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment