From: Douglas Gregor Date: Tue, 25 Jan 2011 16:13:26 +0000 (+0000) Subject: When performing a glvalue-to-xvalue static_cast that involves a X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=88b22a432549e315662f96abe148923c921970cb;p=clang When performing a glvalue-to-xvalue static_cast that involves a derived-to-base conversion, set the cast kind and base path appropriately. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124189 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 075deda4dd..3a9ad5ff7f 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -78,7 +78,9 @@ static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType); // %1: Source Type // %2: Destination Type static TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, - QualType DestType, unsigned &msg); + QualType DestType, CastKind &Kind, + CXXCastPath &BasePath, + unsigned &msg); static TryCastResult TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, @@ -581,11 +583,9 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, // 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; + tcr = TryLValueToRValueCast(Self, SrcExpr, DestType, Kind, BasePath, msg); + if (tcr != TC_NotApplicable) return tcr; - } // C++ 5.2.9p2: An expression e can be explicitly converted to a type T // [...] if the declaration "T t(e);" is well-formed, [...]. @@ -695,7 +695,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, /// Tests whether a conversion according to N2844 is valid. TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, - unsigned &msg) { + CastKind &Kind, CXXCastPath &BasePath, unsigned &msg) { // 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". @@ -719,6 +719,17 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, return TC_Failed; } + if (DerivedToBase) { + Kind = CK_DerivedToBase; + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, + /*DetectVirtual=*/true); + if (!Self.IsDerivedFrom(SrcExpr->getType(), R->getPointeeType(), Paths)) + return TC_NotApplicable; + + Self.BuildBasePathArray(Paths, BasePath); + } else + Kind = CK_NoOp; + return TC_Success; } diff --git a/test/CodeGenCXX/rvalue-references.cpp b/test/CodeGenCXX/rvalue-references.cpp new file mode 100644 index 0000000000..693e1431dd --- /dev/null +++ b/test/CodeGenCXX/rvalue-references.cpp @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -std=c++0x -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s + + +struct Spacer { int x; }; +struct A { double array[2]; }; +struct B : Spacer, A { }; + +B &getB(); + +// CHECK: define %struct.A* @_Z4getAv() +// CHECK: call %struct.B* @_Z4getBv() +// CHECK-NEXT: bitcast %struct.B* +// CHECK-NEXT: getelementptr i8* +// CHECK-NEXT: bitcast i8* {{.*}} to %struct.A* +// CHECK-NEXT: ret %struct.A* +A &&getA() { return static_cast(getB()); } + +int &getIntLValue(); +int &&getIntXValue(); +int getIntPRValue(); + +// CHECK: define i32* @_Z2f0v() +// CHECK: call i32* @_Z12getIntLValuev() +// CHECK-NEXT: ret i32* +int &&f0() { return static_cast(getIntLValue()); } + +// CHECK: define i32* @_Z2f1v() +// CHECK: call i32* @_Z12getIntXValuev() +// CHECK-NEXT: ret i32* +int &&f1() { return static_cast(getIntXValue()); } + +// CHECK: define i32* @_Z2f2v +// CHECK: call i32 @_Z13getIntPRValuev() +// CHECK-NEXT: store i32 {{.*}}, i32* +// CHECK-NEXT: ret i32* +int &&f2() { return static_cast(getIntPRValue()); }