diff options
author | Jason Merrill <jason@redhat.com> | 2002-10-31 16:42:46 -0500 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2002-10-31 16:42:46 -0500 |
commit | bab076f76ac1930fcec0f0b2e8a6f11b966d2d87 (patch) | |
tree | 04aa0aa91b9adb53b30b87f93d942e389537dd4a | |
parent | ce02ba255cf6b023124277264fe6b34554674910 (diff) | |
download | gcc-bab076f76ac1930fcec0f0b2e8a6f11b966d2d87.zip gcc-bab076f76ac1930fcec0f0b2e8a6f11b966d2d87.tar.gz gcc-bab076f76ac1930fcec0f0b2e8a6f11b966d2d87.tar.bz2 |
re PR c++/8186 (ICE in cp_expr_size, at cp/cp-lang.c:304)
PR c++/8186
* cp-tree.h (ADDR_IS_INVISIREF): New macro.
* call.c (convert_for_arg_passing): Set it.
* except.c (stabilize_throw_expr): Recurse for such an arg.
From-SVN: r58696
-rw-r--r-- | gcc/cp/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/cp/call.c | 11 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 5 | ||||
-rw-r--r-- | gcc/cp/except.c | 27 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/eh/stabilize.C | 26 |
5 files changed, 70 insertions, 6 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0f7653c..8b0d774 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2002-10-30 Jason Merrill <jason@redhat.com> + + PR c++/8186 + * cp-tree.h (ADDR_IS_INVISIREF): New macro. + * call.c (convert_for_arg_passing): Set it. + * except.c (stabilize_throw_expr): Recurse for such an arg. + 2002-10-31 Mark Mitchell <mark@codesourcery.com> * cp-tree.h (lang_decl_flags): Remove init_priority. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 4ec8d5e..a347bba 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -4277,7 +4277,10 @@ convert_for_arg_passing (type, val) { /* Pass classes with copy ctors by invisible reference. */ if (TREE_ADDRESSABLE (type)) - val = build1 (ADDR_EXPR, build_reference_type (type), val); + { + val = build1 (ADDR_EXPR, build_reference_type (type), val); + ADDR_IS_INVISIREF (val) = 1; + } else if (PROMOTE_PROTOTYPES && INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) @@ -4295,7 +4298,11 @@ cp_convert_parm_for_inlining (parm, value, fn) /* When inlining, we don't need to mess with invisible references, so undo the ADDR_EXPR. */ if (TREE_ADDRESSABLE (TREE_TYPE (parm))) - value = build_indirect_ref (value, NULL); + { + value = TREE_OPERAND (value, 0); + if (TREE_CODE (value) != TARGET_EXPR) + abort (); + } return value; } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f74c58e..cfe7cc9 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -66,6 +66,7 @@ struct diagnostic_context; BINDING_HAS_LEVEL_P (in CPLUS_BINDING) BINFO_LOST_PRIMARY_P (in BINFO) TREE_PARMLIST (in TREE_LIST) + ADDR_IS_INVISIREF (in ADDR_EXPR) 3: TYPE_USES_VIRTUAL_BASECLASSES (in a class TYPE). BINFO_VTABLE_PATH_MARKED. BINFO_PUSHDECLS_MARKED. @@ -1673,6 +1674,10 @@ struct lang_type GTY(()) /* Nonzero for a parmlist means that this parmlist ended in ... */ #define PARMLIST_ELLIPSIS_P(NODE) TREE_LANG_FLAG_0 (NODE) +/* Nonzero if this ADDR_EXPR is used to implement the pass by invisible + reference calling convention. */ +#define ADDR_IS_INVISIREF(NODE) TREE_LANG_FLAG_2 (NODE) + /* For FUNCTION_TYPE or METHOD_TYPE, a list of the exceptions that this type can raise. Each TREE_VALUE is a _TYPE. The TREE_VALUE will be NULL_TREE to indicate a throw specification of `()', or diff --git a/gcc/cp/except.c b/gcc/cp/except.c index afe4bbd..5e2ae89 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -599,12 +599,31 @@ stabilize_throw_expr (exp, initp) init_expr = void_zero_node; for (; args; args = TREE_CHAIN (args)) { + tree arg = TREE_VALUE (args); tree arg_init_expr; - tree newarg = stabilize_expr (TREE_VALUE (args), &arg_init_expr); + if (TREE_CODE (arg) == ADDR_EXPR + && ADDR_IS_INVISIREF (arg)) + { + /* A sub-TARGET_EXPR. Recurse; we can't wrap the actual call + without introducing an extra copy. */ + tree sub = TREE_OPERAND (arg, 0); + if (TREE_CODE (sub) != TARGET_EXPR) + abort (); + sub = stabilize_throw_expr (sub, &arg_init_expr); + TREE_OPERAND (arg, 0) = sub; + if (TREE_SIDE_EFFECTS (arg_init_expr)) + init_expr = build (COMPOUND_EXPR, void_type_node, init_expr, + arg_init_expr); + } + else + { + arg = stabilize_expr (arg, &arg_init_expr); - if (arg_init_expr != void_zero_node) - init_expr = build (COMPOUND_EXPR, void_type_node, arg_init_expr, init_expr); - *p = tree_cons (NULL_TREE, newarg, NULL_TREE); + if (TREE_SIDE_EFFECTS (arg_init_expr)) + init_expr = build (COMPOUND_EXPR, void_type_node, init_expr, + arg_init_expr); + } + *p = tree_cons (NULL_TREE, arg, NULL_TREE); p = &TREE_CHAIN (*p); } TREE_OPERAND (aggr_init, 1) = newargs; diff --git a/gcc/testsuite/g++.dg/eh/stabilize.C b/gcc/testsuite/g++.dg/eh/stabilize.C new file mode 100644 index 0000000..df47cab --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/stabilize.C @@ -0,0 +1,26 @@ +// PR c++/8186 + +// Bug: In f, convert_for_arg_passing wrapped the A TARGET_EXPR in an +// ADDR_EXPR for passing by invisible ref. stabilize_throw_expr copied the +// resulting pointer into a temporary. cp_convert_parm_for_inlining then +// dereferences it and tries to initialize B::am with the INDIRECT_REF, +// which calls for a bitwise copy. Which is broken. + +// { dg-options "-O" } + +struct A +{ + A(); + A(const A&); + A& operator=(const A&); +}; + +struct B { + A am; + B(A a) { am = a; } +}; + +void f () +{ + throw B(A()); +} |