From: Sebastian Redl Date: Sun, 22 Mar 2009 22:30:06 +0000 (+0000) Subject: Implement static_cast from lvalue to rvalue reference. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=157be839ade8312389b20d02a3d470c0487fd756;p=clang Implement static_cast from lvalue to rvalue reference. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67487 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 390554ff9e..f4a8470ecb 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1010,6 +1010,9 @@ def err_ambiguous_base_to_derived_cast : Error< "ambiguous static_cast from base %0 to derived %1:%2">; def err_static_downcast_via_virtual : Error< "cannot cast %0 to %1 via virtual base %2">; +def err_bad_lvalue_to_rvalue_cast : Error< + "cannot cast from lvalue of type %0 to rvalue reference to %1; types are " + "not compatible">; // Other C++ expressions def err_need_header_before_typeid : Error< diff --git a/lib/Sema/SemaNamedCast.cpp b/lib/Sema/SemaNamedCast.cpp index 9f5c5e5870..96de1bbad0 100644 --- a/lib/Sema/SemaNamedCast.cpp +++ b/lib/Sema/SemaNamedCast.cpp @@ -39,6 +39,8 @@ static void CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const SourceRange &DestRange); static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType); +static TryStaticCastResult TryLValueToRValueCast( + Sema &Self, Expr *SrcExpr, QualType DestType, const SourceRange &OpRange); static TryStaticCastResult TryStaticReferenceDowncast( Sema &Self, Expr *SrcExpr, QualType DestType, const SourceRange &OpRange); static TryStaticCastResult TryStaticPointerDowncast( @@ -452,6 +454,13 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, return; } + // 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". + if (TryLValueToRValueCast(Self, SrcExpr, DestType, OpRange) > + TSC_NotApplicable) { + return; + } + // C++ 5.2.9p2: An expression e can be explicitly converted to a type T // [...] if the declaration "T t(e);" is well-formed, [...]. if (TryStaticImplicitCast(Self, SrcExpr, DestType, OpRange) > @@ -533,6 +542,36 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, << OpRange; } +/// Tests whether a conversion according to N2844 is valid. +TryStaticCastResult +TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, + const SourceRange &OpRange) +{ + // 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". + const RValueReferenceType *R = DestType->getAsRValueReferenceType(); + if (!R) + return TSC_NotApplicable; + + if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) + return TSC_NotApplicable; + + // Because we try the reference downcast before this function, from now on + // this is the only cast possibility, so we issue an error if we fail now. + bool DerivedToBase; + if (Self.CompareReferenceRelationship(SrcExpr->getType(), R->getPointeeType(), + DerivedToBase) < + Sema::Ref_Compatible_With_Added_Qualification) { + Self.Diag(OpRange.getBegin(), diag::err_bad_lvalue_to_rvalue_cast) + << SrcExpr->getType() << R->getPointeeType() << OpRange; + return TSC_Failed; + } + + // FIXME: Similar to CheckReferenceInit, we actually need more AST annotation + // than nothing. + return TSC_Success; +} + /// Tests whether a conversion according to C++ 5.2.9p5 is valid. TryStaticCastResult TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType, diff --git a/test/SemaCXX/rval-references.cpp b/test/SemaCXX/rval-references.cpp index aafb334b84..59be9f50f6 100644 --- a/test/SemaCXX/rval-references.cpp +++ b/test/SemaCXX/rval-references.cpp @@ -28,6 +28,8 @@ void f() { int i1 = 0; int &&virr4 = i1; // expected-error {{rvalue reference cannot bind to lvalue}} int &&virr5 = ret_irr(); + int &&virr6 = static_cast(i1); + (void)static_cast(i1); // expected-error {{types are not compatible}} int i2 = over(i1); not_int ni1 = over(0);