[clang] [Clang][C++23] Implement P2448R2: Relaxing some constexpr restrictions (PR #77753)

via cfe-commits cfe-commits at lists.llvm.org
Thu Jan 11 03:07:14 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Mariya Podchishchaeva (Fznamznon)

<details>
<summary>Changes</summary>

Per https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2448r2.html function/constructor/destructor can be marked `constexpr` even though it never produces a constant expression.
Non-literal types as return types and parameter types of functions marked `constexpr` are also allowed.
Since this is not a DR, the diagnostic messages are still preserved for C++ standards older than C++23.

---

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


36 Files Affected:

- (modified) clang/docs/ReleaseNotes.rst (+2) 
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+26-16) 
- (modified) clang/lib/Sema/SemaDeclCXX.cpp (+39-15) 
- (modified) clang/test/AST/Interp/cxx23.cpp (+6-18) 
- (modified) clang/test/AST/Interp/literals.cpp (+1-1) 
- (modified) clang/test/AST/Interp/shifts.cpp (+4-4) 
- (modified) clang/test/CXX/basic/basic.types/p10.cpp (+13-13) 
- (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 (+2-2) 
- (modified) clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp (+13-14) 
- (modified) clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp (+10-10) 
- (modified) clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp (+3-3) 
- (modified) clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp (+1-1) 
- (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/dr16xx.cpp (+6-6) 
- (modified) clang/test/CXX/drs/dr6xx.cpp (+12-12) 
- (modified) clang/test/CXX/expr/expr.const/p2-0x.cpp (+1-1) 
- (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/PCH/cxx11-constexpr.cpp (+1-1) 
- (modified) clang/test/SemaCXX/builtin_vectorelements.cpp (+1-1) 
- (modified) clang/test/SemaCXX/constant-expression-cxx11.cpp (+15-14) 
- (modified) clang/test/SemaCXX/constant-expression-cxx14.cpp (+17-16) 
- (modified) clang/test/SemaCXX/constant-expression-cxx2b.cpp (+12-6) 
- (modified) clang/test/SemaCXX/constexpr-function-recovery-crash.cpp (+2-2) 
- (modified) clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp (+2-2) 
- (added) clang/test/SemaCXX/cxx23-invalid-constexpr.cpp (+152) 
- (modified) clang/test/SemaCXX/cxx2a-consteval.cpp (+2-2) 
- (modified) clang/test/SemaCXX/deduced-return-type-cxx14.cpp (+4-4) 
- (modified) clang/test/SemaCXX/ms-constexpr-invalid.cpp (+3-3) 
- (modified) clang/test/SemaCXX/ms-constexpr.cpp (+1-1) 
- (modified) clang/test/SemaCXX/sizeless-1.cpp (+1-1) 
- (modified) clang/test/SemaOpenCLCXX/addrspace-constructors.clcpp (+1-1) 
- (modified) clang/www/cxx_status.html (+1-8) 


``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index a18d36a16b1a9c..23342a6a7256d8 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -165,6 +165,8 @@ C++23 Feature Support
 - Added a separate warning to warn the use of attributes on lambdas as a C++23 extension
   in previous language versions: ``-Wc++23-lambda-attributes``.
 
+- 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 1a79892e40030a..67409374f26dfa 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2765,10 +2765,14 @@ def err_constexpr_tag : Error<
   "cannot be marked %sub{select_constexpr_spec_kind}1">;
 def err_constexpr_dtor : Error<
   "destructor cannot be declared %sub{select_constexpr_spec_kind}0">;
-def err_constexpr_dtor_subobject : Error<
-  "destructor cannot be declared %sub{select_constexpr_spec_kind}0 because "
+def ext_constexpr_dtor_subobject : ExtWarn<
+  "destructor cannot be declared %sub{select_constexpr_spec_kind}0 before C++23 because "
   "%select{data member %2|base class %3}1 does not have a "
-  "constexpr destructor">;
+  "constexpr destructor">, InGroup<CXX23>, DefaultError;
+def warn_cxx23_compat_constexpr_dtor_subobject : ExtWarn<
+  "%sub{select_constexpr_spec_kind}0 destructor is incompatible with C++ standards before C++23 because "
+  "%select{data member %2|base class %3}1 does not have a "
+  "constexpr destructor">, InGroup<CXXPre23Compat>, DefaultIgnore;
 def note_constexpr_dtor_subobject : Note<
   "%select{data member %1|base class %2}0 declared here">;
 def err_constexpr_wrong_decl_kind : Error<
@@ -2800,11 +2804,14 @@ def note_non_literal_incomplete : Note<
 def note_non_literal_virtual_base : Note<"%select{struct|interface|class}0 "
   "with virtual base %plural{1:class|:classes}1 is not a literal type">;
 def note_constexpr_virtual_base_here : Note<"virtual base class declared here">;
-def err_constexpr_non_literal_return : Error<
-  "%select{constexpr|consteval}0 function's return type %1 is not a literal type">;
-def err_constexpr_non_literal_param : Error<
-  "%select{constexpr|consteval}2 %select{function|constructor}1's %ordinal0 parameter type %3 is "
-  "not a literal type">;
+def ext_constexpr_non_literal_return : ExtWarn<
+  "%select{constexpr|consteval}0 function with non-literal return type %1 is a C++23 extension">, InGroup<CXX23>, DefaultError;
+def warn_cxx23_compat_constexpr_non_literal_return : Warning<
+  "%select{constexpr|consteval}0 function with non-literal return type %1 is incompatible with C++ standards before C++23">, InGroup<CXXPre23Compat>, DefaultIgnore;
+def ext_constexpr_non_literal_param : ExtWarn<
+  "%select{constexpr|consteval}2 %select{function|constructor}1 with %ordinal0 non-literal parameter type %3 is a C++23 extension">, InGroup<CXX23>, DefaultError;
+def warn_cxx23_compat_constexpr_non_literal_param : Warning<
+  "%select{constexpr|consteval}2 %select{function|constructor}1 with %ordinal0 non-literal parameter type %3 is not compatible with C++ standards before C++23">, InGroup<CXXPre23Compat>, DefaultIgnore;
 def err_constexpr_body_invalid_stmt : Error<
   "statement not allowed in %select{constexpr|consteval}1 %select{function|constructor}0">;
 def ext_constexpr_body_invalid_stmt : ExtWarn<
@@ -2865,8 +2872,11 @@ def warn_cxx17_compat_constexpr_local_var_no_init : Warning<
   "is incompatible with C++ standards before C++20">,
   InGroup<CXXPre20Compat>, DefaultIgnore;
 def ext_constexpr_function_never_constant_expr : ExtWarn<
-  "%select{constexpr|consteval}1 %select{function|constructor}0 never produces a "
-  "constant expression">, InGroup<DiagGroup<"invalid-constexpr">>, DefaultError;
+  "%select{constexpr|consteval}1 %select{function|constructor}0 that never produces a "
+  "constant expression is a C++23 extension">, InGroup<DiagGroup<"invalid-constexpr">>, DefaultError;
+def warn_cxx23_compat_constexpr_function_never_constant_expr : Warning<
+  "%select{constexpr|consteval}1 %select{function|constructor}0 that never produces a "
+  "constant expression is incompatible with C++ standards before C++23">, InGroup<CXXPre23Compat>, DefaultIgnore;
 def err_attr_cond_never_constant_expr : Error<
   "%0 attribute expression never produces a constant expression">;
 def err_diagnose_if_invalid_diagnostic_type : Error<
@@ -9539,14 +9549,14 @@ def err_defaulted_special_member_copy_const_param : Error<
 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 "
-  "is not constexpr">;
+def ext_incorrect_defaulted_constexpr : ExtWarn<
+  "defaulted definition of %sub{select_special_member_kind}0 that marked %select{constexpr|consteval}1 "
+  "but never produces a constant expression is a C++23 extension">, InGroup<CXX23>, DefaultError;
+def warn_cxx23_compat_incorrect_defaulted_constexpr : Warning<
+  "defaulted definition of %sub{select_special_member_kind}0 that marked %select{constexpr|consteval}1 "
+  "but never produces a constant expression is incompatible with C++ standards before C++23">, InGroup<CXXPre23Compat>, DefaultIgnore;
 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>;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 36e53c684ac4dc..aa49dc73e157bf 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -1722,12 +1722,19 @@ static bool CheckConstexprDestructorSubobjects(Sema &SemaRef,
       return true;
 
     if (Kind == Sema::CheckConstexprKind::Diagnose) {
-      SemaRef.Diag(DD->getLocation(), diag::err_constexpr_dtor_subobject)
+      SemaRef.Diag(DD->getLocation(),
+                   SemaRef.getLangOpts().CPlusPlus23
+                       ? diag::warn_cxx23_compat_constexpr_dtor_subobject
+                       : diag::ext_constexpr_dtor_subobject)
           << static_cast<int>(DD->getConstexprKind()) << !FD
           << (FD ? FD->getDeclName() : DeclarationName()) << T;
       SemaRef.Diag(Loc, diag::note_constexpr_dtor_subobject)
           << !FD << (FD ? FD->getDeclName() : DeclarationName()) << T;
     }
+
+    if (SemaRef.getLangOpts().CPlusPlus23)
+      return true;
+
     return false;
   };
 
@@ -1754,11 +1761,17 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef,
     const ParmVarDecl *PD = FD->getParamDecl(ArgIndex);
     assert(PD && "null in a parameter list");
     SourceLocation ParamLoc = PD->getLocation();
-    if (CheckLiteralType(SemaRef, Kind, ParamLoc, *i,
-                         diag::err_constexpr_non_literal_param, ArgIndex + 1,
-                         PD->getSourceRange(), isa<CXXConstructorDecl>(FD),
-                         FD->isConsteval()))
+    if (CheckLiteralType(
+            SemaRef, Kind, ParamLoc, *i,
+            SemaRef.getLangOpts().CPlusPlus23
+                ? diag::warn_cxx23_compat_constexpr_non_literal_param
+                : diag::ext_constexpr_non_literal_param,
+            ArgIndex + 1, PD->getSourceRange(), isa<CXXConstructorDecl>(FD),
+            FD->isConsteval())) {
+      if (SemaRef.getLangOpts().CPlusPlus23)
+        return true;
       return false;
+    }
   }
   return true;
 }
@@ -1767,10 +1780,16 @@ 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) {
-  if (CheckLiteralType(SemaRef, Kind, FD->getLocation(), FD->getReturnType(),
-                       diag::err_constexpr_non_literal_return,
-                       FD->isConsteval()))
+  if (CheckLiteralType(
+          SemaRef, Kind, FD->getLocation(), FD->getReturnType(),
+          SemaRef.getLangOpts().CPlusPlus23
+              ? diag::warn_cxx23_compat_constexpr_non_literal_return
+              : diag::ext_constexpr_non_literal_return,
+          FD->isConsteval())) {
+    if (SemaRef.getLangOpts().CPlusPlus23)
+      return true;
     return false;
+  }
   return true;
 }
 
