Skip to content

Commit 302840d

Browse files
committed
Fixing problems with the consteval guards
Corentin asked about ODR issues which led to me making more tests, alas the existing tests all triggered new/delete inside explicitly consteval contexts (if consteval, template parameters, requires, etc) In a fully general constexpr function the logic failed, so this update removes the fast path I was trying to use and just implements the required semantics in both constant expression evaluators. It also adds a bunch more tests :D
1 parent eaa8348 commit 302840d

File tree

12 files changed

+148
-39
lines changed

12 files changed

+148
-39
lines changed

clang/include/clang/AST/Decl.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2521,6 +2521,17 @@ class FunctionDecl : public DeclaratorDecl,
25212521
/// If this function is an allocation/deallocation function that takes
25222522
/// the `std::nothrow_t` tag, return true through IsNothrow,
25232523
bool isReplaceableGlobalAllocationFunction(
2524+
std::optional<unsigned> *AlignmentParam = nullptr,
2525+
bool *IsNothrow = nullptr) const {
2526+
if (isTypeAwareOperatorNewOrDelete())
2527+
return false;
2528+
return isConstEvalSafeOrReplaceableGlobalAllocationFunction(AlignmentParam, IsNothrow);
2529+
}
2530+
2531+
/// Determines whether this function is one of the replaceable global
2532+
/// allocation functions described in isReplaceableGlobalAllocationFunction,
2533+
/// or is a function that may be treated as such during constant evaluation
2534+
bool isConstEvalSafeOrReplaceableGlobalAllocationFunction(
25242535
std::optional<unsigned> *AlignmentParam = nullptr,
25252536
bool *IsNothrow = nullptr) const;
25262537

clang/include/clang/Sema/Sema.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2146,12 +2146,6 @@ class Sema final : public SemaBase {
21462146
isConstantEvaluatedOverride;
21472147
}
21482148

2149-
TypeAwareAllocationMode allocationModeInCurrentContext() const {
2150-
if (getLangOpts().TypeAwareAllocators && !isConstantEvaluatedContext())
2151-
return TypeAwareAllocationMode::Yes;
2152-
return TypeAwareAllocationMode::No;
2153-
}
2154-
21552149
SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL,
21562150
unsigned ByteNo) const;
21572151

clang/lib/AST/ByteCode/Compiler.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3304,7 +3304,7 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) {
33043304
// Always invalid.
33053305
return this->emitInvalid(E);
33063306
}
3307-
} else if (!OperatorNew->isReplaceableGlobalAllocationFunction())
3307+
} else if (!OperatorNew->isConstEvalSafeOrReplaceableGlobalAllocationFunction())
33083308
return this->emitInvalidNewDeleteExpr(E, E);
33093309

