OSDN Git Service

PR c++/8186
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 31 Oct 2002 21:42:46 +0000 (21:42 +0000)
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 31 Oct 2002 21:42:46 +0000 (21:42 +0000)
        * 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@58696 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/except.c
gcc/testsuite/g++.dg/eh/stabilize.C [new file with mode: 0644]

index 0f7653c..8b0d774 100644 (file)
@@ -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.
index 4ec8d5e..a347bba 100644 (file)
@@ -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;
 }
 
index f74c58e..cfe7cc9 100644 (file)
@@ -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
index afe4bbd..5e2ae89 100644 (file)
@@ -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 (file)
index 0000000..df47cab
--- /dev/null
@@ -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());
+}