[PATCH] D87565: [Sema] Improve const_cast conformance to N4261

Mark de Wever via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Sat Sep 12 10:53:59 PDT 2020


Mordante created this revision.
Mordante added reviewers: rjmccall, rsmith.
Mordante added a project: clang.
Mordante requested review of this revision.

Allows `const_cast`s of similar non-record types.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D87565

Files:
  clang/lib/Sema/SemaCast.cpp
  clang/test/SemaCXX/const-cast.cpp


Index: clang/test/SemaCXX/const-cast.cpp
===================================================================
--- clang/test/SemaCXX/const-cast.cpp
+++ clang/test/SemaCXX/const-cast.cpp
@@ -1,6 +1,9 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++14 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
 
 struct A {};
 
@@ -71,12 +74,30 @@
   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-re {{const_cast to 'void (A::*)(){{( __attribute__\(\(thiscall\)\))?}}', 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 &&'}}
+  (void)const_cast<int&&>(0);
+#if __cplusplus < 201703L // N4261
+  // expected-error at -2 {{const_cast from rvalue to reference type 'int &&'}}
+#endif
 #if __cplusplus <= 199711L // C++03 or earlier modes
-  // expected-warning at -2 {{rvalue references are a C++11 extension}}
+  // expected-warning at -5 {{rvalue references are a C++11 extension}}
 #endif
   return **var3;
 }
 
 template <typename T>
 char *PR21845() { return const_cast<char *>((void)T::x); } // expected-error {{const_cast from 'void' to 'char *' is not allowed}}
+
+#if __cplusplus >= 201103L
+namespace N4261 {
+typedef int *A[3];
+typedef const int *const CA[3];
+
+CA &&r = A{};
+A &&r1 = const_cast<A>(CA{}); // expected-error {{const_cast to 'N4261::A' (aka 'int *[3]'), which is not a reference, pointer-to-object, or pointer-to-data-member}}
+
+A &&r2 = const_cast<A &&>(CA{});
+#if __cplusplus < 201703L
+// expected-error at -2 {{const_cast from rvalue to reference type 'N4261::A &&' (aka 'int *(&&)[3]')}}
+#endif
+} // namespace N4261
+#endif
Index: clang/lib/Sema/SemaCast.cpp
===================================================================
--- clang/lib/Sema/SemaCast.cpp
+++ clang/lib/Sema/SemaCast.cpp
@@ -1769,7 +1769,7 @@
   QualType SrcType = SrcExpr.get()->getType();
   bool NeedToMaterializeTemporary = false;
 
-  if (const ReferenceType *DestTypeTmp =DestType->getAs<ReferenceType>()) {
+  if (const ReferenceType *DestTypeTmp = DestType->getAs<ReferenceType>()) {
     // 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
@@ -1790,16 +1790,23 @@
     }
 
     if (isa<RValueReferenceType>(DestTypeTmp) && SrcExpr.get()->isRValue()) {
-      if (!SrcType->isRecordType()) {
+      // Materialize the class prvalue so that the const_cast can bind a
+      // reference to it.
+      NeedToMaterializeTemporary = SrcType->isRecordType();
+
+      // C++17 [expr.const.cast]p3
+      // For two similar types T1 and T2, a prvalue of type T1 may be explicitly
+      // converted to the type T2 using a const_cast if, considering the
+      // cv-decompositions of both types, each P1i is the same as P2i for all i.
+      // The result of a const_cast refers to the original entity.
+      //
+      // Prior to C++17 only RecordTypes were allowed.
+      if (!NeedToMaterializeTemporary && !Self.getLangOpts().CPlusPlus17) {
         // 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


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D87565.291404.patch
Type: text/x-patch
Size: 3949 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20200912/90814858/attachment.bin>


More information about the cfe-commits mailing list