[clang] Revert "[Clang][C++23] Implement P2448R2 ..." (PR #85136)

via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 13 14:46:10 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Amy Huang (amykhuang)

<details>
<summary>Changes</summary>

Revert "[Clang][C++23] Implement P2448R2: Relaxing some constexpr restrictions (#<!-- -->77753)"

This reverts commit 99500e8c08a4d941acb8a7eb00523296fb2acf7a because it causes a behavior change for std=c++20. See
https://github.com/llvm/llvm-project/pull/77753.

---

Patch is 83.76 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/85136.diff


27 Files Affected:

- (modified) clang/docs/ReleaseNotes.rst (-2) 
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+19-7) 
- (modified) clang/lib/AST/DeclCXX.cpp (+5-8) 
- (modified) clang/lib/Sema/SemaDeclCXX.cpp (+41-52) 
- (modified) clang/test/AST/Interp/cxx23.cpp (+41-18) 
- (modified) clang/test/CXX/class/class.compare/class.compare.default/p3.cpp (+19-21) 
- (modified) clang/test/CXX/class/class.compare/class.compare.default/p4.cpp (+10-10) 
- (modified) clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/dtor.cpp (+4-4) 
- (modified) clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3-2b.cpp (+6-4) 
- (modified) clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp (+9-9) 
- (modified) clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp (+4-4) 
- (modified) clang/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp (+3-3) 
- (modified) clang/test/CXX/drs/dr13xx.cpp (+11-11) 
- (modified) clang/test/CXX/drs/dr14xx.cpp (+3-3) 
- (modified) clang/test/CXX/drs/dr15xx.cpp (+9-12) 
- (modified) clang/test/CXX/drs/dr16xx.cpp (+10-10) 
- (modified) clang/test/CXX/drs/dr6xx.cpp (+12-12) 
- (modified) clang/test/CXX/expr/expr.const/p5-26.cpp (+2-2) 
- (modified) clang/test/CXX/special/class.copy/p13-0x.cpp (+1-1) 
- (modified) clang/test/SemaCXX/constant-expression-cxx11.cpp (+18-20) 
- (modified) clang/test/SemaCXX/constant-expression-cxx14.cpp (+16-17) 
- (modified) clang/test/SemaCXX/constant-expression-cxx2b.cpp (+12-12) 
- (removed) clang/test/SemaCXX/cxx23-invalid-constexpr.cpp (-159) 
- (modified) clang/test/SemaCXX/cxx2a-consteval.cpp (+1-1) 
- (modified) clang/test/SemaCXX/deduced-return-type-cxx14.cpp (+4-4) 
- (modified) clang/test/SemaOpenCLCXX/addrspace-constructors.clcpp (+1-1) 
- (modified) clang/www/cxx_status.html (+8-1) 


``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 5fe3fd066df235..e018d38355945f 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -102,8 +102,6 @@ C++23 Feature Support
   materialize temporary object which is a prvalue in discarded-value expression.
 - Implemented `P1774R8: Portable assumptions <https://wg21.link/P1774R8>`_.
 
-- Implemented `P2448R2: Relaxing some constexpr restrictions <https://wg21.link/P2448R2>`_.
-
 C++2c Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d7ab1635cf12bc..605fbc52701df0 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9617,10 +9617,13 @@ def err_defaulted_copy_assign_not_ref : Error<
   "the parameter for an explicitly-defaulted copy assignment operator must be an "
   "lvalue reference type">;
 def err_incorrect_defaulted_constexpr : Error<
-  "defaulted definition of %sub{select_special_member_kind}0 cannot be marked %select{constexpr|consteval}1 "
-  "before C++23">;
+  "defaulted definition of %sub{select_special_member_kind}0 "
+  "is not constexpr">;
 def err_incorrect_defaulted_constexpr_with_vb: Error<
   "%sub{select_special_member_kind}0 cannot be 'constexpr' in a class with virtual base class">;
+def err_incorrect_defaulted_consteval : Error<
+  "defaulted declaration of %sub{select_special_member_kind}0 "
+  "cannot be consteval because implicit definition is not constexpr">;
 def warn_defaulted_method_deleted : Warning<
   "explicitly defaulted %sub{select_special_member_kind}0 is implicitly "
   "deleted">, InGroup<DefaultedFunctionDeleted>;