@@ -2458,8 +2477,11 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
   SmallVector<PartialDiagnosticAt, 8> Diags;
   if (Kind == Sema::CheckConstexprKind::Diagnose &&
       !Expr::isPotentialConstantExpr(Dcl, Diags)) {
-    SemaRef.Diag(Dcl->getLocation(),
-                 diag::ext_constexpr_function_never_constant_expr)
+    SemaRef.Diag(
+        Dcl->getLocation(),
+        SemaRef.getLangOpts().CPlusPlus23
+            ? diag::warn_cxx23_compat_constexpr_function_never_constant_expr
+            : diag::ext_constexpr_function_never_constant_expr)
         << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval()
         << Dcl->getNameInfo().getSourceRange();
     for (size_t I = 0, N = Diags.size(); I != N; ++I)
@@ -7852,13 +7874,15 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
           for (const auto &I : RD->vbases())
             Diag(I.getBeginLoc(), diag::note_constexpr_virtual_base_here);
         } else {
-          Diag(MD->getBeginLoc(), MD->isConsteval()
-                                      ? diag::err_incorrect_defaulted_consteval
-                                      : diag::err_incorrect_defaulted_constexpr)
-              << CSM;
+          Diag(MD->getBeginLoc(),
+               getLangOpts().CPlusPlus23
+                   ? diag::warn_cxx23_compat_incorrect_defaulted_constexpr
+                   : diag::ext_incorrect_defaulted_constexpr)
+              << CSM << MD->isConsteval();
         }
     // FIXME: Explain why the special member can't be constexpr.