33103310
const Descriptor *Desc;
@@ -3402,7 +3402,7 @@ bool Compiler<Emitter>::VisitCXXDeleteExpr(const CXXDeleteExpr *E) {
34023402

34033403
const FunctionDecl *OperatorDelete = E->getOperatorDelete();
34043404

3405-
if (!OperatorDelete->isReplaceableGlobalAllocationFunction())
3405+
if (!OperatorDelete->isConstEvalSafeOrReplaceableGlobalAllocationFunction())
34063406
return this->emitInvalidNewDeleteExpr(E, E);
34073407

34083408
// Arg must be an lvalue.
@@ -4559,7 +4559,7 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
45594559

45604560
const FunctionDecl *FuncDecl = E->getDirectCallee();
45614561
// Calls to replaceable operator new/operator delete.
4562-
if (FuncDecl && FuncDecl->isReplaceableGlobalAllocationFunction()) {
4562+
if (FuncDecl && FuncDecl->isConstEvalSafeOrReplaceableGlobalAllocationFunction()) {
45634563
if (FuncDecl->getDeclName().getCXXOverloadedOperator() == OO_New ||
45644564
FuncDecl->getDeclName().getCXXOverloadedOperator() == OO_Array_New) {
45654565
return VisitBuiltinCallExpr(E, Builtin::BI__builtin_operator_new);

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,7 +1063,7 @@ bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
10631063
if (const FunctionDecl *VirtualDelete =
10641064
getVirtualOperatorDelete(AllocType);
10651065
VirtualDelete &&
1066-
!VirtualDelete->isReplaceableGlobalAllocationFunction()) {
1066+
!VirtualDelete->isConstEvalSafeOrReplaceableGlobalAllocationFunction()) {
10671067
S.FFDiag(S.Current->getSource(OpPC),
10681068
diag::note_constexpr_new_non_replaceable)
10691069
<< isa<CXXMethodDecl>(VirtualDelete) << VirtualDelete;
@@ -1498,14 +1498,14 @@ bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E) {
14981498
!OperatorNew->isReservedGlobalPlacementOperator()) {
14991499
S.FFDiag(Loc, diag::note_constexpr_new_placement)
15001500
<< /*Unsupported*/ 0 << E->getSourceRange();
1501-
} else if (!OperatorNew->isReplaceableGlobalAllocationFunction()) {
1501+
} else if (!OperatorNew->isConstEvalSafeOrReplaceableGlobalAllocationFunction()) {
15021502
S.FFDiag(Loc, diag::note_constexpr_new_non_replaceable)
15031503
<< isa<CXXMethodDecl>(OperatorNew) << OperatorNew;
15041504
}
15051505
} else {
15061506
const auto *DeleteExpr = cast<CXXDeleteExpr>(E);
15071507
const FunctionDecl *OperatorDelete = DeleteExpr->getOperatorDelete();
1508-
if (!OperatorDelete->isReplaceableGlobalAllocationFunction()) {
1508+
if (!OperatorDelete->isConstEvalSafeOrReplaceableGlobalAllocationFunction()) {
15091509
S.FFDiag(Loc, diag::note_constexpr_new_non_replaceable)
15101510
<< isa<CXXMethodDecl>(OperatorDelete) << OperatorDelete;
15111511
}

clang/lib/AST/Decl.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3373,7 +3373,7 @@ bool FunctionDecl::isReservedGlobalPlacementOperator() const {
33733373
return (proto->getParamType(1).getCanonicalType() == Context.VoidPtrTy);
33743374
}
33753375

3376-
bool FunctionDecl::isReplaceableGlobalAllocationFunction(
3376+
bool FunctionDecl::isConstEvalSafeOrReplaceableGlobalAllocationFunction(
33773377
std::optional<unsigned> *AlignmentParam, bool *IsNothrow) const {
33783378
if (getDeclName().getNameKind() != DeclarationName::CXXOperatorName)
33793379
return false;
@@ -3390,16 +3390,19 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction(
33903390
if (!getDeclContext()->getRedeclContext()->isTranslationUnit())
33913391
return false;
33923392

3393+
bool IsTypeAware = isTypeAwareOperatorNewOrDelete();
3394+
unsigned MaxParamCount = IsTypeAware + 4;
33933395
const auto *FPT = getType()->castAs<FunctionProtoType>();
3394-
if (FPT->getNumParams() == 0 || FPT->getNumParams() > 4 || FPT->isVariadic())
3396+
if (FPT->getNumParams() == 0 || FPT->getNumParams() > MaxParamCount || FPT->isVariadic())
33953397
return false;
33963398

3399+
unsigned MinimumParamCount = IsTypeAware + 1;
33973400
// If this is a single-parameter function, it must be a replaceable global
33983401
// allocation or deallocation function.
3399-
if (FPT->getNumParams() == 1)
3402+
if (FPT->getNumParams() == MinimumParamCount)
34003403
return true;
34013404

3402-
unsigned Params = 1;
3405+
unsigned Params = MinimumParamCount;
34033406
QualType Ty = FPT->getParamType(Params);
34043407
const ASTContext &Ctx = getASTContext();
34053408

clang/lib/AST/ExprConstant.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8277,7 +8277,7 @@ class ExprEvaluatorBase
82778277
FD = CorrespondingCallOpSpecialization;
82788278
} else
82798279
FD = LambdaCallOp;
8280-
} else if (FD->isReplaceableGlobalAllocationFunction()) {
8280+
} else if (FD->isConstEvalSafeOrReplaceableGlobalAllocationFunction()) {
82818281
if (FD->getDeclName().getCXXOverloadedOperator() == OO_New ||
82828282
FD->getDeclName().getCXXOverloadedOperator() == OO_Array_New) {
82838283
LValue Ptr;
@@ -10188,7 +10188,7 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
1018810188
Info.FFDiag(E, diag::note_constexpr_new_placement)
1018910189
<< /*Unsupported*/ 0 << E->getSourceRange();
1019010190
return false;
10191-
} else if (!OperatorNew->isReplaceableGlobalAllocationFunction()) {
10191+
} else if (!OperatorNew->isConstEvalSafeOrReplaceableGlobalAllocationFunction()) {
1019210192
Info.FFDiag(E, diag::note_constexpr_new_non_replaceable)
1019310193
<< isa<CXXMethodDecl>(OperatorNew) << OperatorNew;
1019410194
return false;
@@ -16256,7 +16256,7 @@ bool VoidExprEvaluator::VisitCXXDeleteExpr(const CXXDeleteExpr *E) {
1625616256
return false;
1625716257

1625816258
FunctionDecl *OperatorDelete = E->getOperatorDelete();
16259-
if (!OperatorDelete->isReplaceableGlobalAllocationFunction()) {
16259+
if (!OperatorDelete->isConstEvalSafeOrReplaceableGlobalAllocationFunction()) {
1626016260
Info.FFDiag(E, diag::note_constexpr_new_non_replaceable)
1626116261
<< isa<CXXMethodDecl>(OperatorDelete) << OperatorDelete;
1626216262
return false;
@@ -16300,7 +16300,7 @@ bool VoidExprEvaluator::VisitCXXDeleteExpr(const CXXDeleteExpr *E) {
1630016300
if (!E->isArrayForm() && !E->isGlobalDelete()) {
1630116301
const FunctionDecl *VirtualDelete = getVirtualOperatorDelete(AllocType);
1630216302
if (VirtualDelete &&
16303-
!VirtualDelete->isReplaceableGlobalAllocationFunction()) {
16303+
!VirtualDelete->isConstEvalSafeOrReplaceableGlobalAllocationFunction()) {
1630416304
Info.FFDiag(E, diag::note_constexpr_new_non_replaceable)
1630516305
<< isa<CXXMethodDecl>(VirtualDelete) << VirtualDelete;
1630616306
return false;

clang/lib/Sema/SemaCoroutine.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,7 +1111,7 @@ static bool findDeleteForPromise(Sema &S, SourceLocation Loc, QualType PromiseTy
11111111
// scope of the promise type. If nothing is found, a search is performed in
11121112
// the global scope.
11131113
ImplicitDeallocationParameters IDP = {
1114-
S.allocationModeInCurrentContext(),
1114+
typeAwareAllocationModeFromBool(S.getLangOpts().TypeAwareAllocators),
11151115
alignedAllocationModeFromBool(Overaligned), SizedDeallocationMode::Yes};
11161116
if (S.FindDeallocationFunction(Loc, PointeeRD, DeleteName, OperatorDelete,
11171117
PromiseType, IDP, /*Diagnose*/ true))
@@ -1422,7 +1422,7 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
14221422
// Helper function to indicate whether the last lookup found the aligned
14231423
// allocation function.
14241424
ImplicitAllocationParameters IAP = {
1425-
S.allocationModeInCurrentContext(),
1425+
typeAwareAllocationModeFromBool(S.getLangOpts().TypeAwareAllocators),
14261426
alignedAllocationModeFromBool(S.getLangOpts().CoroAlignedAllocation)};
14271427
auto LookupAllocationFunction =
14281428
[&](Sema::AllocationFunctionScope NewScope = Sema::AFS_Both,
@@ -1437,9 +1437,10 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
14371437
if (NewScope == Sema::AFS_Both)
14381438
NewScope = PromiseContainsNew ? Sema::AFS_Class : Sema::AFS_Global;
14391439

1440-
IAP = {S.allocationModeInCurrentContext(),
1441-
alignedAllocationModeFromBool(
1442-
!ForceNonAligned && S.getLangOpts().CoroAlignedAllocation)};
1440+
bool ShouldUseAlignedAlloc = !ForceNonAligned && S.getLangOpts().CoroAlignedAllocation;
1441+
IAP = {
1442+
typeAwareAllocationModeFromBool(S.getLangOpts().TypeAwareAllocators),
1443+
alignedAllocationModeFromBool(ShouldUseAlignedAlloc)};
14431444

14441445
FunctionDecl *UnusedResult = nullptr;
14451446

clang/lib/Sema/SemaDecl.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14475,10 +14475,11 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
1447514475
<< var;
1447614476

1447714477
// Check whether the initializer is sufficiently constant.
14478-
if ((getLangOpts().CPlusPlus || (getLangOpts().C23 && var->isConstexpr())) &&
14479-
!type->isDependentType() && Init && !Init->isValueDependent() &&
14480-
(GlobalStorage || var->isConstexpr() ||
14481-
var->mightBeUsableInConstantExpressions(Context))) {
14478+
bool c1 = (getLangOpts().CPlusPlus || (getLangOpts().C23 && var->isConstexpr()));
14479+
bool c2 = !type->isDependentType() && Init && !Init->isValueDependent();
14480+
bool c3 = var->isConstexpr();
14481+
bool c4 = var->mightBeUsableInConstantExpressions(Context);
14482+
if (c1 && c2 && (GlobalStorage || c3 || c4)) {
1448214483
// If this variable might have a constant initializer or might be usable in
1448314484
// constant expressions, check whether or not it actually is now. We can't
1448414485
// do this lazily, because the result might depend on things that change

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9715,7 +9715,8 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD,
97159715
QualType DeallocType = Context.getRecordType(RD);
97169716
DeclarationName Name =
97179717
Context.DeclarationNames.getCXXOperatorName(OO_Delete);
9718-
ImplicitDeallocationParameters IDP = {allocationModeInCurrentContext(),
9718+
ImplicitDeallocationParameters IDP = {
9719+
typeAwareAllocationModeFromBool(getLangOpts().TypeAwareAllocators),
97199720
AlignedAllocationMode::No,
97209721
SizedDeallocationMode::No};
97219722
if (FindDeallocationFunction(MD->getLocation(), MD->getParent(), Name,
@@ -16140,7 +16141,7 @@ bool Sema::isTypeAwareOperatorNewOrDelete(const NamedDecl *ND) const {
1614016141
FunctionDecl *
1614116142
Sema::instantiateTypeAwareUsualDelete(FunctionTemplateDecl *FnTemplateDecl,
1614216143
QualType DeallocType) {
16143-
if (!isTypeAwareAllocation(allocationModeInCurrentContext()))
16144+
if (!getLangOpts().TypeAwareAllocators)
1614416145
return nullptr;
1614516146

1614616147
TemplateParameterList *TemplateParameters =
@@ -16214,7 +16215,7 @@ Sema::instantiateTypeAwareUsualDelete(FunctionTemplateDecl *FnTemplateDecl,
1621416215
}
1621516216

1621616217
QualType Sema::instantiateSpecializedTypeIdentity(QualType Subject) {
16217-
assert(clang::isTypeAwareAllocation(allocationModeInCurrentContext()));
16218+
assert(getLangOpts().TypeAwareAllocators);
1621816219
ClassTemplateDecl *TypeIdentity = getStdTypeIdentity();
1621916220
if (!TypeIdentity)
1622016221
return QualType();

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1754,7 +1754,7 @@ static bool isNonPlacementDeallocationFunction(Sema &S, FunctionDecl *FD) {
17541754
return false;
17551755

17561756
unsigned UsualParams = 1;
1757-
if (isTypeAwareAllocation(S.allocationModeInCurrentContext()) &&
1757+
if (S.getLangOpts().TypeAwareAllocators &&
17581758
UsualParams < FD->getNumParams() && FD->isTypeAwareOperatorNewOrDelete())
17591759
++UsualParams;
17601760

@@ -1795,7 +1795,7 @@ namespace {
17951795
FD = InstantiatedDecl;
17961796
}
17971797
unsigned NumBaseParams = 1;
1798-
if (isTypeAwareAllocation(S.allocationModeInCurrentContext()) &&
1798+
if (S.getLangOpts().TypeAwareAllocators &&
17991799
FD->isTypeAwareOperatorNewOrDelete()) {
18001800
QualType TypeIdentityTag = FD->getParamDecl(0)->getType();
18011801
QualType ExpectedTypeIdentityTag =
@@ -2425,7 +2425,7 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
24252425
AllocType->isDependentType() ? 0 : Context.getTypeAlign(AllocType);
24262426
unsigned NewAlignment = Context.getTargetInfo().getNewAlign();
24272427
ImplicitAllocationParameters IAP = {
2428-
allocationModeInCurrentContext(),
2428+
typeAwareAllocationModeFromBool(getLangOpts().TypeAwareAllocators),
24292429
alignedAllocationModeFromBool(getLangOpts().AlignedAllocation &&
24302430
Alignment > NewAlignment)};
24312431

@@ -3514,7 +3514,7 @@ FunctionDecl *Sema::FindUsualDeallocationFunction(
35143514

35153515
LookupResult FoundDelete(*this, Name, StartLoc, LookupOrdinaryName);
35163516
DeallocLookupMode LookupMode =
3517-
isTypeAwareAllocation(allocationModeInCurrentContext())
3517+
getLangOpts().TypeAwareAllocators
35183518
? DeallocLookupMode::OptionallyTyped
35193519
: DeallocLookupMode::Untyped;
35203520
LookupGlobalDeallocationFunctions(*this, StartLoc, FoundDelete, LookupMode,
@@ -3544,7 +3544,8 @@ FunctionDecl *Sema::FindDeallocationFunctionForDestructor(SourceLocation Loc,
35443544

35453545
FunctionDecl *OperatorDelete = nullptr;
35463546
QualType DeallocType = Context.getRecordType(RD);
3547-
ImplicitDeallocationParameters IDP = {allocationModeInCurrentContext(),
3547+
ImplicitDeallocationParameters IDP = {
3548+
typeAwareAllocationModeFromBool(getLangOpts().TypeAwareAllocators),
35483549
AlignedAllocationMode::No,
35493550
SizedDeallocationMode::No};
35503551

@@ -4017,7 +4018,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
40174018
ArrayForm ? OO_Array_Delete : OO_Delete);
40184019

40194020
if (PointeeRD) {
4020-
ImplicitDeallocationParameters IDP = {allocationModeInCurrentContext(),
4021+
ImplicitDeallocationParameters IDP = {
4022+
typeAwareAllocationModeFromBool(getLangOpts().TypeAwareAllocators),
40214023
AlignedAllocationMode::No,
40224024
SizedDeallocationMode::No};
40234025
if (!UseGlobal &&
@@ -4071,7 +4073,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
40714073

40724074
// Look for a global declaration.
40734075
ImplicitDeallocationParameters IDP = {
4074-
allocationModeInCurrentContext(),
4076+
typeAwareAllocationModeFromBool(getLangOpts().TypeAwareAllocators),
40754077
alignedAllocationModeFromBool(Overaligned),
40764078
sizedDeallocationModeFromBool(CanProvideSize)};
40774079
OperatorDelete =

0 commit comments

Comments
 (0)