From 465184ae10e9ab0532cfe043d8a6b84d95c28b7f Mon Sep 17 00:00:00 2001 From: Douglas Gregor 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())) { DestPointee = DestReference->getPointeeType(); - VK = isa(DestReference) ? VK_LValue : VK_RValue; + VK = isa(DestReference) ? VK_LValue + : isa(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(); 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(x); + Y &&yr1 = dynamic_cast(static_cast(x)); + Y &&yr2 = dynamic_cast(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 T& lvalue(); +template T&& xvalue(); + +void test(A &a, B &b) { + A &&ar0 = static_cast(a); + A &&ar1 = static_cast(b); + A &&ar2 = static_cast(lvalue()); + A &&ar3 = static_cast(lvalue()); + A &&ar4 = static_cast(xvalue()); + A &&ar5 = static_cast(xvalue()); + const A &&ar6 = static_cast(a); + const A &&ar7 = static_cast(b); + const A &&ar8 = static_cast(lvalue()); + const A &&ar9 = static_cast(lvalue()); + const A &&ar10 = static_cast(xvalue()); + const A &&ar11 = static_cast(xvalue()); +}