@@ -9731,12 +9734,21 @@ def note_defaulted_comparison_cannot_deduce_undeduced_auto : Note<
   "%select{|member|base class}0 %1 declared here">;
 def note_defaulted_comparison_cannot_deduce_callee : Note<
   "selected 'operator<=>' for %select{|member|base class}0 %1 declared here">;
-def err_defaulted_comparison_constexpr_mismatch : Error<
+def ext_defaulted_comparison_constexpr_mismatch : Extension<
   "defaulted definition of %select{%sub{select_defaulted_comparison_kind}1|"
-  "three-way comparison operator}0 cannot be "
-  "declared %select{constexpr|consteval}2 because "
-  "%select{it|for which the corresponding implicit 'operator==' }0 "
-  "invokes a non-constexpr comparison function ">;
+  "three-way comparison operator}0 that is "
+  "declared %select{constexpr|consteval}2 but"
+  "%select{|for which the corresponding implicit 'operator==' }0 "
+  "invokes a non-constexpr comparison function is a C++23 extension">,
+  InGroup<DiagGroup<"c++23-default-comp-relaxed-constexpr">>;
+def warn_cxx23_compat_defaulted_comparison_constexpr_mismatch : Warning<
+  "defaulted definition of %select{%sub{select_defaulted_comparison_kind}1|"
+  "three-way comparison operator}0 that is "
+  "declared %select{constexpr|consteval}2 but"
+  "%select{|for which the corresponding implicit 'operator==' }0 "
+  "invokes a non-constexpr comparison function is incompatible with C++ "
+  "standards before C++23">,
+  InGroup<CXXPre23Compat>, DefaultIgnore;
 def note_defaulted_comparison_not_constexpr : Note<
   "non-constexpr comparison function would be used to compare "
   "%select{|member %1|base class %1}0">;
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 1c3dcf63465c68..b4f2327d9c560a 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -400,11 +400,10 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
 
       // C++11 [class.ctor]p6:
       //   If that user-written default constructor would satisfy the
-      //   requirements of a constexpr constructor/function(C++23), the
-      //   implicitly-defined default constructor is constexpr.
+      //   requirements of a constexpr constructor, the implicitly-defined
+      //   default constructor is constexpr.
       if (!BaseClassDecl->hasConstexprDefaultConstructor())
-        data().DefaultedDefaultConstructorIsConstexpr =
-            C.getLangOpts().CPlusPlus23;
+        data().DefaultedDefaultConstructorIsConstexpr = false;
 
       // C++1z [class.copy]p8:
       //   The implicitly-declared copy constructor for a class X will have
