-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[Clang][C++23] Implement P2448R2: Relaxing some constexpr restrictions #77753
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
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.
@llvm/pr-subscribers-clang Author: Mariya Podchishchaeva (Fznamznon) ChangesPer https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2448r2.html function/constructor/destructor can be marked 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:
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@-2 {{'void' is not a literal type}}
+// expected-error@-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]
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I checked changes to DR tests, as that's the only part of this PR I'm competent enough for.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, I think this looks good.
Afaict the whole paper is implemented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me modulo the tiniest of nitpicks
@Endilll , are you ok with the changes? |
@Fznamznon I think that unless bots find something, this is good for 18. I don't see anything that concerns me |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other than the one diagnostic concern, the changes LGTM and I think are fine for Clang 18.
as @groundswellaudio pointed out in #78195, this is because llvm-project/clang/lib/AST/DeclCXX.cpp Line 551 in 99cae9a
will set We should also inspect uses and setting of |
This change started to cause
to fail, which I think is not intentional? |
No, it is not. Fails only for c++23 now. I'm looking. |
Ok, now I looked at it a bit more, and I think this is expected due to the change and how clang behaved before this patch. After this patch implicit destructor of S, i.e. llvm-project/clang/lib/Sema/SemaDeclCXX.cpp Line 7225 in 0ef61ed
So, once I manually change this example to force
Demo https://godbolt.org/z/rT3bWMdqz (note I took 18.1.0 clang which doesn't have P2448R2 implementation). I'm not quite sure the error itself is correct, I've got to educate myself about standard matters a bit more to understand this, but no other compiler errors on this https://godbolt.org/z/Ehhn5sno7. cc @AaronBallman , @cor3ntin, @zygoloid in case you can weigh in here |
I think the discourse thread Clang is overly aggressive when evaluating constexpr functions is relevant here. |
Yeah, I think this is related to https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0859r0.html and I think this comment from @zygoloid might be related as well: #12223 (comment) It's possible this is valid for Clang to reject because of eager instantiation, but I'm not 100% convinced yet either. CC @erichkeane @hubert-reinterpretcast as well |
Hi, this is causing failures for Chrome, building with c++20:
|
I'm assuming this behavior is unintended? Sorry for the late revert |
…strictions (llvm#77753)" This reverts commit 2f67dfb.
Nevermind, unreverted since there appear to be newer tests that use this patch. |
@amykhuang your unrevert (9bfa506) appears to be an empty commit? Was that intended? |
Whoops, not very familiar with git pull requests, I guess. actually reapplying the commit now |
I looked at this a bit and the change that increases the constexpr restrictions is that |
Yes, it was intentional change. And the diagnostic you're seeing is valid for C++20. Prior C++23 defaulted function that invokes non-constexpr function under the hood cannot be marked constexpr. Since relaxing that was made in https://reviews.llvm.org/D146090 is a part of P2448R2, but other parts implemented by this patch are C++23-only due to the problems I described in #77753 (comment) , I've made all parts of P2448R2 consistent. |
…trictions (#77753)" This reverts commit 99500e8 because it causes a behavior change for std=c++20. See llvm/llvm-project#77753.
These are rejected by Clang (19) trunk as a result of llvm/llvm-project#77753.
These are rejected by Clang (19) trunk as a result of llvm/llvm-project#77753.
These are rejected by Clang (19) trunk as a result of llvm/llvm-project#77753.
These are rejected by Clang (19) trunk as a result of llvm/llvm-project#77753.
These are rejected by Clang (19) trunk as a result of llvm/llvm-project#77753. (cherry picked from commit bf1f631)
These are rejected by Clang (19) trunk as a result of llvm/llvm-project#77753. (cherry picked from commit bf1f631)
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.