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@-2 {{const_cast from rvalue to reference type 'int &&'}}
+#endif
 #if __cplusplus <= 199711L // C++03 or earlier modes
-  // expected-warning@-2 {{rvalue references are a C++11 extension}}
+  // expected-warning@-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@-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


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@-2 {{const_cast from rvalue to reference type 'int &&'}}
+#endif
 #if __cplusplus <= 199711L // C++03 or earlier modes
-  // expected-warning@-2 {{rvalue references are a C++11 extension}}
+  // expected-warning@-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@-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
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D87565: [... Mark de Wever via Phabricator via cfe-commits

Reply via email to