Skip to content

Commit 1dbada8

Browse files
committed
[clang] SFINAE context refactor
This teases the SFINAE handling bits out of the CodeSynthesisContext, and moves that functionality into SFINAETrap and a new class. There is also a small performance benefit here:
1 parent 63ca2fd commit 1dbada8

26 files changed

+284
-409
lines changed

clang-tools-extra/clang-include-fixer/IncludeFixer.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ static bool addDiagnosticsForContext(TypoCorrection &Correction,
149149
bool IncludeFixerSemaSource::MaybeDiagnoseMissingCompleteType(
150150
clang::SourceLocation Loc, clang::QualType T) {
151151
// Ignore spurious callbacks from SFINAE contexts.
152-
if (CI->getSema().isSFINAEContext())
152+
if (CI->getSema().getSFINAEContext())
153153
return false;
154154

155155
clang::ASTContext &context = CI->getASTContext();
@@ -186,7 +186,7 @@ clang::TypoCorrection IncludeFixerSemaSource::CorrectTypo(
186186
CorrectionCandidateCallback &CCC, DeclContext *MemberContext,
187187
bool EnteringContext, const ObjCObjectPointerType *OPT) {
188188
// Ignore spurious callbacks from SFINAE contexts.
189-
if (CI->getSema().isSFINAEContext())
189+
if (CI->getSema().getSFINAEContext())
190190
return clang::TypoCorrection();
191191

192192
// We currently ignore the unidentified symbol which is not from the

clang-tools-extra/clangd/IncludeFixer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ class IncludeFixer::UnresolvedNameRecorder : public ExternalSemaSource {
506506
const ObjCObjectPointerType *OPT) override {
507507
dlog("CorrectTypo: {0}", Typo.getAsString());
508508
assert(SemaPtr && "Sema must have been set.");
509-
if (SemaPtr->isSFINAEContext())
509+
if (SemaPtr->getSFINAEContext())
510510
return TypoCorrection();
511511
if (!isInsideMainFile(Typo.getLoc(), SemaPtr->SourceMgr))
512512
return clang::TypoCorrection();

clang/include/clang/Sema/Sema.h

Lines changed: 56 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -11318,9 +11318,6 @@ class Sema final : public SemaBase {
1131811318
InventedParameterInfos.end());
1131911319
}
1132011320

11321-
/// The number of SFINAE diagnostics that have been trapped.
11322-
unsigned NumSFINAEErrors;
11323-
1132411321
ArrayRef<sema::FunctionScopeInfo *> getFunctionScopes() const {
1132511322
return llvm::ArrayRef(FunctionScopes.begin() + FunctionScopesStart,
1132611323
FunctionScopes.end());
@@ -12398,45 +12395,65 @@ class Sema final : public SemaBase {
1239812395
/// failures rather than hard errors.
1239912396
bool AccessCheckingSFINAE;
1240012397

12398+
class SFINAETrap;
12399+
12400+
struct SFINAEContextBase {
12401+
SFINAEContextBase(Sema &S, SFINAETrap *Cur)
12402+
: S(S), Prev(std::exchange(S.CurrentSFINAEContext, Cur)) {}
12403+
12404+
protected:
12405+
Sema &S;
12406+
~SFINAEContextBase() { S.CurrentSFINAEContext = Prev; }
12407+
12408+
private:
12409+
SFINAETrap *Prev;
12410+
};
12411+
12412+
struct NonSFINAEContext : SFINAEContextBase {
12413+
NonSFINAEContext(Sema &S) : SFINAEContextBase(S, nullptr) {}
12414+
};
12415+
1240112416
/// RAII class used to determine whether SFINAE has
1240212417
/// trapped any errors that occur during template argument
1240312418
/// deduction.
12404-
class SFINAETrap {
12405-
Sema &SemaRef;
12406-
unsigned PrevSFINAEErrors;
12407-
bool PrevInNonInstantiationSFINAEContext;
12408-
bool PrevAccessCheckingSFINAE;
12409-
bool PrevLastDiagnosticIgnored;
12419+
class SFINAETrap : SFINAEContextBase {
12420+
bool HasErrorOcurred = false;
12421+
bool PrevAccessCheckingSFINAE = S.AccessCheckingSFINAE;
12422+
bool PrevLastDiagnosticIgnored =
12423+
S.getDiagnostics().isLastDiagnosticIgnored();
12424+
sema::TemplateDeductionInfo *DeductionInfo = nullptr;
12425+
12426+
SFINAETrap(Sema &S, sema::TemplateDeductionInfo *Info,
12427+
bool ForValidityCheck)
12428+
: SFINAEContextBase(S, this), DeductionInfo(Info) {
12429+
S.AccessCheckingSFINAE = ForValidityCheck;
12430+
}
1241012431

1241112432
public:
1241212433
/// \param ForValidityCheck If true, discard all diagnostics (from the
1241312434
/// immediate context) instead of adding them to the currently active
1241412435
/// \ref TemplateDeductionInfo (as returned by \ref isSFINAEContext).
12415-
explicit SFINAETrap(Sema &SemaRef, bool ForValidityCheck = false)
12416-
: SemaRef(SemaRef), PrevSFINAEErrors(SemaRef.NumSFINAEErrors),
12417-
PrevInNonInstantiationSFINAEContext(
12418-
SemaRef.InNonInstantiationSFINAEContext),
12419-
PrevAccessCheckingSFINAE(SemaRef.AccessCheckingSFINAE),
12420-
PrevLastDiagnosticIgnored(
12421-
SemaRef.getDiagnostics().isLastDiagnosticIgnored()) {
12422-
if (ForValidityCheck || !SemaRef.isSFINAEContext())
12423-
SemaRef.InNonInstantiationSFINAEContext = true;
12424-
SemaRef.AccessCheckingSFINAE = ForValidityCheck;
12425-
}
12436+
explicit SFINAETrap(Sema &S, bool ForValidityCheck = false)
12437+
: SFINAETrap(S, /*Info=*/nullptr, ForValidityCheck) {}
12438+
12439+
SFINAETrap(Sema &S, sema::TemplateDeductionInfo &Info)
12440+
: SFINAETrap(S, &Info, /*ForValidityCheck=*/false) {}
1242612441

1242712442
~SFINAETrap() {
12428-
SemaRef.NumSFINAEErrors = PrevSFINAEErrors;
12429-
SemaRef.InNonInstantiationSFINAEContext =
12430-
PrevInNonInstantiationSFINAEContext;
12431-
SemaRef.AccessCheckingSFINAE = PrevAccessCheckingSFINAE;
12432-
SemaRef.getDiagnostics().setLastDiagnosticIgnored(
12433-
PrevLastDiagnosticIgnored);
12443+
S.AccessCheckingSFINAE = PrevAccessCheckingSFINAE;
12444+
S.getDiagnostics().setLastDiagnosticIgnored(PrevLastDiagnosticIgnored);
1243412445
}
1243512446

12436-
/// Determine whether any SFINAE errors have been trapped.
12437-
bool hasErrorOccurred() const {
12438-
return SemaRef.NumSFINAEErrors > PrevSFINAEErrors;
12447+
SFINAETrap(const SFINAETrap &) = delete;
12448+
SFINAETrap &operator=(const SFINAETrap &) = delete;
12449+
12450+
sema::TemplateDeductionInfo *getDeductionInfo() const {
12451+
return DeductionInfo;
1243912452
}
12453+
12454+
/// Determine whether any SFINAE errors have been trapped.
12455+
bool hasErrorOccurred() const { return HasErrorOcurred; }
12456+
void setErrorOccurred() { HasErrorOcurred = true; }
1244012457
};
1244112458

1244212459
/// RAII class used to indicate that we are performing provisional
@@ -13157,9 +13174,6 @@ class Sema final : public SemaBase {
1315713174
PartialOrderingTTP,
1315813175
} Kind;
1315913176

13160-
/// Was the enclosing context a non-instantiation SFINAE context?
13161-
bool SavedInNonInstantiationSFINAEContext;
13162-
1316313177
/// Whether we're substituting into constraints.
1316413178
bool InConstraintSubstitution;
1316513179

@@ -13204,22 +13218,15 @@ class Sema final : public SemaBase {
1320413218
return {TemplateArgs, NumTemplateArgs};
1320513219
}
1320613220

13207-
/// The template deduction info object associated with the
13208-
/// substitution or checking of explicit or deduced template arguments.
13209-
sema::TemplateDeductionInfo *DeductionInfo;
13210-
1321113221
/// The source range that covers the construct that cause
1321213222
/// the instantiation, e.g., the template-id that causes a class
1321313223
/// template instantiation.
1321413224
SourceRange InstantiationRange;
1321513225

1321613226
CodeSynthesisContext()
13217-
: Kind(TemplateInstantiation),
13218-
SavedInNonInstantiationSFINAEContext(false),
13219-
InConstraintSubstitution(false),
13227+
: Kind(TemplateInstantiation), InConstraintSubstitution(false),
1322013228
InParameterMappingSubstitution(false), Entity(nullptr),
13221-
Template(nullptr), TemplateArgs(nullptr), NumTemplateArgs(0),
13222-
DeductionInfo(nullptr) {}
13229+
Template(nullptr), TemplateArgs(nullptr), NumTemplateArgs(0) {}
1322313230

1322413231
/// Determines whether this template is an actual instantiation
1322513232
/// that should be counted toward the maximum instantiation depth.
@@ -13271,15 +13278,13 @@ class Sema final : public SemaBase {
1327113278
FunctionTemplateDecl *FunctionTemplate,
1327213279
ArrayRef<TemplateArgument> TemplateArgs,
1327313280
CodeSynthesisContext::SynthesisKind Kind,
13274-
sema::TemplateDeductionInfo &DeductionInfo,
1327513281
SourceRange InstantiationRange = SourceRange());
1327613282

1327713283
/// Note that we are instantiating as part of template
1327813284
/// argument deduction for a class template declaration.
1327913285
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
1328013286
TemplateDecl *Template,
1328113287
ArrayRef<TemplateArgument> TemplateArgs,
13282-
sema::TemplateDeductionInfo &DeductionInfo,
1328313288
SourceRange InstantiationRange = SourceRange());
1328413289

1328513290
/// Note that we are instantiating as part of template
@@ -13288,7 +13293,6 @@ class Sema final : public SemaBase {
1328813293
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
1328913294
ClassTemplatePartialSpecializationDecl *PartialSpec,
1329013295
ArrayRef<TemplateArgument> TemplateArgs,
13291-
sema::TemplateDeductionInfo &DeductionInfo,
1329213296
SourceRange InstantiationRange = SourceRange());
1329313297

1329413298
/// Note that we are instantiating as part of template
@@ -13297,7 +13301,6 @@ class Sema final : public SemaBase {
1329713301
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
1329813302
VarTemplatePartialSpecializationDecl *PartialSpec,
1329913303
ArrayRef<TemplateArgument> TemplateArgs,
13300-
sema::TemplateDeductionInfo &DeductionInfo,
1330113304
SourceRange InstantiationRange = SourceRange());
1330213305

1330313306
/// Note that we are instantiating a default argument for a function
@@ -13343,7 +13346,6 @@ class Sema final : public SemaBase {
1334313346
/// concept.
1334413347
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
1334513348
ConstraintSubstitution, NamedDecl *Template,
13346-
sema::TemplateDeductionInfo &DeductionInfo,
1334713349
SourceRange InstantiationRange);
1334813350

1334913351
struct ConstraintNormalization {};
@@ -13363,7 +13365,6 @@ class Sema final : public SemaBase {
1336313365
/// a requirement of a requires expression.
1336413366
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
1336513367
concepts::Requirement *Req,
13366-
sema::TemplateDeductionInfo &DeductionInfo,
1336713368
SourceRange InstantiationRange = SourceRange());
1336813369

1336913370
/// \brief Note that we are checking the satisfaction of the constraint
@@ -13375,7 +13376,6 @@ class Sema final : public SemaBase {
1337513376
/// \brief Note that we are checking a requires clause.
1337613377
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
1337713378
const RequiresExpr *E,
13378-
sema::TemplateDeductionInfo &DeductionInfo,
1337913379
SourceRange InstantiationRange);
1338013380

1338113381
struct BuildingDeductionGuidesTag {};
@@ -13408,8 +13408,7 @@ class Sema final : public SemaBase {
1340813408
SourceLocation PointOfInstantiation,
1340913409
SourceRange InstantiationRange, Decl *Entity,
1341013410
NamedDecl *Template = nullptr,
13411-
ArrayRef<TemplateArgument> TemplateArgs = {},
13412-
sema::TemplateDeductionInfo *DeductionInfo = nullptr);
13411+
ArrayRef<TemplateArgument> TemplateArgs = {});
1341313412

1341413413
InstantiatingTemplate(const InstantiatingTemplate &) = delete;
1341513414

@@ -13550,12 +13549,7 @@ class Sema final : public SemaBase {
1355013549
/// recent visible declaration of that namespace.
1355113550
llvm::DenseMap<NamedDecl *, NamedDecl *> VisibleNamespaceCache;
1355213551

13553-
/// Whether we are in a SFINAE context that is not associated with
13554-
/// template instantiation.
13555-
///
13556-
/// This is used when setting up a SFINAE trap (\c see SFINAETrap) outside
13557-
/// of a template instantiation or template argument deduction.
13558-
bool InNonInstantiationSFINAEContext;
13552+
SFINAETrap *CurrentSFINAEContext = nullptr;
1355913553

1356013554
/// The number of \p CodeSynthesisContexts that are not template
1356113555
/// instantiations and, therefore, should not be counted as part of the
@@ -13626,15 +13620,10 @@ class Sema final : public SemaBase {
1362613620
PrintInstantiationStack(getDefaultDiagFunc());
1362713621
}
1362813622

13629-
/// Determines whether we are currently in a context where
13630-
/// template argument substitution failures are not considered
13631-
/// errors.
13632-
///
13633-
/// \returns An empty \c Optional if we're not in a SFINAE context.
13634-
/// Otherwise, contains a pointer that, if non-NULL, contains the nearest
13635-
/// template-deduction context object, which can be used to capture
13636-
/// diagnostics that will be suppressed.
13637-
std::optional<sema::TemplateDeductionInfo *> isSFINAEContext() const;
13623+
/// Returns a pointer to the current SFINAE context, if any.
13624+
[[nodiscard]] SFINAETrap *getSFINAEContext() const {
13625+
return CurrentSFINAEContext;
13626+
}
1363813627

1363913628
/// Perform substitution on the type T with a given set of template
1364013629
/// arguments.
@@ -14646,7 +14635,8 @@ class Sema final : public SemaBase {
1464614635
ArrayRef<UnexpandedParameterPack> Unexpanded,
1464714636
const MultiLevelTemplateArgumentList &TemplateArgs,
1464814637
bool FailOnPackProducingTemplates, bool &ShouldExpand,
14649-
bool &RetainExpansion, UnsignedOrNone &NumExpansions);
14638+
bool &RetainExpansion, UnsignedOrNone &NumExpansions,
14639+
bool Diagnose = true);
1465014640

1465114641
/// Determine the number of arguments in the given pack expansion
1465214642
/// type.

clang/lib/Sema/Sema.cpp

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -322,10 +322,10 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
322322
static_cast<unsigned>(ComparisonCategoryType::Last) + 1),
323323
StdSourceLocationImplDecl(nullptr), CXXTypeInfoDecl(nullptr),
324324
GlobalNewDeleteDeclared(false), DisableTypoCorrection(false),
325-
TyposCorrected(0), IsBuildingRecoveryCallExpr(false), NumSFINAEErrors(0),
325+
TyposCorrected(0), IsBuildingRecoveryCallExpr(false),
326326
AccessCheckingSFINAE(false), CurrentInstantiationScope(nullptr),
327-
InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0),
328-
ArgPackSubstIndex(std::nullopt), SatisfactionCache(Context) {
327+
NonInstantiationEntries(0), ArgPackSubstIndex(std::nullopt),
328+
SatisfactionCache(Context) {
329329
assert(pp.TUKind == TUKind);
330330
TUScope = nullptr;
331331

@@ -671,7 +671,9 @@ void Sema::addExternalSource(IntrusiveRefCntPtr<ExternalSemaSource> E) {
671671

672672
void Sema::PrintStats() const {
673673
llvm::errs() << "\n*** Semantic Analysis Stats:\n";
674-
llvm::errs() << NumSFINAEErrors << " SFINAE diagnostics trapped.\n";
674+
if (SFINAETrap *Trap = getSFINAEContext())
675+
llvm::errs() << int(Trap->hasErrorOccurred())
676+
<< " SFINAE diagnostics trapped.\n";
675677

676678
BumpAlloc.PrintStats();
677679
AnalysisWarnings.PrintStats();
@@ -1678,7 +1680,8 @@ void Sema::EmitDiagnostic(unsigned DiagID, const DiagnosticBuilder &DB) {
16781680
// issue I am not seeing yet), then there should at least be a clarifying
16791681
// comment somewhere.
16801682
Diagnostic DiagInfo(&Diags, DB);
1681-
if (std::optional<TemplateDeductionInfo *> Info = isSFINAEContext()) {
1683+
if (SFINAETrap *Trap = getSFINAEContext()) {
1684+
sema::TemplateDeductionInfo *Info = Trap->getDeductionInfo();
16821685
switch (DiagnosticIDs::getDiagnosticSFINAEResponse(DiagInfo.getID())) {
16831686
case DiagnosticIDs::SFINAE_Report:
16841687
// We'll report the diagnostic below.
@@ -1687,14 +1690,14 @@ void Sema::EmitDiagnostic(unsigned DiagID, const DiagnosticBuilder &DB) {
16871690
case DiagnosticIDs::SFINAE_SubstitutionFailure:
16881691
// Count this failure so that we know that template argument deduction
16891692
// has failed.
1690-
++NumSFINAEErrors;
1693+
Trap->setErrorOccurred();
16911694

16921695
// Make a copy of this suppressed diagnostic and store it with the
16931696
// template-deduction information.
1694-
if (*Info && !(*Info)->hasSFINAEDiagnostic()) {
1695-
(*Info)->addSFINAEDiagnostic(DiagInfo.getLocation(),
1696-
PartialDiagnostic(DiagInfo, Context.getDiagAllocator()));
1697-
}
1697+
if (Info && !Info->hasSFINAEDiagnostic())
1698+
Info->addSFINAEDiagnostic(
1699+
DiagInfo.getLocation(),
1700+
PartialDiagnostic(DiagInfo, Context.getDiagAllocator()));
16981701

16991702
Diags.setLastDiagnosticIgnored(true);
17001703
return;
@@ -1710,14 +1713,14 @@ void Sema::EmitDiagnostic(unsigned DiagID, const DiagnosticBuilder &DB) {
17101713
SourceLocation Loc = DiagInfo.getLocation();
17111714

17121715
// Suppress this diagnostic.
1713-
++NumSFINAEErrors;
1716+
Trap->setErrorOccurred();
17141717

17151718
// Make a copy of this suppressed diagnostic and store it with the
17161719
// template-deduction information.
1717-
if (*Info && !(*Info)->hasSFINAEDiagnostic()) {
1718-
(*Info)->addSFINAEDiagnostic(DiagInfo.getLocation(),
1719-
PartialDiagnostic(DiagInfo, Context.getDiagAllocator()));
1720-
}
1720+
if (Info && !Info->hasSFINAEDiagnostic())
1721+
Info->addSFINAEDiagnostic(
1722+
DiagInfo.getLocation(),
1723+
PartialDiagnostic(DiagInfo, Context.getDiagAllocator()));
17211724

17221725
Diags.setLastDiagnosticIgnored(true);
17231726

@@ -1737,13 +1740,13 @@ void Sema::EmitDiagnostic(unsigned DiagID, const DiagnosticBuilder &DB) {
17371740
return;
17381741
// Make a copy of this suppressed diagnostic and store it with the
17391742
// template-deduction information;
1740-
if (*Info) {
1741-
(*Info)->addSuppressedDiagnostic(
1743+
if (Info) {
1744+
Info->addSuppressedDiagnostic(
17421745
DiagInfo.getLocation(),
17431746
PartialDiagnostic(DiagInfo, Context.getDiagAllocator()));
17441747
if (!Diags.getDiagnosticIDs()->isNote(DiagID))
17451748
PrintContextStack([Info](SourceLocation Loc, PartialDiagnostic PD) {
1746-
(*Info)->addSuppressedDiagnostic(Loc, std::move(PD));
1749+
Info->addSuppressedDiagnostic(Loc, std::move(PD));
17471750
});
17481751
}
17491752

@@ -2827,7 +2830,7 @@ bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD,
28272830

28282831
// If this is a SFINAE context, don't try anything that might trigger ADL
28292832
// prematurely.
2830-
if (!isSFINAEContext()) {
2833+
if (!getSFINAEContext()) {
28312834
QualType ZeroArgCallTy;
28322835
if (tryExprAsCall(*E.get(), ZeroArgCallTy, Overloads) &&
28332836
!ZeroArgCallTy.isNull() &&

clang/lib/Sema/SemaAMDGPU.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,8 @@ AMDGPUMaxNumWorkGroupsAttr *SemaAMDGPU::CreateAMDGPUMaxNumWorkGroupsAttr(
517517
const AttributeCommonInfo &CI, Expr *XExpr, Expr *YExpr, Expr *ZExpr) {
518518
ASTContext &Context = getASTContext();
519519
AMDGPUMaxNumWorkGroupsAttr TmpAttr(Context, CI, XExpr, YExpr, ZExpr);
520+
assert(!SemaRef.getSFINAEContext() &&
521+
"Can't produce SFINAE diagnostic pointing to temporary attribute");
520522

521523
if (checkAMDGPUMaxNumWorkGroupsArguments(SemaRef, XExpr, YExpr, ZExpr,
522524
TmpAttr))

0 commit comments

Comments
 (0)