@@ -549,8 +548,7 @@ void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) {
   //   -- for every subobject of class type or (possibly multi-dimensional)
   //      array thereof, that class type shall have a constexpr destructor
   if (!Subobj->hasConstexprDestructor())
-    data().DefaultedDestructorIsConstexpr =
-        getASTContext().getLangOpts().CPlusPlus23;
+    data().DefaultedDestructorIsConstexpr = false;
 
   // C++20 [temp.param]p7:
   //   A structural type is [...] a literal class type [for which] the types
@@ -1299,8 +1297,7 @@ void CXXRecordDecl::addedMember(Decl *D) {
             !FieldRec->hasConstexprDefaultConstructor() && !isUnion())
           // The standard requires any in-class initializer to be a constant
           // expression. We consider this to be a defect.
-          data().DefaultedDefaultConstructorIsConstexpr =
-              Context.getLangOpts().CPlusPlus23;
+          data().DefaultedDefaultConstructorIsConstexpr = false;
 
         // C++11 [class.copy]p8:
         //   The implicitly-declared copy constructor for a class X will have
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index e258a4f7c89415..199f2523cfb5d2 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -1715,8 +1715,6 @@ static bool CheckLiteralType(Sema &SemaRef, Sema::CheckConstexprKind Kind,
 static bool CheckConstexprDestructorSubobjects(Sema &SemaRef,
                                                const CXXDestructorDecl *DD,
                                                Sema::CheckConstexprKind Kind) {
-  assert(!SemaRef.getLangOpts().CPlusPlus23 &&
-         "this check is obsolete for C++23");
   auto Check = [&](SourceLocation Loc, QualType T, const FieldDecl *FD) {
     const CXXRecordDecl *RD =
         T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
@@ -1748,8 +1746,6 @@ static bool CheckConstexprDestructorSubobjects(Sema &SemaRef,
 static bool CheckConstexprParameterTypes(Sema &SemaRef,
                                          const FunctionDecl *FD,
                                          Sema::CheckConstexprKind Kind) {
-  assert(!SemaRef.getLangOpts().CPlusPlus23 &&
-         "this check is obsolete for C++23");
   unsigned ArgIndex = 0;
   const auto *FT = FD->getType()->castAs<FunctionProtoType>();
   for (FunctionProtoType::param_type_iterator i = FT->param_type_begin(),
@@ -1771,8 +1767,6 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef,
 /// true. If not, produce a suitable diagnostic and return false.
 static bool CheckConstexprReturnType(Sema &SemaRef, const FunctionDecl *FD,
                                      Sema::CheckConstexprKind Kind) {
-  assert(!SemaRef.getLangOpts().CPlusPlus23 &&
-         "this check is obsolete for C++23");
   if (CheckLiteralType(SemaRef, Kind, FD->getLocation(), FD->getReturnType(),
                        diag::err_constexpr_non_literal_return,
                        FD->isConsteval()))
@@ -1862,18 +1856,16 @@ bool Sema::CheckConstexprFunctionDefinition(const FunctionDecl *NewFD,
       }
     }
 
-    // - its return type shall be a literal type; (removed in C++23)
-    if (!getLangOpts().CPlusPlus23 &&
-        !CheckConstexprReturnType(*this, NewFD, Kind))
+    // - its return type shall be a literal type;
+    if (!CheckConstexprReturnType(*this, NewFD, Kind))
       return false;
   }
 
   if (auto *Dtor = dyn_cast<CXXDestructorDecl>(NewFD)) {
     // A destructor can be constexpr only if the defaulted destructor could be;
     // we don't need to check the members and bases if we already know they all
-    // have constexpr destructors. (removed in C++23)
-    if (!getLangOpts().CPlusPlus23 &&
-        !Dtor->getParent()->defaultedDestructorIsConstexpr()) {
+    // have constexpr destructors.
+    if (!Dtor->getParent()->defaultedDestructorIsConstexpr()) {
       if (Kind == CheckConstexprKind::CheckValid)
         return false;
       if (!CheckConstexprDestructorSubobjects(*this, Dtor, Kind))
@@ -1881,9 +1873,8 @@ bool Sema::CheckConstexprFunctionDefinition(const FunctionDecl *NewFD,
     }
   }
 
-  // - each of its parameter types shall be a literal type; (removed in C++23)
-  if (!getLangOpts().CPlusPlus23 &&
-      !CheckConstexprParameterTypes(*this, NewFD, Kind))
+  // - each of its parameter types shall be a literal type;
+  if (!CheckConstexprParameterTypes(*this, NewFD, Kind))
     return false;
 
   Stmt *Body = NewFD->getBody();
@@ -2466,8 +2457,7 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
   // function", so is not checked in CheckValid mode.
   SmallVector<PartialDiagnosticAt, 8> Diags;
   if (Kind == Sema::CheckConstexprKind::Diagnose &&
-      !Expr::isPotentialConstantExpr(Dcl, Diags) &&
-      !SemaRef.getLangOpts().CPlusPlus23) {
+      !Expr::isPotentialConstantExpr(Dcl, Diags)) {
     SemaRef.Diag(Dcl->getLocation(),
                  diag::ext_constexpr_function_never_constant_expr)
         << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval()
@@ -7545,23 +7535,21 @@ static bool defaultedSpecialMemberIsConstexpr(
 
   // C++1y [class.copy]p26:
   //   -- [the class] is a literal type, and
-  if (!Ctor && !ClassDecl->isLiteral() && !S.getLangOpts().CPlusPlus23)
+  if (!Ctor && !ClassDecl->isLiteral())
     return false;
 
   //   -- every constructor involved in initializing [...] base class
   //      sub-objects shall be a constexpr constructor;
   //   -- the assignment operator selected to copy/move each direct base
   //      class is a constexpr function, and
-  if (!S.getLangOpts().CPlusPlus23) {
-    for (const auto &B : ClassDecl->bases()) {
-      const RecordType *BaseType = B.getType()->getAs<RecordType>();
-      if (!BaseType)
-        continue;
-      CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
-      if (!specialMemberIsConstexpr(S, BaseClassDecl, CSM, 0, ConstArg,
-                                    InheritedCtor, Inherited))
-        return false;
-    }
+  for (const auto &B : ClassDecl->bases()) {
+    const RecordType *BaseType = B.getType()->getAs<RecordType>();
+    if (!BaseType)
+      continue;
+    CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
+    if (!specialMemberIsConstexpr(S, BaseClassDecl, CSM, 0, ConstArg,
+                                  InheritedCtor, Inherited))
+      return false;
   }
 
   //   -- every constructor involved in initializing non-static data members
@@ -7571,22 +7559,20 @@ static bool defaultedSpecialMemberIsConstexpr(
   //   -- for each non-static data member of X that is of class type (or array
   //      thereof), the assignment operator selected to copy/move that member is
   //      a constexpr function
-  if (!S.getLangOpts().CPlusPlus23) {
-    for (const auto *F : ClassDecl->fields()) {
-      if (F->isInvalidDecl())
-        continue;
-      if (CSM == Sema::CXXDefaultConstructor && F->hasInClassInitializer())
-        continue;
-      QualType BaseType = S.Context.getBaseElementType(F->getType());
-      if (const RecordType *RecordTy = BaseType->getAs<RecordType>()) {
-        CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
-        if (!specialMemberIsConstexpr(S, FieldRecDecl, CSM,
-                                      BaseType.getCVRQualifiers(),
-                                      ConstArg && !F->isMutable()))
-          return false;
-      } else if (CSM == Sema::CXXDefaultConstructor) {
+  for (const auto *F : ClassDecl->fields()) {
+    if (F->isInvalidDecl())
+      continue;
+    if (CSM == Sema::CXXDefaultConstructor && F->hasInClassInitializer())
+      continue;
+    QualType BaseType = S.Context.getBaseElementType(F->getType());
+    if (const RecordType *RecordTy = BaseType->getAs<RecordType>()) {
+      CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
+      if (!specialMemberIsConstexpr(S, FieldRecDecl, CSM,
+                                    BaseType.getCVRQualifiers(),
+                                    ConstArg && !F->isMutable()))
         return false;
-      }
+    } else if (CSM == Sema::CXXDefaultConstructor) {
+      return false;
     }
   }
 
@@ -7872,17 +7858,18 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
       MD->isConstexpr() && !Constexpr &&
       MD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) {
         if (!MD->isConsteval() && RD->getNumVBases()) {
-          Diag(MD->getBeginLoc(),
-               diag::err_incorrect_defaulted_constexpr_with_vb)
+          Diag(MD->getBeginLoc(), diag::err_incorrect_defaulted_constexpr_with_vb)
               << CSM;
           for (const auto &I : RD->vbases())
             Diag(I.getBeginLoc(), diag::note_constexpr_virtual_base_here);
         } else {
-          Diag(MD->getBeginLoc(), diag::err_incorrect_defaulted_constexpr)
-              << CSM << MD->isConsteval();
+          Diag(MD->getBeginLoc(), MD->isConsteval()
+                                      ? diag::err_incorrect_defaulted_consteval
+                                      : diag::err_incorrect_defaulted_constexpr)
+              << CSM;
         }
-        HadError = true;
-        // FIXME: Explain why the special member can't be constexpr.
+    // FIXME: Explain why the special member can't be constexpr.
+    HadError = true;
   }
 
   if (First) {
@@ -9114,11 +9101,13 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD,
   //    - if the function is a constructor or destructor, its class does not
   //      have any virtual base classes.
   if (FD->isConstexpr()) {
-    if (!getLangOpts().CPlusPlus23 &&
-        CheckConstexprReturnType(*this, FD, CheckConstexprKind::Diagnose) &&
+    if (CheckConstexprReturnType(*this, FD, CheckConstexprKind::Diagnose) &&
         CheckConstexprParameterTypes(*this, FD, CheckConstexprKind::Diagnose) &&
         !Info.Constexpr) {
-      Diag(FD->getBeginLoc(), diag::err_defaulted_comparison_constexpr_mismatch)
+      Diag(FD->getBeginLoc(),
+           getLangOpts().CPlusPlus23
+               ? diag::warn_cxx23_compat_defaulted_comparison_constexpr_mismatch
+               : diag::ext_defaulted_comparison_constexpr_mismatch)
           << FD->isImplicit() << (int)DCK << FD->isConsteval();
       DefaultedComparisonAnalyzer(*this, RD, FD, DCK,
                                   DefaultedComparisonAnalyzer::ExplainConstexpr)
diff --git a/clang/test/AST/Interp/cxx23.cpp b/clang/test/AST/Interp/cxx23.cpp
index 127b58915127cf..f1df936a5abe74 100644
--- a/clang/test/AST/Interp/cxx23.cpp
+++ b/clang/test/AST/Interp/cxx23.cpp
@@ -1,58 +1,82 @@
-// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify=ref20,all,all-20 %s
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify=ref20,all %s
 // RUN: %clang_cc1 -std=c++23 -fsyntax-only -fcxx-exceptions -verify=ref23,all %s
-// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify=expected20,all,all-20 %s -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify=expected20,all %s -fexperimental-new-constant-interpreter
 // RUN: %clang_cc1 -std=c++23 -fsyntax-only -fcxx-exceptions -verify=expected23,all %s -fexperimental-new-constant-interpreter
 
 /// FIXME: The new interpreter is missing all the 'control flows through...' diagnostics.
 
 constexpr int f(int n) {  // ref20-error {{constexpr function never produces a constant expression}} \
-                          // expected20-error {{constexpr function never produces a constant expression}}
+                          // ref23-error {{constexpr function never produces a constant expression}} \
+                          // expected20-error {{constexpr function never produces a constant expression}} \
+                          // expected23-error {{constexpr function never produces a constant expression}}
   static const int m = n; // ref20-note {{control flows through the definition of a static variable}} \
                           // ref20-warning {{is a C++23 extension}} \
+                          // ref23-note {{control flows through the definition of a static variable}} \
                           // expected20-warning {{is a C++23 extension}} \
                           // expected20-note {{declared here}} \
+                          // expected23-note {{declared here}}
 
-  return m; // expected20-note {{initializer of 'm' is not a constant expression}}
+  return m; // expected20-note {{initializer of 'm' is not a constant expression}} \
+            // expected23-note {{initializer of 'm' is not a constant expression}}
 }
 constexpr int g(int n) {        // ref20-error {{constexpr function never produces a constant expression}} \
-                                // expected20-error {{constexpr function never produces a constant expression}}
+                                // ref23-error {{constexpr function never produces a constant expression}} \
+                                // expected20-error {{constexpr function never produces a constant expression}} \
+                                // expected23-error {{constexpr function never produces a constant expression}}
   thread_local const int m = n; // ref20-note {{control flows through the definition of a thread_local variable}} \
                                 // ref20-warning {{is a C++23 extension}} \
+                                // ref23-note {{control flows through the definition of a thread_local variable}} \
                                 // expected20-warning {{is a C++23 extension}} \
-                                // expected20-note {{declared here}}
-  return m; // expected20-note {{initializer of 'm' is not a constant expression}}
+                                // expected20-note {{declared here}} \
+                                // expected23-note {{declared here}}
+  return m; // expected20-note {{initializer of 'm' is not a constant expression}} \
+            // expected23-note {{initializer of 'm' is not a constant expression}}
 
 }
 
 constexpr int c_thread_local(int n) { // ref20-error {{constexpr function never produces a constant expression}} \
-                                      // expected20-error {{constexpr function never produces a constant expression}}
+                                      // ref23-error {{constexpr function never produces a constant expression}} \
+                                      // expected20-error {{constexpr function never produces a constant expression}} \
+                                      // expected23-error {{constexpr function never produces a constant expression}}
   static _Thread_local int m = 0;     // ref20-note {{control flows through the definition of a thread_local variable}} \
                                       // ref20-warning {{is a C++23 extension}} \
+                                      // ref23-note {{control flows through the definition of a thread_local variable}} \
                                       // expected20-warning {{is a C++23 extension}} \
-                                      // expected20-note {{declared here}}
-  return m; // expected20-note {{read of non-const variable}}
+                                      // expected20-note {{declared here}} \
+                                      // expected23-note {{declared here}}
+  return m; // expected20-note {{read of non-const variable}} \
+            // expected23-note {{read of non-const variable}}
 }
 
 
 constexpr int gnu_thread_local(int n) { // ref20-error {{constexpr function never produces a constant expression}} \
-                                        // expected20-error {{constexpr function never produces a constant expression}}
+                                        // ref23-error {{constexpr function never produces a constant expression}} \
+                                        // expected20-error {{constexpr function never produces a constant expression}} \
+                                        // expected23-error {{constexpr function never produces a cons...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/85136


More information about the cfe-commits mailing list