-
Notifications
You must be signed in to change notification settings - Fork 13.5k
Reapply "[Clang][C++23] Implement P2448R2 ..." (#85136) #85145
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
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This reverts commit 003e292.
@llvm/pr-subscribers-clang Author: Amy Huang (amykhuang) ChangesThis reverts commit 003e292 because there were dependent changes in the codebase that now fail. Patch is 83.76 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/85145.diff 27 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index e018d38355945f..5fe3fd066df235 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -102,6 +102,8 @@ 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 605fbc52701df0..d7ab1635cf12bc 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9617,13 +9617,10 @@ 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">;
+ "defaulted definition of %sub{select_special_member_kind}0 cannot be marked %select{constexpr|consteval}1 "
+ "before C++23">;
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>;
@@ -9734,21 +9731,12 @@ 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 ext_defaulted_comparison_constexpr_mismatch : Extension<
+def err_defaulted_comparison_constexpr_mismatch : Error<
"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 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;
+ "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 ">;
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 b4f2327d9c560a..1c3dcf63465c68 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -400,10 +400,11 @@ 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, the implicitly-defined
- // default constructor is constexpr.
+ // requirements of a constexpr constructor/function(C++23), the
+ // implicitly-defined default constructor is constexpr.
if (!BaseClassDecl->hasConstexprDefaultConstructor())
- data().DefaultedDefaultConstructorIsConstexpr = false;
+ data().DefaultedDefaultConstructorIsConstexpr =
+ C.getLangOpts().CPlusPlus23;
// C++1z [class.copy]p8:
// The implicitly-declared copy constructor for a class X will have
@@ -548,7 +549,8 @@ 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 = false;
+ data().DefaultedDestructorIsConstexpr =
+ getASTContext().getLangOpts().CPlusPlus23;
// C++20 [temp.param]p7:
// A structural type is [...] a literal class type [for which] the types
@@ -1297,7 +1299,8 @@ 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 = false;
+ data().DefaultedDefaultConstructorIsConstexpr =
+ Context.getLangOpts().CPlusPlus23;
// 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 199f2523cfb5d2..e258a4f7c89415 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -1715,6 +1715,8 @@ 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();
@@ -1746,6 +1748,8 @@ 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(),
@@ -1767,6 +1771,8 @@ 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()))
@@ -1856,16 +1862,18 @@ bool Sema::CheckConstexprFunctionDefinition(const FunctionDecl *NewFD,
}
}
- // - its return type shall be a literal type;
- if (!CheckConstexprReturnType(*this, NewFD, Kind))
+ // - its return type shall be a literal type; (removed in C++23)
+ if (!getLangOpts().CPlusPlus23 &&
+ !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.
- if (!Dtor->getParent()->defaultedDestructorIsConstexpr()) {
+ // have constexpr destructors. (removed in C++23)
+ if (!getLangOpts().CPlusPlus23 &&
+ !Dtor->getParent()->defaultedDestructorIsConstexpr()) {
if (Kind == CheckConstexprKind::CheckValid)
return false;
if (!CheckConstexprDestructorSubobjects(*this, Dtor, Kind))
@@ -1873,8 +1881,9 @@ bool Sema::CheckConstexprFunctionDefinition(const FunctionDecl *NewFD,
}
}
- // - each of its parameter types shall be a literal type;
- if (!CheckConstexprParameterTypes(*this, NewFD, Kind))
+ // - each of its parameter types shall be a literal type; (removed in C++23)
+ if (!getLangOpts().CPlusPlus23 &&
+ !CheckConstexprParameterTypes(*this, NewFD, Kind))
return false;
Stmt *Body = NewFD->getBody();
@@ -2457,7 +2466,8 @@ 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)) {
+ !Expr::isPotentialConstantExpr(Dcl, Diags) &&
+ !SemaRef.getLangOpts().CPlusPlus23) {
SemaRef.Diag(Dcl->getLocation(),
diag::ext_constexpr_function_never_constant_expr)
<< isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval()
@@ -7535,21 +7545,23 @@ static bool defaultedSpecialMemberIsConstexpr(
// C++1y [class.copy]p26:
// -- [the class] is a literal type, and
- if (!Ctor && !ClassDecl->isLiteral())
+ if (!Ctor && !ClassDecl->isLiteral() && !S.getLangOpts().CPlusPlus23)
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
- 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;
+ 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;
+ }
}
// -- every constructor involved in initializing non-static data members
@@ -7559,20 +7571,22 @@ 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
- 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()))
+ 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) {
return false;
- } else if (CSM == Sema::CXXDefaultConstructor) {
- return false;
+ }
}
}
@@ -7858,18 +7872,17 @@ 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(), MD->isConsteval()
- ? diag::err_incorrect_defaulted_consteval
- : diag::err_incorrect_defaulted_constexpr)
- << CSM;
+ Diag(MD->getBeginLoc(), diag::err_incorrect_defaulted_constexpr)
+ << CSM << MD->isConsteval();
}
- // FIXME: Explain why the special member can't be constexpr.
- HadError = true;
+ HadError = true;
+ // FIXME: Explain why the special member can't be constexpr.
}
if (First) {
@@ -9101,13 +9114,11 @@ 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 (CheckConstexprReturnType(*this, FD, CheckConstexprKind::Diagnose) &&
+ if (!getLangOpts().CPlusPlus23 &&
+ CheckConstexprReturnType(*this, FD, CheckConstexprKind::Diagnose) &&
CheckConstexprParameterTypes(*this, FD, CheckConstexprKind::Diagnose) &&
!Info.Constexpr) {
- Diag(FD->getBeginLoc(),
- getLangOpts().CPlusPlus23
- ? diag::warn_cxx23_compat_defaulted_comparison_constexpr_mismatch
- : diag::ext_defaulted_comparison_constexpr_mismatch)
+ Diag(FD->getBeginLoc(), diag::err_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 f1df936a5abe74..127b58915127cf 100644
--- a/clang/test/AST/Interp/cxx23.cpp
+++ b/clang/test/AST/Interp/cxx23.cpp
@@ -1,82 +1,58 @@
-// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify=ref20,all %s
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify=ref20,all,all-20 %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 %s -fexperimental-new-constant-interpreter
+// 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++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}} \
- // 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}}
+ // expected20-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}} \
- // expected23-note {{initializer of 'm' is not a constant expression}}
+ return m; // expected20-note {{initializer of 'm' is not a constant expression}}
}
constexpr int g(int n) { // ref20-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}}
+ // expected20-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}} \
- // 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}}
+ // expected20-note {{declared here}}
+ return m; // expected20-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}} \
- // 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}}
+ // expected20-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}} \
- // expected23-note {{declared here}}
- return m; // expected20-note {{read of non-const variable}} \
- // expected23-note {{read of non-const variable}}
+ // expected20-note {{declared here}}
+ return m; // expected20-note {{read of non-const variable}}
}
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}} \
- // expected20-error {{constexpr function never produces a constant expression}} \
- // expected23-error {{constexpr function never produces a constant expression}}
+ // expected20-error {{constexpr function never produces a cons...
[truncated]
|
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This reverts commit 003e292 because there were dependent changes in the codebase that now fail.