From c1aa4de772757f0c5afb61f8ebcf58550fc62a83 Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Mon, 17 May 1999 07:42:26 +0000 Subject: [PATCH] call.c (build_over_call): Don't throw away initializations/copies of empty classes... * call.c (build_over_call): Don't throw away initializations/copies of empty classes; use MODIFY_EXPR and INIT_EXPR as for non-empty classes. * class.c (finish_struct_1): Put the padding byte for an empty class on the TYPE_NONCOPIED_PARTS list for the class. From-SVN: r26970 --- gcc/cp/ChangeLog | 8 ++++ gcc/cp/call.c | 40 +++++++++++-------- gcc/cp/class.c | 19 +++++++-- gcc/testsuite/g++.old-deja/g++.other/empty1.C | 23 +++++++++++ 4 files changed, 71 insertions(+), 19 deletions(-) create mode 100644 gcc/testsuite/g++.old-deja/g++.other/empty1.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 51479528fd9..a43deddfdb1 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +1999-05-17 Mark Mitchell + + * call.c (build_over_call): Don't throw away + initializations/copies of empty classes; use MODIFY_EXPR and + INIT_EXPR as for non-empty classes. + * class.c (finish_struct_1): Put the padding byte for an empty + class on the TYPE_NONCOPIED_PARTS list for the class. + 1999-05-16 Mark Mitchell * decl2.c (build_expr_from_tree): Handle COMPONENT_REFs that diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 1dccabcf102..496cf91e17e 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -3426,20 +3426,34 @@ build_over_call (cand, args, flags) else if (! real_lvalue_p (arg) || TYPE_HAS_TRIVIAL_INIT_REF (DECL_CONTEXT (fn))) { + tree address; tree to = stabilize_reference (build_indirect_ref (TREE_VALUE (args), 0)); - /* Don't copy the padding byte; it might not have been allocated - if to is a base subobject. */ - if (is_empty_class (DECL_CLASS_CONTEXT (fn))) - return build_unary_op - (ADDR_EXPR, build (COMPOUND_EXPR, TREE_TYPE (to), - cp_convert (void_type_node, arg), to), - 0); - - val = build (INIT_EXPR, DECL_CONTEXT (fn), to, arg); + /* If we're initializing an empty class, then we actually + have to use a MODIFY_EXPR rather than an INIT_EXPR. The + reason is that the dummy padding member in the target may + not actually be allocated if TO is a base class + subobject. Since we've set TYPE_NONCOPIED_PARTS on the + padding, a MODIFY_EXPR will preserve its value, which is + the right thing to do if it's not really padding at all. + + It's not safe to just throw away the ARG if we're looking + at an empty class because the ARG might contain a + TARGET_EXPR which wants to be bound to TO. If it is not, + expand_expr will assign a dummy slot for the TARGET_EXPR, + and we will call a destructor for it, which is wrong, + because we will also destroy TO, but will never have + constructed it. */ + val = build (is_empty_class (DECL_CLASS_CONTEXT (fn)) + ? MODIFY_EXPR : INIT_EXPR, + DECL_CONTEXT (fn), to, arg); TREE_SIDE_EFFECTS (val) = 1; - return build_unary_op (ADDR_EXPR, val, 0); + address = build_unary_op (ADDR_EXPR, val, 0); + /* Avoid a warning about this expression, if the address is + never used. */ + TREE_USED (address) = 1; + return address; } } else if (DECL_NAME (fn) == ansi_opname[MODIFY_EXPR] @@ -3451,12 +3465,6 @@ build_over_call (cand, args, flags) arg = build_indirect_ref (TREE_VALUE (TREE_CHAIN (converted_args)), 0); - /* Don't copy the padding byte; it might not have been allocated - if to is a base subobject. */ - if (is_empty_class (DECL_CLASS_CONTEXT (fn))) - return build (COMPOUND_EXPR, TREE_TYPE (to), - cp_convert (void_type_node, arg), to); - val = build (MODIFY_EXPR, TREE_TYPE (to), to, arg); TREE_SIDE_EFFECTS (val) = 1; return val; diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 1466e949771..f7998c1c976 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -3133,6 +3133,7 @@ finish_struct_1 (t, warn_anon) int aggregate = 1; int empty = 1; int has_pointers = 0; + tree inline_friends; if (warn_anon && code != UNION_TYPE && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))) pedwarn ("anonymous class type not used to declare any objects"); @@ -3740,6 +3741,13 @@ finish_struct_1 (t, warn_anon) if (DECL_SIZE (x) != integer_zero_node) empty = 0; } + + /* CLASSTYPE_INLINE_FRIENDS is really TYPE_NONCOPIED_PARTS. Thus, + we have to save this before we start modifying + TYPE_NONCOPIED_PARTS. */ + inline_friends = CLASSTYPE_INLINE_FRIENDS (t); + CLASSTYPE_INLINE_FRIENDS (t) = NULL_TREE; + if (empty) { /* C++: do not let empty structures exist. */ @@ -3747,7 +3755,11 @@ finish_struct_1 (t, warn_anon) (FIELD_DECL, NULL_TREE, char_type_node); TREE_CHAIN (decl) = fields; TYPE_FIELDS (t) = decl; + TYPE_NONCOPIED_PARTS (t) + = tree_cons (NULL_TREE, decl, TYPE_NONCOPIED_PARTS (t)); + TREE_STATIC (TYPE_NONCOPIED_PARTS (t)) = 1; } + if (n_baseclasses) TYPE_FIELDS (t) = chainon (last_x, TYPE_FIELDS (t)); @@ -4021,8 +4033,7 @@ finish_struct_1 (t, warn_anon) } /* Write out inline function definitions. */ - do_inline_function_hair (t, CLASSTYPE_INLINE_FRIENDS (t)); - CLASSTYPE_INLINE_FRIENDS (t) = 0; + do_inline_function_hair (t, inline_friends); if (CLASSTYPE_VSIZE (t) != 0) { @@ -4049,7 +4060,9 @@ finish_struct_1 (t, warn_anon) /* In addition to this one, all the other vfields should be listed. */ /* Before that can be done, we have to have FIELD_DECLs for them, and a place to find them. */ - TYPE_NONCOPIED_PARTS (t) = build_tree_list (default_conversion (TYPE_BINFO_VTABLE (t)), vfield); + TYPE_NONCOPIED_PARTS (t) + = tree_cons (default_conversion (TYPE_BINFO_VTABLE (t)), + vfield, TYPE_NONCOPIED_PARTS (t)); if (warn_nonvdtor && TYPE_HAS_DESTRUCTOR (t) && DECL_VINDEX (TREE_VEC_ELT (method_vec, 1)) == NULL_TREE) diff --git a/gcc/testsuite/g++.old-deja/g++.other/empty1.C b/gcc/testsuite/g++.old-deja/g++.other/empty1.C new file mode 100644 index 00000000000..0789884079b --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.other/empty1.C @@ -0,0 +1,23 @@ +// Origin: Mark Mitchell + +extern "C" void abort(); +extern "C" void printf(const char*, ...); + +int i; + +struct A; + +struct A* as[10]; + +struct A { + A () { as[i++] = this; } + A (const A&) { as[i++] = this; } + ~A() { if (i == 0 || as[--i] != this) abort(); } +}; + +A f() { return A(); } + +int main () +{ + A a (f ()); +}