r184017 - Fix handling of const_cast from prvalue to rvalue reference: such a cast is

Richard Smith richard-llvm at metafoo.co.uk
Fri Jun 14 15:27:52 PDT 2013


Author: rsmith
Date: Fri Jun 14 17:27:52 2013
New Revision: 184017

URL: http://llvm.org/viewvc/llvm-project?rev=184017&view=rev
Log:
Fix handling of const_cast from prvalue to rvalue reference: such a cast is
only permitted if the source object is of class type, and should materialize a
temporary for the reference to bind to.

Modified:
    cfe/trunk/lib/Sema/SemaCast.cpp
    cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp
    cfe/trunk/test/CXX/expr/expr.post/expr.const.cast/p1-0x.cpp
    cfe/trunk/test/SemaCXX/const-cast.cpp
    cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp

Modified: cfe/trunk/lib/Sema/SemaCast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCast.cpp?rev=184017&r1=184016&r2=184017&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCast.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCast.cpp Fri Jun 14 17:27:52 2013
@@ -200,8 +200,9 @@ static TryCastResult TryStaticCast(Sema
                                    unsigned &msg, CastKind &Kind,
                                    CXXCastPath &BasePath,
                                    bool ListInitialization);
-static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
-                                  bool CStyle, unsigned &msg);
+static TryCastResult TryConstCast(Sema &Self, ExprResult &SrcExpr,
+                                  QualType DestType, bool CStyle,
+                                  unsigned &msg);
 static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
                                         QualType DestType, bool CStyle,
                                         const SourceRange &OpRange,
