+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
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);
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
{
/* 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
/* 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);
/* 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);
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);
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)
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,
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)
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
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);
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;
}
}
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))
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);
/* 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);
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)
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
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.
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;
/* 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;
#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)
(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
&& 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) \
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);
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);
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))
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;
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));
}
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);
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
}
}
-/* 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.
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. */
DECL_DECLARED_INLINE_P (fn) = 1;
DECL_INLINE (fn) = 1;
gcc_assert (!TREE_USED (fn));
-
+
return fn;
}
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;
}
/* 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. */
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]:
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);
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))
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++)
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);
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]
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.
--- /dev/null
+// 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 "" }
+}
+
+
--- /dev/null
+// { dg-options "-Weffc++" }
+
+struct S {};
+/* Base classes should have virtual destructors. */
+struct T : public S {}; // { dg-warning "" }