aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2011-12-14 00:18:39 -0500
committerJason Merrill <jason@gcc.gnu.org>2011-12-14 00:18:39 -0500
commit58fc93fb001225df27cb502d0d5f4f939f0dc0aa (patch)
tree9fb673218f2b6198b16aae17a2adca505dd879b5 /gcc
parentc990877a412109c1e7eac6506239a27ab309051f (diff)
downloadgcc-58fc93fb001225df27cb502d0d5f4f939f0dc0aa.zip
gcc-58fc93fb001225df27cb502d0d5f4f939f0dc0aa.tar.gz
gcc-58fc93fb001225df27cb502d0d5f4f939f0dc0aa.tar.bz2
re PR c++/51406 ([c++0x] Incorrect result of static_cast to rvalue reference to base class.)
PR c++/51406 PR c++/51161 * typeck.c (build_static_cast_1): Fix cast of lvalue to base rvalue reference. From-SVN: r182322
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog7
-rw-r--r--gcc/cp/typeck.c16
-rw-r--r--gcc/testsuite/ChangeLog7
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/rv-cast3.C17
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/rv-cast4.C13
5 files changed, 57 insertions, 3 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 23748d8..d326133 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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-12-13 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/51464
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 4973d7d..b168963 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -5856,12 +5856,22 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
cv2 T2 if cv2 T2 is reference-compatible with cv1 T1 (8.5.3)." */
if (TREE_CODE (type) == REFERENCE_TYPE
&& TYPE_REF_IS_RVALUE (type)
- && lvalue_or_rvalue_with_address_p (expr)
+ && real_lvalue_p (expr)
&& 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);
}
/* Resolve overloaded address here rather than once in
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 5011d2c..e22d114 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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-13 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/51464
diff --git a/gcc/testsuite/g++.dg/cpp0x/rv-cast3.C b/gcc/testsuite/g++.dg/cpp0x/rv-cast3.C
new file mode 100644
index 0000000..6c70324
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/rv-cast3.C
@@ -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
index 0000000..13f369d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/rv-cast4.C
@@ -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" }
+}