@@ -677,7 +678,7 @@ void CastOperation::CheckConstCast() {
     return;
 
   unsigned msg = diag::err_bad_cxx_cast_generic;
-  if (TryConstCast(Self, SrcExpr.get(), DestType, /*CStyle*/false, msg) != TC_Success
+  if (TryConstCast(Self, SrcExpr, DestType, /*CStyle*/false, msg) != TC_Success
       && msg != 0)
     Self.Diag(OpRange.getBegin(), msg) << CT_Const
       << SrcExpr.get()->getType() << DestType << OpRange;
@@ -1447,12 +1448,26 @@ TryStaticImplicitCast(Sema &Self, ExprRe
 
 /// TryConstCast - See if a const_cast from source to destination is allowed,
 /// and perform it if it is.
-static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
-                                  bool CStyle, unsigned &msg) {
+static TryCastResult TryConstCast(Sema &Self, ExprResult &SrcExpr,
+                                  QualType DestType, bool CStyle,
+                                  unsigned &msg) {
   DestType = Self.Context.getCanonicalType(DestType);
-  QualType SrcType = SrcExpr->getType();
+  QualType SrcType = SrcExpr.get()->getType();
+  bool NeedToMaterializeTemporary = false;
+
   if (const ReferenceType *DestTypeTmp =DestType->getAs<ReferenceType>()) {
-    if (isa<LValueReferenceType>(DestTypeTmp) && !SrcExpr->isLValue()) {
+    // C++11 5.2.11p4:
+    //   if a pointer to T1 can be explicitly converted to the type "pointer to
+    //   T2" using a const_cast, then the following conversions can also be
+    //   made:
+    //    -- an lvalue of type T1 can be explicitly converted to an lvalue of
+    //       type T2 using the cast const_cast<T2&>;
+    //    -- a glvalue of type T1 can be explicitly converted to an xvalue of
+    //       type T2 using the cast const_cast<T2&&>; and
+    //    -- if T1 is a class type, a prvalue of type T1 can be explicitly
+    //       converted to an xvalue of type T2 using the cast const_cast<T2&&>.
+
+    if (isa<LValueReferenceType>(DestTypeTmp) && !SrcExpr.get()->isLValue()) {
       // Cannot const_cast non-lvalue to lvalue reference type. But if this
       // is C-style, static_cast might find a way, so we simply suggest a
       // message and tell the parent to keep searching.
@@ -1460,18 +1475,29 @@ static TryCastResult TryConstCast(Sema &
       return TC_NotApplicable;
     }
 
+    if (isa<RValueReferenceType>(DestTypeTmp) && SrcExpr.get()->isRValue()) {
+      if (!SrcType->isRecordType()) {
+        // Cannot const_cast non-class prvalue to rvalue reference type. But if
+        // this is C-style, static_cast can do this.
+        msg = diag::err_bad_cxx_cast_rvalue;
+        return TC_NotApplicable;
+      }
+
+      // Materialize the class prvalue so that the const_cast can bind a
+      // reference to it.
+      NeedToMaterializeTemporary = true;
+    }
+
     // It's not completely clear under the standard whether we can
     // const_cast bit-field gl-values.  Doing so would not be
     // intrinsically complicated, but for now, we say no for
     // consistency with other compilers and await the word of the
     // committee.
-    if (SrcExpr->refersToBitField()) {
+    if (SrcExpr.get()->refersToBitField()) {
       msg = diag::err_bad_cxx_cast_bitfield;
       return TC_NotApplicable;
     }
 
-    // C++ 5.2.11p4: An lvalue of type T1 can be [cast] to an lvalue of type T2
-    //   [...] if a pointer to T1 can be [cast] to the type pointer to T2.
     DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType());
     SrcType = Self.Context.getPointerType(SrcType);
   }
@@ -1525,6 +1551,13 @@ static TryCastResult TryConstCast(Sema &
   if (SrcType != DestType)
     return TC_NotApplicable;
 
+  if (NeedToMaterializeTemporary)
+    // This is a const_cast from a class prvalue to an rvalue reference type.
+    // Materialize a temporary to store the result of the conversion.
+    SrcExpr = new (Self.Context) MaterializeTemporaryExpr(
+        SrcType, SrcExpr.take(), /*IsLValueReference*/ false,
+        /*ExtendingDecl*/ 0);
+
   return TC_Success;
 }
 
@@ -1992,8 +2025,10 @@ void CastOperation::CheckCXXCStyleCast(b
   //   even if a cast resulting from that interpretation is ill-formed.
   // In plain language, this means trying a const_cast ...
   unsigned msg = diag::err_bad_cxx_cast_generic;
-  TryCastResult tcr = TryConstCast(Self, SrcExpr.get(), DestType,
+  TryCastResult tcr = TryConstCast(Self, SrcExpr, DestType,
                                    /*CStyle*/true, msg);
+  if (SrcExpr.isInvalid())
+    return;
   if (tcr == TC_Success)
     Kind = CK_NoOp;
 

Modified: cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp?rev=184017&r1=184016&r2=184017&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp Fri Jun 14 17:27:52 2013
@@ -322,7 +322,7 @@ namespace LValueToRValue {
   //   constant expression;
   constexpr volatile S f() { return S(); }
   static_assert(f().i, ""); // ok! there's no lvalue-to-rvalue conversion here!
-  static_assert(((volatile const S&&)(S)0).i, ""); // expected-error {{constant expression}}
+  static_assert(((volatile const S&&)(S)0).i, ""); // expected-error {{constant expression}} expected-note {{read of volatile-qualified type}}
 }
 
 // DR1312: The proposed wording for this defect has issues, so we ignore this

Modified: cfe/trunk/test/CXX/expr/expr.post/expr.const.cast/p1-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.post/expr.const.cast/p1-0x.cpp?rev=184017&r1=184016&r2=184017&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.post/expr.const.cast/p1-0x.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.post/expr.const.cast/p1-0x.cpp Fri Jun 14 17:27:52 2013
@@ -6,14 +6,26 @@
 
 unsigned int f(int);
 
+struct X {};
+
 template<typename T> T& lvalue();
 template<typename T> T&& xvalue();
 template<typename T> T prvalue();
 
-void test_classification(const int *ptr) {
-  int *ptr0 = const_cast<int *&&>(ptr);
-  int *ptr1 = const_cast<int *&&>(xvalue<const int*>());
-  int *ptr2 = const_cast<int *&&>(prvalue<const int*>());
+void test_classification(const int *ptr, X x) {
+  int *&&ptr0 = const_cast<int *&&>(ptr);
+  int *&&ptr1 = const_cast<int *&&>(xvalue<const int*>());
+  int *&&ptr2 = const_cast<int *&&>(prvalue<const int*>()); // expected-error {{const_cast from rvalue to reference type 'int *&&'}}
+  X &&ptr3 = const_cast<X&&>(x);
+  X &&ptr4 = const_cast<X&&>(xvalue<X>());
+  X &&ptr5 = const_cast<X&&>(prvalue<X>());
+
+  int *&ptr6 = const_cast<int *&>(ptr);
+  int *&ptr7 = const_cast<int *&>(xvalue<const int*>()); // expected-error {{const_cast from rvalue to reference type 'int *&'}}
+  int *&ptr8 = const_cast<int *&>(prvalue<const int*>()); // expected-error {{const_cast from rvalue to reference type 'int *&'}}
+  X &ptr9 = const_cast<X&>(x);
+  X &ptrA = const_cast<X&>(xvalue<X>()); // expected-error {{const_cast from rvalue to reference type 'X &'}}
+  X &ptrB = const_cast<X&>(prvalue<X>()); // expected-error {{const_cast from rvalue to reference type 'X &'}}
 }
 
 struct A {

Modified: cfe/trunk/test/SemaCXX/const-cast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/const-cast.cpp?rev=184017&r1=184016&r2=184017&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/const-cast.cpp (original)
+++ cfe/trunk/test/SemaCXX/const-cast.cpp Fri Jun 14 17:27:52 2013
@@ -38,6 +38,7 @@ char ***good_const_cast_test(ccvpcvpp va
   f *fpp = const_cast<f*>(&fp);
   int const A::* const A::*icapcap = 0;
   int A::* A::* iapap = const_cast<int A::* A::*>(icapcap);
+  (void)const_cast<A&&>(A()); // expected-warning {{C++11}}
 
   return var4;
 }
@@ -60,5 +61,6 @@ short *bad_const_cast_test(char const *v
   f fp2 = const_cast<f>(fp1); // expected-error {{const_cast to 'f' (aka 'int (*)(int)'), which is not a reference, pointer-to-object, or pointer-to-data-member}}
   void (A::*mfn)() = 0;
   (void)const_cast<void (A::*)()>(mfn); // expected-error {{const_cast to 'void (A::*)()', which is not a reference, pointer-to-object, or pointer-to-data-member}}
+  (void)const_cast<int&&>(0); // expected-error {{const_cast from rvalue to reference type 'int &&'}} expected-warning {{C++11}}
   return **var3;
 }

Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=184017&r1=184016&r2=184017&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Fri Jun 14 17:27:52 2013
@@ -79,6 +79,11 @@ constexpr int **n6 = const_cast<int**>(&
 constexpr int n7 = **n5;
 constexpr int n8 = **n6;
 
+// const_cast from prvalue to xvalue.
+struct A { int n; };
+constexpr int n9 = (const_cast<A&&>(A{123})).n;
+static_assert(n9 == 123, "");
+
 }
 
 namespace TemplateArgumentConversion {





More information about the cfe-commits mailing list