-    HadError = true;
+    if (!getLangOpts().CPlusPlus23)
+      HadError = true;
   }
 
   if (First) {
diff --git a/clang/test/AST/Interp/cxx23.cpp b/clang/test/AST/Interp/cxx23.cpp
index bd1cf186d519c5..6ef7df9662e6a4 100644
--- a/clang/test/AST/Interp/cxx23.cpp
+++ b/clang/test/AST/Interp/cxx23.cpp
@@ -6,57 +6,45 @@
 
 /// 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}} \
-                          // ref23-error {{constexpr function never produces a constant expression}}
+constexpr int f(int n) {  // ref20-error {{constexpr function that 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}}
 
   return m;
 }
-constexpr int g(int n) {        // ref20-error {{constexpr function never produces a constant expression}} \
-                                // ref23-error {{constexpr function never produces a constant expression}}
+constexpr int g(int n) {        // ref20-error {{constexpr function that 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}}
   return m;
 }
 
-constexpr int c_thread_local(int n) { // ref20-error {{constexpr function never produces a constant expression}} \
-                                      // ref23-error {{constexpr function never produces a constant expression}}
+constexpr int c_thread_local(int n) { // ref20-error {{constexpr function that 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}}
   return m;
 }
 
 
-constexpr int gnu_thread_local(int n) { // ref20-error {{constexpr function never produces a constant expression}} \
-                                        // ref23-error {{constexpr function never produces a constant expression}}
+constexpr int gnu_thread_local(int n) { // ref20-error {{constexpr function that never produces a constant expression}}
   static __thread 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}}
   return m;
 }
 
-constexpr int h(int n) {  // ref20-error {{constexpr function never produces a constant expression}} \
-                          // ref23-error {{constexpr function never produces a constant expression}}
+constexpr int h(int n) {  // ref20-error {{constexpr function that 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}}
   return &m - &m;
 }
 
-constexpr int i(int n) {        // ref20-error {{constexpr function never produces a constant expression}} \
-                                // ref23-error {{constexpr function never produces a constant expression}}
+constexpr int i(int n) {        // ref20-error {{constexpr function that 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}}
   return &m - &m;
 }
diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp
index 61825bc11438f6..ab09280e883fba 100644
--- a/clang/test/AST/Interp/literals.cpp
+++ b/clang/test/AST/Interp/literals.cpp
@@ -275,7 +275,7 @@ namespace SizeOf {
 
 #if __cplusplus >= 202002L
   /// FIXME: The following code should be accepted.
-  consteval int foo(int n) { // ref-error {{consteval function never produces a constant expression}}
+  consteval int foo(int n) { // ref-error {{consteval function that never produces a constant expression}}
     return sizeof(int[n]); // ref-note 3{{not valid in a constant expression}}
   }
   constinit int var = foo(5); // ref-error {{not a constant expression}} \
diff --git a/clang/test/AST/Interp/shifts.cpp b/clang/test/AST/Interp/shifts.cpp
index cf71e7145c2742..f8fa1b5d095da0 100644
--- a/clang/test/AST/Interp/shifts.cpp
+++ b/clang/test/AST/Interp/shifts.cpp
@@ -7,10 +7,10 @@
 
 
 namespace shifts {
-  constexpr void test() { // ref-error {{constexpr function never produces a constant expression}} \
-                          // ref-cxx17-error {{constexpr function never produces a constant expression}} \
-                          // expected-error {{constexpr function never produces a constant expression}} \
-                          // cxx17-error {{constexpr function never produces a constant expression}} \
+  constexpr void test() { // ref-error {{constexpr function that never produces a constant expression}} \
+                          // ref-cxx17-error {{constexpr function that never produces a constant expression}} \
+                          // expected-error {{constexpr function that never produces a constant expression}} \
+                          // cxx17-error {{constexpr function that never produces a constant expression}} \
 
     char c; // cxx17-warning {{uninitialized variable}} \
             // ref-cxx17-warning {{uninitialized variable}}
diff --git a/clang/test/CXX/basic/basic.types/p10.cpp b/clang/test/CXX/basic/basic.types/p10.cpp
index a543f248e53711..19e099d5077de7 100644
--- a/clang/test/CXX/basic/basic.types/p10.cpp
+++ b/clang/test/CXX/basic/basic.types/p10.cpp
@@ -8,7 +8,7 @@ struct NonLiteral { NonLiteral(); };
 // [C++1y] - void
 constexpr void f() {}
 #ifndef CXX1Y
-// expected-error at -2 {{'void' is not a literal type}}
+// expected-error at -2 {{constexpr function with non-literal return type 'void' is a C++23 extension}}
 #endif
 
 // - a scalar type
@@ -40,12 +40,12 @@ constexpr ClassTemp<int> classtemplate2[] = {};
 struct UserProvDtor {
   ~UserProvDtor(); // expected-note {{has a user-provided destructor}}
 };
-constexpr int f(UserProvDtor) { return 0; } // expected-error {{'UserProvDtor' is not a literal type}}
+constexpr int f(UserProvDtor) { return 0; } // expected-error {{non-literal parameter type 'UserProvDtor'}}
 struct NonTrivDtor {
   constexpr NonTrivDtor();
   virtual ~NonTrivDtor() = default; // expected-note {{has a non-trivial destructor}} expected-note {{because it is virtual}}
 };
-constexpr int f(NonTrivDtor) { return 0; } // expected-error {{'NonTrivDtor' is not a literal type}}
+constexpr int f(NonTrivDtor) { return 0; } // expected-error {{non-literal parameter type 'NonTrivDtor'}}
 struct NonTrivDtorBase {
   ~NonTrivDtorBase();
 };
@@ -53,7 +53,7 @@ template<typename T>
 struct DerivedFromNonTrivDtor : T { // expected-note {{'DerivedFromNonTrivDtor<NonTrivDtorBase>' is not literal because it has base class 'NonTrivDtorBase' of non-literal type}}
   constexpr DerivedFromNonTrivDtor();
 };
-constexpr int f(DerivedFromNonTrivDtor<NonTrivDtorBase>) { return 0; } // expected-error {{constexpr function's 1st parameter type 'DerivedFromNonTrivDtor<NonTrivDtorBase>' is not a literal type}}
+constexpr int f(DerivedFromNonTrivDtor<NonTrivDtorBase>) { return 0; } // expected-error {{constexpr function with 1st non-literal parameter type 'DerivedFromNonTrivDtor<NonTrivDtorBase>' is a C++23 extension}}
 struct TrivDtor {
   constexpr TrivDtor();
 };
@@ -77,11 +77,11 @@ struct CtorTemplate {
 struct CopyCtorOnly { // expected-note {{'CopyCtorOnly' is not literal because it is not an aggregate and has no constexpr constructors other than copy or move constructors}}
   constexpr CopyCtorOnly(CopyCtorOnly&);
 };
-constexpr int f(CopyCtorOnly) { return 0; } // expected-error {{'CopyCtorOnly' is not a literal type}}
+constexpr int f(CopyCtorOnly) { return 0; } // expected-error {{non-literal parameter type 'CopyCtorOnly'}}
 struct MoveCtorOnly { // expected-note {{no constexpr constructors other than copy or move constructors}}
   constexpr MoveCtorOnly(MoveCtorOnly&&);
 };
-constexpr int f(MoveCtorOnly) { return 0; } // expected-error {{'MoveCtorOnly' is not a literal type}}
+constexpr int f(MoveCtorOnly) { return 0; } // expected-error {{non-literal parameter type 'MoveCtorOnly'}}
 template<typename T>
 struct CtorArg {
   constexpr CtorArg(T);
@@ -97,7 +97,7 @@ struct Derived : HasVBase {
 template<typename T> struct DerivedFromVBase : T { // expected-note {{struct with virtual base class is not a literal type}}
   constexpr DerivedFromVBase();
 };
-constexpr int f(De...
[truncated]

``````````

</details>


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


More information about the cfe-commits mailing list