PR c++/79533 - C++17 ICE with temporary cast to reference
authorJason Merrill <jason@redhat.com>
Fri, 17 Feb 2017 16:50:16 +0000 (11:50 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 17 Feb 2017 16:50:16 +0000 (11:50 -0500)
* call.c (build_over_call): Conversion to a reference prevents copy
elision.

From-SVN: r245538

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/testsuite/g++.dg/init/elide6.C [new file with mode: 0644]

index 11ef320..a1e4948 100644 (file)
@@ -1,3 +1,9 @@
+2017-02-17  Jason Merrill  <jason@redhat.com>
+
+       PR c++/79533 - C++17 ICE with temporary cast to reference
+       * call.c (build_over_call): Conversion to a reference prevents copy
+       elision.
+
 2017-02-16  Jakub Jelinek  <jakub@redhat.com>
            Jason Merrill  <jason@redhat.com>
 
index 154509b..4ef444b 100644 (file)
@@ -7955,7 +7955,14 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
 
       /* Pull out the real argument, disregarding const-correctness.  */
       targ = arg;
-      while (CONVERT_EXPR_P (targ)
+      /* Strip the reference binding for the constructor parameter.  */
+      if (CONVERT_EXPR_P (targ)
+         && TREE_CODE (TREE_TYPE (targ)) == REFERENCE_TYPE)
+       targ = TREE_OPERAND (targ, 0);
+      /* But don't strip any other reference bindings; binding a temporary to a
+        reference prevents copy elision.  */
+      while ((CONVERT_EXPR_P (targ)
+             && TREE_CODE (TREE_TYPE (targ)) != REFERENCE_TYPE)
             || TREE_CODE (targ) == NON_LVALUE_EXPR)
        targ = TREE_OPERAND (targ, 0);
       if (TREE_CODE (targ) == ADDR_EXPR)
diff --git a/gcc/testsuite/g++.dg/init/elide6.C b/gcc/testsuite/g++.dg/init/elide6.C
new file mode 100644 (file)
index 0000000..d40bd9d
--- /dev/null
@@ -0,0 +1,11 @@
+// PR c++/79533
+
+struct S {
+  S();
+  S(const S&);
+};
+S f();
+S s(static_cast<S const &>(f()));
+
+// The static_cast prevents copy elision.
+// { dg-final { scan-assembler "_ZN1SC1ERKS_" } }