[clang] Improve stack usage to increase template instantiation depth (PR #88546)
Aaron Ballman via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 12 10:58:59 PDT 2024
https://github.com/AaronBallman created https://github.com/llvm/llvm-project/pull/88546
We were crashing due to stack exhaustion on rather reasonable C++ template code. After some investigation, I found that we have a stack-allocated object that was huge: `InitializationSequence` was 7016 bytes. This caused an overflow with deep call stacks in initialization code.
With these change, `InitializationSequence` is now 248 bytes.
With the original code, testing RelWithDebInfo on Windows 10, all the tests in SemaCXX took about 6s 800ms. The max template depth I could reach on my machine using the code in the issue was 708. After that, I would get `-Wstack-exhausted` warnings until crashing at 976 instantiations.
With these changes on the same machine, all the tests in SemaCXX took about 6s 500ms. The max template depth I could reach was 1492. After that, I would get `-Wstack-exhausted` warnings until crashing at 2898 instantiations.
Fixes #88330
>From b3c53b13181d0ae9897a79aa5dff59b90b8025fd Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aaron at aaronballman.com>
Date: Fri, 12 Apr 2024 12:48:09 -0400
Subject: [PATCH 1/2] More efficient stack usage; NFC
---
clang/include/clang/Sema/Overload.h | 69 +++++++++--------------------
clang/lib/Sema/SemaCodeComplete.cpp | 6 ++-
clang/lib/Sema/SemaDecl.cpp | 3 +-
clang/lib/Sema/SemaDeclCXX.cpp | 5 ++-
clang/lib/Sema/SemaExpr.cpp | 7 +--
clang/lib/Sema/SemaExprCXX.cpp | 6 +--
clang/lib/Sema/SemaInit.cpp | 11 +++--
clang/lib/Sema/SemaLookup.cpp | 2 +-
clang/lib/Sema/SemaOverload.cpp | 53 +++++++++++++---------
clang/lib/Sema/SemaStmt.cpp | 2 +-
10 files changed, 78 insertions(+), 86 deletions(-)
diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h
index 76311b00d2fc58..40800c7e1af381 100644
--- a/clang/include/clang/Sema/Overload.h
+++ b/clang/include/clang/Sema/Overload.h
@@ -874,7 +874,8 @@ class Sema;
ConversionFixItGenerator Fix;
/// Viable - True to indicate that this overload candidate is viable.
- bool Viable : 1;
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned Viable : 1;
/// Whether this candidate is the best viable function, or tied for being
/// the best viable function.
@@ -883,12 +884,14 @@ class Sema;
/// was part of the ambiguity kernel: the minimal non-empty set of viable
/// candidates such that all elements of the ambiguity kernel are better
/// than all viable candidates not in the ambiguity kernel.
- bool Best : 1;
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned Best : 1;
/// IsSurrogate - True to indicate that this candidate is a
/// surrogate for a conversion to a function pointer or reference
/// (C++ [over.call.object]).
- bool IsSurrogate : 1;
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned IsSurrogate : 1;
/// IgnoreObjectArgument - True to indicate that the first
/// argument's conversion, which for this function represents the
@@ -897,18 +900,20 @@ class Sema;
/// implicit object argument is just a placeholder) or a
/// non-static member function when the call doesn't have an
/// object argument.
- bool IgnoreObjectArgument : 1;
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned IgnoreObjectArgument : 1;
/// True if the candidate was found using ADL.
- CallExpr::ADLCallKind IsADLCandidate : 1;
+ LLVM_PREFERRED_TYPE(CallExpr::ADLCallKind)
+ unsigned IsADLCandidate : 1;
/// Whether this is a rewritten candidate, and if so, of what kind?
LLVM_PREFERRED_TYPE(OverloadCandidateRewriteKind)
unsigned RewriteKind : 2;
/// FailureKind - The reason why this candidate is not viable.
- /// Actually an OverloadFailureKind.
- unsigned char FailureKind;
+ LLVM_PREFERRED_TYPE(OverloadFailureKind)
+ unsigned FailureKind : 5;
/// The number of call arguments that were explicitly provided,
/// to be used while performing partial ordering of function templates.
@@ -972,7 +977,9 @@ class Sema;
private:
friend class OverloadCandidateSet;
OverloadCandidate()
- : IsSurrogate(false), IsADLCandidate(CallExpr::NotADL), RewriteKind(CRK_None) {}
+ : IsSurrogate(false),
+ IsADLCandidate(static_cast<unsigned>(CallExpr::NotADL)),
+ RewriteKind(CRK_None) {}
};
/// OverloadCandidateSet - A set of overload candidates, used in C++
@@ -1070,57 +1077,25 @@ class Sema;
};
private:
- SmallVector<OverloadCandidate, 16> Candidates;
- llvm::SmallPtrSet<uintptr_t, 16> Functions;
-
- // Allocator for ConversionSequenceLists. We store the first few of these
- // inline to avoid allocation for small sets.
- llvm::BumpPtrAllocator SlabAllocator;
+ ASTContext &Ctx;
+ SmallVector<OverloadCandidate, 4> Candidates;
+ llvm::SmallPtrSet<uintptr_t, 4> Functions;
SourceLocation Loc;
CandidateSetKind Kind;
OperatorRewriteInfo RewriteInfo;
- constexpr static unsigned NumInlineBytes =
- 24 * sizeof(ImplicitConversionSequence);
- unsigned NumInlineBytesUsed = 0;
- alignas(void *) char InlineSpace[NumInlineBytes];
-
// Address space of the object being constructed.
LangAS DestAS = LangAS::Default;
- /// If we have space, allocates from inline storage. Otherwise, allocates
- /// from the slab allocator.
- /// FIXME: It would probably be nice to have a SmallBumpPtrAllocator
- /// instead.
- /// FIXME: Now that this only allocates ImplicitConversionSequences, do we
- /// want to un-generalize this?
- template <typename T>
- T *slabAllocate(unsigned N) {
- // It's simpler if this doesn't need to consider alignment.
- static_assert(alignof(T) == alignof(void *),
- "Only works for pointer-aligned types.");
- static_assert(std::is_trivial<T>::value ||
- std::is_same<ImplicitConversionSequence, T>::value,
- "Add destruction logic to OverloadCandidateSet::clear().");
-
- unsigned NBytes = sizeof(T) * N;
- if (NBytes > NumInlineBytes - NumInlineBytesUsed)
- return SlabAllocator.Allocate<T>(N);
- char *FreeSpaceStart = InlineSpace + NumInlineBytesUsed;
- assert(uintptr_t(FreeSpaceStart) % alignof(void *) == 0 &&
- "Misaligned storage!");
-
- NumInlineBytesUsed += NBytes;
- return reinterpret_cast<T *>(FreeSpaceStart);
- }
void destroyCandidates();
public:
- OverloadCandidateSet(SourceLocation Loc, CandidateSetKind CSK,
+ OverloadCandidateSet(ASTContext &Ctx, SourceLocation Loc,
+ CandidateSetKind CSK,
OperatorRewriteInfo RewriteInfo = {})
- : Loc(Loc), Kind(CSK), RewriteInfo(RewriteInfo) {}
+ : Ctx(Ctx), Loc(Loc), Kind(CSK), RewriteInfo(RewriteInfo) {}
OverloadCandidateSet(const OverloadCandidateSet &) = delete;
OverloadCandidateSet &operator=(const OverloadCandidateSet &) = delete;
~OverloadCandidateSet() { destroyCandidates(); }
@@ -1163,7 +1138,7 @@ class Sema;
ConversionSequenceList
allocateConversionSequences(unsigned NumConversions) {
ImplicitConversionSequence *Conversions =
- slabAllocate<ImplicitConversionSequence>(NumConversions);
+ Ctx.Allocate<ImplicitConversionSequence>(NumConversions);
// Construct the new objects.
for (unsigned I = 0; I != NumConversions; ++I)
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index c335017f243eb2..c561fdc93ba00c 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -6210,7 +6210,8 @@ QualType Sema::ProduceCallSignatureHelp(Expr *Fn, ArrayRef<Expr *> Args,
Expr *NakedFn = Fn->IgnoreParenCasts();
// Build an overload candidate set based on the functions we find.
SourceLocation Loc = Fn->getExprLoc();
- OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
+ OverloadCandidateSet CandidateSet(Context, Loc,
+ OverloadCandidateSet::CSK_Normal);
if (auto ULE = dyn_cast<UnresolvedLookupExpr>(NakedFn)) {
AddOverloadedCallCandidates(ULE, ArgsWithoutDependentTypes, CandidateSet,
@@ -6411,7 +6412,8 @@ QualType Sema::ProduceConstructorSignatureHelp(QualType Type,
// FIXME: Provide support for variadic template constructors.
if (CRD) {
- OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
+ OverloadCandidateSet CandidateSet(Context, Loc,
+ OverloadCandidateSet::CSK_Normal);
for (NamedDecl *C : LookupConstructors(CRD)) {
if (auto *FD = dyn_cast<FunctionDecl>(C)) {
// FIXME: we can't yet provide correct signature help for initializer
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 720e56692359b3..de22408cd16a03 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -19073,7 +19073,8 @@ static void ComputeSelectedDestructor(Sema &S, CXXRecordDecl *Record) {
}
SourceLocation Loc = Record->getLocation();
- OverloadCandidateSet OCS(Loc, OverloadCandidateSet::CSK_Normal);
+ OverloadCandidateSet OCS(S.getASTContext(), Loc,
+ OverloadCandidateSet::CSK_Normal);
for (auto *Decl : Record->decls()) {
if (auto *DD = dyn_cast<CXXDestructorDecl>(Decl)) {
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 51c14443d2d8f1..df6381e2cdf3bc 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -8198,7 +8198,8 @@ class DefaultedComparisonAnalyzer
// we've already found there is no viable 'operator<=>' candidate (and are
// considering synthesizing a '<=>' from '==' and '<').
OverloadCandidateSet CandidateSet(
- FD->getLocation(), OverloadCandidateSet::CSK_Operator,
+ S.getASTContext(), FD->getLocation(),
+ OverloadCandidateSet::CSK_Operator,
OverloadCandidateSet::OperatorRewriteInfo(
OO, FD->getLocation(),
/*AllowRewrittenCandidates=*/!SpaceshipCandidates));
@@ -17409,7 +17410,7 @@ bool Sema::EvaluateStaticAssertMessageAsString(Expr *Message,
LookupResult MemberLookup(*this, DN, Loc, Sema::LookupMemberName);
LookupQualifiedName(MemberLookup, RD);
Empty = MemberLookup.empty();
- OverloadCandidateSet Candidates(MemberLookup.getNameLoc(),
+ OverloadCandidateSet Candidates(Context, MemberLookup.getNameLoc(),
OverloadCandidateSet::CSK_Normal);
if (MemberLookup.empty())
return std::nullopt;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index b294d2bd9f53f2..c14d484378a866 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2500,7 +2500,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
// If there's a best viable function among the results, only mention
// that one in the notes.
- OverloadCandidateSet Candidates(R.getNameLoc(),
+ OverloadCandidateSet Candidates(Context, R.getNameLoc(),
OverloadCandidateSet::CSK_Normal);
AddOverloadedCallCandidates(R, ExplicitTemplateArgs, Args, Candidates);
OverloadCandidateSet::iterator Best;
@@ -2548,7 +2548,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
NamedDecl *ND = Corrected.getFoundDecl();
if (ND) {
if (Corrected.isOverloaded()) {
- OverloadCandidateSet OCS(R.getNameLoc(),
+ OverloadCandidateSet OCS(Context, R.getNameLoc(),
OverloadCandidateSet::CSK_Normal);
OverloadCandidateSet::iterator Best;
for (NamedDecl *CD : Corrected) {
@@ -6501,7 +6501,8 @@ static TypoCorrection TryTypoCorrectionForCall(Sema &S, Expr *Fn,
Sema::CTK_ErrorRecovery)) {
if (NamedDecl *ND = Corrected.getFoundDecl()) {
if (Corrected.isOverloaded()) {
- OverloadCandidateSet OCS(NameLoc, OverloadCandidateSet::CSK_Normal);
+ OverloadCandidateSet OCS(S.getASTContext(), NameLoc,
+ OverloadCandidateSet::CSK_Normal);
OverloadCandidateSet::iterator Best;
for (NamedDecl *CD : Corrected) {
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(CD))
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index ce9d5c26e21858..0b7bda6d5f2f25 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -2586,7 +2586,7 @@ static bool resolveAllocationOverload(
Sema &S, LookupResult &R, SourceRange Range, SmallVectorImpl<Expr *> &Args,
bool &PassAlignment, FunctionDecl *&Operator,
OverloadCandidateSet *AlignedCandidates, Expr *AlignArg, bool Diagnose) {
- OverloadCandidateSet Candidates(R.getNameLoc(),
+ OverloadCandidateSet Candidates(S.getASTContext(), R.getNameLoc(),
OverloadCandidateSet::CSK_Normal);
for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end();
Alloc != AllocEnd; ++Alloc) {
@@ -3919,7 +3919,7 @@ static bool resolveBuiltinNewDeleteOverload(Sema &S, CallExpr *TheCall,
R.suppressDiagnostics();
SmallVector<Expr *, 8> Args(TheCall->arguments());
- OverloadCandidateSet Candidates(R.getNameLoc(),
+ OverloadCandidateSet Candidates(S.getASTContext(), R.getNameLoc(),
OverloadCandidateSet::CSK_Normal);
for (LookupResult::iterator FnOvl = R.begin(), FnOvlEnd = R.end();
FnOvl != FnOvlEnd; ++FnOvl) {
@@ -6488,7 +6488,7 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
static bool FindConditionalOverload(Sema &Self, ExprResult &LHS, ExprResult &RHS,
SourceLocation QuestionLoc) {
Expr *Args[2] = { LHS.get(), RHS.get() };
- OverloadCandidateSet CandidateSet(QuestionLoc,
+ OverloadCandidateSet CandidateSet(Self.getASTContext(), QuestionLoc,
OverloadCandidateSet::CSK_Operator);
Self.AddBuiltinOperatorCandidates(OO_Conditional, QuestionLoc, Args,
CandidateSet);
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 6b8ce0f633a3ea..86d2d4c530679a 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -6114,7 +6114,8 @@ InitializationSequence::InitializationSequence(
Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind,
MultiExprArg Args, bool TopLevelOfInitList, bool TreatUnavailableAsInvalid)
: FailedOverloadResult(OR_Success),
- FailedCandidateSet(Kind.getLocation(), OverloadCandidateSet::CSK_Normal) {
+ FailedCandidateSet(S.getASTContext(), Kind.getLocation(),
+ OverloadCandidateSet::CSK_Normal) {
InitializeFrom(S, Entity, Kind, Args, TopLevelOfInitList,
TreatUnavailableAsInvalid);
}
@@ -6808,7 +6809,8 @@ static ExprResult CopyObject(Sema &S,
// Perform overload resolution using the class's constructors. Per
// C++11 [dcl.init]p16, second bullet for class types, this initialization
// is direct-initialization.
- OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
+ OverloadCandidateSet CandidateSet(S.getASTContext(), Loc,
+ OverloadCandidateSet::CSK_Normal);
DeclContext::lookup_result Ctors = S.LookupConstructors(Class);
OverloadCandidateSet::iterator Best;
@@ -6949,7 +6951,8 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S,
return;
// Find constructors which would have been considered.
- OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
+ OverloadCandidateSet CandidateSet(S.getASTContext(), Loc,
+ OverloadCandidateSet::CSK_Normal);
DeclContext::lookup_result Ctors =
S.LookupConstructors(cast<CXXRecordDecl>(Record->getDecl()));
@@ -10818,7 +10821,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
//
// Since we know we're initializing a class type of a type unrelated to that
// of the initializer, this reduces to something fairly reasonable.
- OverloadCandidateSet Candidates(Kind.getLocation(),
+ OverloadCandidateSet Candidates(Context, Kind.getLocation(),
OverloadCandidateSet::CSK_Normal);
OverloadCandidateSet::iterator Best;
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index d65f52b8efe81f..eedba5c1394770 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -3481,7 +3481,7 @@ Sema::LookupSpecialMember(CXXRecordDecl *RD, CXXSpecialMemberKind SM,
// Now we perform lookup on the name we computed earlier and do overload
// resolution. Lookup is only performed directly into the class since there
// will always be a (possibly implicit) declaration to shadow any others.
- OverloadCandidateSet OCS(LookupLoc, OverloadCandidateSet::CSK_Normal);
+ OverloadCandidateSet OCS(Context, LookupLoc, OverloadCandidateSet::CSK_Normal);
DeclContext::lookup_result R = RD->lookup(Name);
if (R.empty()) {
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index e1155dc2d5d285..e94db8aee144b3 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -1057,7 +1057,8 @@ bool OverloadCandidateSet::OperatorRewriteInfo::shouldAddReversed(
void OverloadCandidateSet::destroyCandidates() {
for (iterator i = begin(), e = end(); i != e; ++i) {
for (auto &C : i->Conversions)
- C.~ImplicitConversionSequence();
+ C.~ImplicitConversionSequence();
+ Ctx.Deallocate(i->Conversions.begin());
if (!i->Viable && i->FailureKind == ovl_fail_bad_deduction)
i->DeductionFailure.Destroy();
}
@@ -1065,8 +1066,6 @@ void OverloadCandidateSet::destroyCandidates() {
void OverloadCandidateSet::clear(CandidateSetKind CSK) {
destroyCandidates();
- SlabAllocator.Reset();
- NumInlineBytesUsed = 0;
Candidates.clear();
Functions.clear();
Kind = CSK;
@@ -1603,7 +1602,7 @@ TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
}
// Attempt user-defined conversion.
- OverloadCandidateSet Conversions(From->getExprLoc(),
+ OverloadCandidateSet Conversions(S.getASTContext(), From->getExprLoc(),
OverloadCandidateSet::CSK_Normal);
switch (IsUserDefinedConversion(S, From, ToType, ICS.UserDefined,
Conversions, AllowExplicit,
@@ -4040,7 +4039,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
bool
Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) {
ImplicitConversionSequence ICS;
- OverloadCandidateSet CandidateSet(From->getExprLoc(),
+ OverloadCandidateSet CandidateSet(Context, From->getExprLoc(),
OverloadCandidateSet::CSK_Normal);
OverloadingResult OvResult =
IsUserDefinedConversion(*this, From, ToType, ICS.UserDefined,
@@ -5032,7 +5031,8 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
auto *T2RecordDecl = cast<CXXRecordDecl>(T2->castAs<RecordType>()->getDecl());
OverloadCandidateSet CandidateSet(
- DeclLoc, OverloadCandidateSet::CSK_InitByUserDefinedConversion);
+ S.getASTContext(), DeclLoc,
+ OverloadCandidateSet::CSK_InitByUserDefinedConversion);
const auto &Conversions = T2RecordDecl->getVisibleConversionFunctions();
for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) {
NamedDecl *D = *I;
@@ -6786,7 +6786,8 @@ ExprResult Sema::PerformContextualImplicitConversion(
// If one unique T is found:
// First, build a candidate set from the previously recorded
// potentially viable conversions.
- OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
+ OverloadCandidateSet CandidateSet(Context, Loc,
+ OverloadCandidateSet::CSK_Normal);
collectViableConversionCandidates(*this, From, ToType, ViableConversions,
CandidateSet);
@@ -6982,7 +6983,7 @@ void Sema::AddOverloadCandidate(
Candidate.RewriteKind =
CandidateSet.getRewriteInfo().getRewriteKind(Function, PO);
Candidate.IsSurrogate = false;
- Candidate.IsADLCandidate = IsADLCandidate;
+ Candidate.IsADLCandidate = static_cast<unsigned>(IsADLCandidate);
Candidate.IgnoreObjectArgument = false;
Candidate.ExplicitCallArguments = Args.size();
@@ -7813,7 +7814,7 @@ void Sema::AddTemplateOverloadCandidate(
Candidate.RewriteKind =
CandidateSet.getRewriteInfo().getRewriteKind(Candidate.Function, PO);
Candidate.IsSurrogate = false;
- Candidate.IsADLCandidate = IsADLCandidate;
+ Candidate.IsADLCandidate = static_cast<unsigned>(IsADLCandidate);
// Ignore the object argument if there is one, since we don't have an object
// type.
Candidate.IgnoreObjectArgument =
@@ -13770,7 +13771,7 @@ static bool DiagnoseTwoPhaseLookup(
if (!R.empty()) {
R.suppressDiagnostics();
- OverloadCandidateSet Candidates(FnLoc, CSK);
+ OverloadCandidateSet Candidates(SemaRef.getASTContext(), FnLoc, CSK);
SemaRef.AddOverloadedCallCandidates(R, ExplicitTemplateArgs, Args,
Candidates);
@@ -14123,7 +14124,8 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
return ExprError();
return SemaRef.BuildResolvedCallExpr(
Res.get(), FDecl, LParenLoc, Args, RParenLoc, ExecConfig,
- /*IsExecConfig=*/false, (*Best)->IsADLCandidate);
+ /*IsExecConfig=*/false,
+ static_cast<CallExpr::ADLCallKind>((*Best)->IsADLCandidate));
}
case OR_No_Viable_Function: {
@@ -14184,7 +14186,8 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
return ExprError();
return SemaRef.BuildResolvedCallExpr(
Res.get(), FDecl, LParenLoc, Args, RParenLoc, ExecConfig,
- /*IsExecConfig=*/false, (*Best)->IsADLCandidate);
+ /*IsExecConfig=*/false,
+ static_cast<CallExpr::ADLCallKind>((*Best)->IsADLCandidate));
}
}
@@ -14220,7 +14223,7 @@ ExprResult Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn,
Expr *ExecConfig,
bool AllowTypoCorrection,
bool CalleesAddressIsTaken) {
- OverloadCandidateSet CandidateSet(Fn->getExprLoc(),
+ OverloadCandidateSet CandidateSet(Context, Fn->getExprLoc(),
OverloadCandidateSet::CSK_Normal);
ExprResult result;
@@ -14411,7 +14414,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
}
// Build an empty overload set.
- OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator);
+ OverloadCandidateSet CandidateSet(Context, OpLoc,
+ OverloadCandidateSet::CSK_Operator);
// Add the candidates from the given function set.
AddNonMemberOperatorCandidates(Fns, ArgsArray, CandidateSet);
@@ -14484,7 +14488,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
Args[0] = Input;
CallExpr *TheCall = CXXOperatorCallExpr::Create(
Context, Op, FnExpr.get(), ArgsArray, ResultTy, VK, OpLoc,
- CurFPFeatureOverrides(), Best->IsADLCandidate);
+ CurFPFeatureOverrides(),
+ static_cast<CallExpr::ADLCallKind>(Best->IsADLCandidate));
if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, FnDecl))
return ExprError();
@@ -14718,7 +14723,8 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
// Build the overload set.
- OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator,
+ OverloadCandidateSet CandidateSet(Context, OpLoc,
+ OverloadCandidateSet::CSK_Operator,
OverloadCandidateSet::OperatorRewriteInfo(
Op, OpLoc, AllowRewrittenCandidates));
if (DefaultedFn)
@@ -14898,7 +14904,8 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// members; CodeGen should take care not to emit the this pointer.
TheCall = CXXOperatorCallExpr::Create(
Context, ChosenOp, FnExpr.get(), Args, ResultTy, VK, OpLoc,
- CurFPFeatureOverrides(), Best->IsADLCandidate);
+ CurFPFeatureOverrides(),
+ static_cast<CallExpr::ADLCallKind>(Best->IsADLCandidate));
if (const auto *Method = dyn_cast<CXXMethodDecl>(FnDecl);
Method && Method->isImplicitObjectMemberFunction()) {
@@ -15267,7 +15274,8 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
return ExprError();
}
// Build an empty overload set.
- OverloadCandidateSet CandidateSet(LLoc, OverloadCandidateSet::CSK_Operator);
+ OverloadCandidateSet CandidateSet(Context, LLoc,
+ OverloadCandidateSet::CSK_Operator);
// Subscript can only be overloaded as a member function.
@@ -15521,7 +15529,7 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
: UnresExpr->getBase()->Classify(Context);
// Add overload candidates
- OverloadCandidateSet CandidateSet(UnresExpr->getMemberLoc(),
+ OverloadCandidateSet CandidateSet(Context, UnresExpr->getMemberLoc(),
OverloadCandidateSet::CSK_Normal);
// FIXME: avoid copy.
@@ -15771,7 +15779,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
// operators of T. The function call operators of T are obtained by
// ordinary lookup of the name operator() in the context of
// (E).operator().
- OverloadCandidateSet CandidateSet(LParenLoc,
+ OverloadCandidateSet CandidateSet(Context, LParenLoc,
OverloadCandidateSet::CSK_Operator);
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Call);
@@ -16038,7 +16046,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
// overload resolution mechanism (13.3).
DeclarationName OpName =
Context.DeclarationNames.getCXXOperatorName(OO_Arrow);
- OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Operator);
+ OverloadCandidateSet CandidateSet(Context, Loc,
+ OverloadCandidateSet::CSK_Operator);
if (RequireCompleteType(Loc, Base->getType(),
diag::err_typecheck_incomplete_tag, Base))
@@ -16154,7 +16163,7 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
TemplateArgumentListInfo *TemplateArgs) {
SourceLocation UDSuffixLoc = SuffixInfo.getCXXLiteralOperatorNameLoc();
- OverloadCandidateSet CandidateSet(UDSuffixLoc,
+ OverloadCandidateSet CandidateSet(Context, UDSuffixLoc,
OverloadCandidateSet::CSK_Normal);
AddNonMemberOperatorCandidates(R.asUnresolvedSet(), Args, CandidateSet,
TemplateArgs);
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 1c2f6120f6218b..8a6e0c58684cf4 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -2944,7 +2944,7 @@ StmtResult Sema::BuildCXXForRangeStmt(
return StmtError();
}
} else {
- OverloadCandidateSet CandidateSet(RangeLoc,
+ OverloadCandidateSet CandidateSet(Context, RangeLoc,
OverloadCandidateSet::CSK_Normal);
BeginEndFunction BEFFailure;
ForRangeStatus RangeStatus = BuildNonArrayForRange(
>From a89ea6c2b409d41be25f52f32c8523bc06734847 Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aaron at aaronballman.com>
Date: Fri, 12 Apr 2024 13:28:09 -0400
Subject: [PATCH 2/2] Further improvements to stack usage
---
clang/include/clang/Sema/Initialization.h | 6 ++++--
clang/lib/Sema/SemaInit.cpp | 24 ++++++++++++-----------
2 files changed, 17 insertions(+), 13 deletions(-)
diff --git a/clang/include/clang/Sema/Initialization.h b/clang/include/clang/Sema/Initialization.h
index 2072cd8d1c3ef8..f41ca97f030066 100644
--- a/clang/include/clang/Sema/Initialization.h
+++ b/clang/include/clang/Sema/Initialization.h
@@ -1134,7 +1134,7 @@ class InitializationSequence {
OverloadingResult FailedOverloadResult;
/// The candidate set created when initialization failed.
- OverloadCandidateSet FailedCandidateSet;
+ OverloadCandidateSet *FailedCandidateSet;
/// The incomplete type that caused a failure.
QualType FailedIncompleteType;
@@ -1403,7 +1403,9 @@ class InitializationSequence {
/// Retrieve a reference to the candidate set when overload
/// resolution fails.
OverloadCandidateSet &getFailedCandidateSet() {
- return FailedCandidateSet;
+ assert(FailedCandidateSet &&
+ "this should have been allocated in the constructor!");
+ return *FailedCandidateSet;
}
/// Get the overloading result, for when the initialization
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 86d2d4c530679a..883bdece74daf1 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -6113,9 +6113,10 @@ static bool TryOCLZeroOpaqueTypeInitialization(Sema &S,
InitializationSequence::InitializationSequence(
Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind,
MultiExprArg Args, bool TopLevelOfInitList, bool TreatUnavailableAsInvalid)
- : FailedOverloadResult(OR_Success),
- FailedCandidateSet(S.getASTContext(), Kind.getLocation(),
- OverloadCandidateSet::CSK_Normal) {
+ : FailedOverloadResult(OR_Success), FailedCandidateSet(nullptr) {
+ FailedCandidateSet = S.getASTContext().Allocate<OverloadCandidateSet>();
+ FailedCandidateSet = new (FailedCandidateSet) OverloadCandidateSet(
+ S.getASTContext(), Kind.getLocation(), OverloadCandidateSet::CSK_Normal);
InitializeFrom(S, Entity, Kind, Args, TopLevelOfInitList,
TreatUnavailableAsInvalid);
}
@@ -9738,7 +9739,7 @@ bool InitializationSequence::Diagnose(Sema &S,
switch (FailedOverloadResult) {
case OR_Ambiguous:
- FailedCandidateSet.NoteCandidates(
+ FailedCandidateSet->NoteCandidates(
PartialDiagnosticAt(
Kind.getLocation(),
Failure == FK_UserConversionOverloadFailed
@@ -9752,7 +9753,8 @@ bool InitializationSequence::Diagnose(Sema &S,
break;
case OR_No_Viable_Function: {
- auto Cands = FailedCandidateSet.CompleteCandidates(S, OCD_AllCandidates, Args);
+ auto Cands =
+ FailedCandidateSet->CompleteCandidates(S, OCD_AllCandidates, Args);
if (!S.RequireCompleteType(Kind.getLocation(),
DestType.getNonReferenceType(),
diag::err_typecheck_nonviable_condition_incomplete,
@@ -9762,7 +9764,7 @@ bool InitializationSequence::Diagnose(Sema &S,
<< OnlyArg->getType() << Args[0]->getSourceRange()
<< DestType.getNonReferenceType();
- FailedCandidateSet.NoteCandidates(S, Args, Cands);
+ FailedCandidateSet->NoteCandidates(S, Args, Cands);
break;
}
case OR_Deleted: {
@@ -9771,7 +9773,7 @@ bool InitializationSequence::Diagnose(Sema &S,
<< Args[0]->getSourceRange();
OverloadCandidateSet::iterator Best;
OverloadingResult Ovl
- = FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best);
+ = FailedCandidateSet->BestViableFunction(S, Kind.getLocation(), Best);
if (Ovl == OR_Deleted) {
S.NoteDeletedFunction(Best->Function);
} else {
@@ -9949,7 +9951,7 @@ bool InitializationSequence::Diagnose(Sema &S,
// bad.
switch (FailedOverloadResult) {
case OR_Ambiguous:
- FailedCandidateSet.NoteCandidates(
+ FailedCandidateSet->NoteCandidates(
PartialDiagnosticAt(Kind.getLocation(),
S.PDiag(diag::err_ovl_ambiguous_init)
<< DestType << ArgsRange),
@@ -10003,7 +10005,7 @@ bool InitializationSequence::Diagnose(Sema &S,
break;
}
- FailedCandidateSet.NoteCandidates(
+ FailedCandidateSet->NoteCandidates(
PartialDiagnosticAt(
Kind.getLocation(),
S.PDiag(diag::err_ovl_no_viable_function_in_init)
@@ -10014,7 +10016,7 @@ bool InitializationSequence::Diagnose(Sema &S,
case OR_Deleted: {
OverloadCandidateSet::iterator Best;
OverloadingResult Ovl
- = FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best);
+ = FailedCandidateSet->BestViableFunction(S, Kind.getLocation(), Best);
if (Ovl != OR_Deleted) {
S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init)
<< DestType << ArgsRange;
@@ -10091,7 +10093,7 @@ bool InitializationSequence::Diagnose(Sema &S,
<< Args[0]->getSourceRange();
OverloadCandidateSet::iterator Best;
OverloadingResult Ovl
- = FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best);
+ = FailedCandidateSet->BestViableFunction(S, Kind.getLocation(), Best);
(void)Ovl;
assert(Ovl == OR_Success && "Inconsistent overload resolution");
CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function);
More information about the cfe-commits
mailing list