From 465184ae10e9ab0532cfe043d8a6b84d95c28b7f Mon Sep 17 00:00:00 2001
From: Douglas Gregor <dgregor@apple.com>
Date: Sat, 22 Jan 2011 00:06:57 +0000
Subject: [PATCH] Teach static_cast and dynamic_cast about rvalue references.

llvm-svn: 124006
---
 clang/lib/Sema/SemaCXXCast.cpp                | 26 +++++++++----------
 .../expr.post/expr.dynamic.cast/p3-0x.cpp     | 14 ++++++++++
 .../expr/expr.post/expr.static.cast/p3-0x.cpp | 24 +++++++++++++++++
 3 files changed, 51 insertions(+), 13 deletions(-)
 create mode 100644 clang/test/CXX/expr/expr.post/expr.dynamic.cast/p3-0x.cpp
 create mode 100644 clang/test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp

diff --git a/clang/lib/Sema/SemaCXXCast.cpp b/clang/lib/Sema/SemaCXXCast.cpp
index 200f975d74b9..7badc7a7971b 100644
--- a/clang/lib/Sema/SemaCXXCast.cpp
+++ b/clang/lib/Sema/SemaCXXCast.cpp
@@ -341,7 +341,9 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
     DestPointee = DestPointer->getPointeeType();
   } else if ((DestReference = DestType->getAs<ReferenceType>())) {
     DestPointee = DestReference->getPointeeType();
-    VK = isa<LValueReferenceType>(DestReference) ? VK_LValue : VK_RValue;
+    VK = isa<LValueReferenceType>(DestReference) ? VK_LValue 
+       : isa<RValueReferenceType>(DestReference) ? VK_XValue
+       : VK_RValue;
   } else {
     Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ref_or_ptr)
       << OrigDestType << DestRange;
@@ -364,10 +366,8 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
 
   // C++0x 5.2.7p2: If T is a pointer type, v shall be an rvalue of a pointer to
   //   complete class type, [...]. If T is an lvalue reference type, v shall be
-  //   an lvalue of a complete class type, [...]. If T is an rvalue reference
-  //   type, v shall be an expression having a complete effective class type,
-  //   [...]
-
+  //   an lvalue of a complete class type, [...]. If T is an rvalue reference 
+  //   type, v shall be an expression having a complete class type, [...]
   QualType SrcType = Self.Context.getCanonicalType(OrigSrcType);
   QualType SrcPointee;
   if (DestPointer) {
@@ -578,8 +578,9 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
   if (tcr != TC_NotApplicable)
     return tcr;
 
-  // N2844 5.2.9p3: An lvalue of type "cv1 T1" can be cast to type "rvalue
-  //   reference to cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1".
+  // C++0x [expr.static.cast]p3: 
+  //   A glvalue of type "cv1 T1" can be cast to type "rvalue reference to cv2
+  //   T2" if "cv2 T2" is reference-compatible with "cv1 T1".
   tcr = TryLValueToRValueCast(Self, SrcExpr, DestType, msg);
   if (tcr != TC_NotApplicable) {
     Kind = CK_NoOp;
@@ -695,13 +696,14 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
 TryCastResult
 TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType,
                       unsigned &msg) {
-  // N2844 5.2.9p3: An lvalue of type "cv1 T1" can be cast to type "rvalue
-  //   reference to cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1".
+  // C++0x [expr.static.cast]p3:
+  //   A glvalue of type "cv1 T1" can be cast to type "rvalue reference to 
+  //   cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1".
   const RValueReferenceType *R = DestType->getAs<RValueReferenceType>();
   if (!R)
     return TC_NotApplicable;
 
-  if (!SrcExpr->isLValue())
+  if (!SrcExpr->isGLValue())
     return TC_NotApplicable;
 
   // Because we try the reference downcast before this function, from now on
@@ -710,15 +712,13 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType,
   bool DerivedToBase;
   bool ObjCConversion;
   if (Self.CompareReferenceRelationship(SrcExpr->getLocStart(),
-                                        SrcExpr->getType(), R->getPointeeType(),
+                                        R->getPointeeType(), SrcExpr->getType(),
                                         DerivedToBase, ObjCConversion) <
         Sema::Ref_Compatible_With_Added_Qualification) {
     msg = diag::err_bad_lvalue_to_rvalue_cast;
     return TC_Failed;
   }
 
-  // FIXME: We should probably have an AST node for lvalue-to-rvalue 
-  // conversions.
   return TC_Success;
 }
 
diff --git a/clang/test/CXX/expr/expr.post/expr.dynamic.cast/p3-0x.cpp b/clang/test/CXX/expr/expr.post/expr.dynamic.cast/p3-0x.cpp
new file mode 100644
index 000000000000..3b448a80db2b
--- /dev/null
+++ b/clang/test/CXX/expr/expr.post/expr.dynamic.cast/p3-0x.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+struct X { virtual ~X(); };
+struct Y : public X { };
+struct Z; // expected-note{{forward declaration of 'Z'}}
+
+void test(X &x, Y &y, Z &z) {
+  // If T is an rvalue reference type, v shall be an expression having
+  // a complete class type, and the result is an xvalue of the type
+  // referred to by T.
+  Y &&yr0 = dynamic_cast<Y&&>(x);
+  Y &&yr1 = dynamic_cast<Y&&>(static_cast<X&&>(x));
+  Y &&yr2 = dynamic_cast<Y&&>(z); // expected-error{{'Z' is an incomplete type}}
+}
diff --git a/clang/test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp b/clang/test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp
new file mode 100644
index 000000000000..c10335183e21
--- /dev/null
+++ b/clang/test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+// A glvalue of type "cv1 T1" can be cast to type "rvalue reference to
+// cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1" (8.5.3).
+struct A { };
+struct B : A { };
+
+template<typename T> T& lvalue();
+template<typename T> T&& xvalue();
+
+void test(A &a, B &b) {
+  A &&ar0 = static_cast<A&&>(a);
+  A &&ar1 = static_cast<A&&>(b);
+  A &&ar2 = static_cast<A&&>(lvalue<A>());
+  A &&ar3 = static_cast<A&&>(lvalue<B>());
+  A &&ar4 = static_cast<A&&>(xvalue<A>());
+  A &&ar5 = static_cast<A&&>(xvalue<B>());
+  const A &&ar6 = static_cast<const A&&>(a);
+  const A &&ar7 = static_cast<const A&&>(b);
+  const A &&ar8 = static_cast<const A&&>(lvalue<A>());
+  const A &&ar9 = static_cast<const A&&>(lvalue<B>());
+  const A &&ar10 = static_cast<const A&&>(xvalue<A>());
+  const A &&ar11 = static_cast<const A&&>(xvalue<B>());
+}
-- 
GitLab