+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.
{
/* 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))
/* 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;
}
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.
/* 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
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;
--- /dev/null
+// 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());
+}