]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR c++/51406 ([c++0x] Incorrect result of static_cast to rvalue reference to base...
authorJason Merrill <jason@redhat.com>
Wed, 14 Dec 2011 16:03:37 +0000 (11:03 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 14 Dec 2011 16:03:37 +0000 (11:03 -0500)
PR c++/51406
PR c++/51161
* typeck.c (build_static_cast_1): Fix cast of lvalue to
base rvalue reference.

From-SVN: r182340

gcc/cp/ChangeLog
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/rv-cast3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/rv-cast4.C [new file with mode: 0644]

index c61269d97ee74e1a25f65a1266d5d4eca7dbc0b1..2f94d210c6dac2c53f5cce5963acf2d1af688311 100644 (file)
@@ -1,3 +1,10 @@
+2011-12-13  Jason Merrill  <jason@redhat.com>
+
+       PR c++/51406
+       PR c++/51161
+       * typeck.c (build_static_cast_1): Fix cast of lvalue to
+       base rvalue reference.
+
 2011-10-19  Jason Merrill  <jason@redhat.com>
 
        PR c++/50793
index 7cdcee939fe418558f24c32a076ecd0e5dbccdc5..b67ab1f05061b06bf8ec9c0ca3bbbc2131a672f0 100644 (file)
@@ -5674,8 +5674,18 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
       && reference_related_p (TREE_TYPE (type), intype)
       && (c_cast_p || at_least_as_qualified_p (TREE_TYPE (type), intype)))
     {
-      expr = build_typed_address (expr, type);
-      return convert_from_reference (expr);
+      /* Handle the lvalue case here by casting to lvalue reference and
+        then changing it to an rvalue reference.  Casting an xvalue to
+        rvalue reference will be handled by the main code path.  */
+      tree lref = cp_build_reference_type (TREE_TYPE (type), false);
+      result = (perform_direct_initialization_if_possible
+               (lref, expr, c_cast_p, complain));
+      result = cp_fold_convert (type, result);
+      /* Make sure we don't fold back down to a named rvalue reference,
+        because that would be an lvalue.  */
+      if (DECL_P (result))
+       result = build1 (NON_LVALUE_EXPR, type, result);
+      return convert_from_reference (result);
     }
 
   orig = expr;
index 67602c3c967b56771d2cf3f3f3a5eaaecb91e2de..8319732b01ee5e1d6f9cffa92cd92f6e8dc547c5 100644 (file)
@@ -1,3 +1,10 @@
+2011-12-13  Jason Merrill  <jason@redhat.com>
+
+       PR c++/51406
+       PR c++/51161
+       * g++.dg/cpp0x/rv-cast3.C: New.
+       * g++.dg/cpp0x/rv-cast4.C: New.
+
 2011-12-09  Kazu Hirata  <kazu@codesourcery.com>
 
        Backport from mainline:
diff --git a/gcc/testsuite/g++.dg/cpp0x/rv-cast3.C b/gcc/testsuite/g++.dg/cpp0x/rv-cast3.C
new file mode 100644 (file)
index 0000000..6c70324
--- /dev/null
@@ -0,0 +1,17 @@
+// PR c++/51406
+// { dg-do run { target c++11 } }
+
+extern "C" int printf(const char *,...);
+extern "C" void abort();
+
+struct A { int a; A() : a(1) {} };
+struct B { int b; B() : b(2) {} };
+struct X : A, B {};
+
+int main() {
+    X x;
+    int a=static_cast<A&&>(x).a;
+    int b=static_cast<B&&>(x).b;
+    // printf ("%d %d\n", a, b);
+    if (a!=1 || b!=2) abort();
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/rv-cast4.C b/gcc/testsuite/g++.dg/cpp0x/rv-cast4.C
new file mode 100644 (file)
index 0000000..13f369d
--- /dev/null
@@ -0,0 +1,13 @@
+// PR c++/51161
+// { dg-do compile { target c++11 } }
+
+struct A{};
+struct B : A{};
+struct C : A{};
+struct D : B, C{};
+
+int main()
+{
+  D d;
+  static_cast<A &&>(d);                // { dg-error "ambiguous" }
+}