Skip to content

Commit e709b8e

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 bfc322d commit e709b8e

16 files changed

+263
-382
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 60 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -11314,9 +11314,6 @@ class Sema final : public SemaBase {
1131411314
InventedParameterInfos.end());
1131511315
}
1131611316

11317-
/// The number of SFINAE diagnostics that have been trapped.
11318-
unsigned NumSFINAEErrors;
11319-
1132011317
ArrayRef<sema::FunctionScopeInfo *> getFunctionScopes() const {
1132111318
return llvm::ArrayRef(FunctionScopes.begin() + FunctionScopesStart,
1132211319
FunctionScopes.end());
@@ -12394,45 +12391,65 @@ class Sema final : public SemaBase {
1239412391
/// failures rather than hard errors.
1239512392
bool AccessCheckingSFINAE;
1239612393

12394+
class SFINAETrap;
12395+
12396+
struct SFINAEContextBase {
12397+
SFINAEContextBase(Sema &S, SFINAETrap *Cur)
12398+
: S(S), Prev(std::exchange(S.CurrentSFINAEContext, Cur)) {}
12399+
12400+
protected:
12401+
Sema &S;
12402+
~SFINAEContextBase() { S.CurrentSFINAEContext = Prev; }
12403+
12404+
private:
12405+
SFINAETrap *Prev;
12406+
};
12407+
12408+
struct NonSFINAEContext : SFINAEContextBase {
12409+
NonSFINAEContext(Sema &S) : SFINAEContextBase(S, nullptr) {}
12410+
};
12411+
1239712412
/// RAII class used to determine whether SFINAE has
1239812413
/// trapped any errors that occur during template argument
1239912414
/// deduction.
12400-
class SFINAETrap {
12401-
Sema &SemaRef;
12402-
unsigned PrevSFINAEErrors;
12403-
bool PrevInNonInstantiationSFINAEContext;
12404-
bool PrevAccessCheckingSFINAE;
12405-
bool PrevLastDiagnosticIgnored;
12415+
class SFINAETrap : SFINAEContextBase {
12416+
bool HasErrorOcurred = false;
12417+
bool PrevAccessCheckingSFINAE = S.AccessCheckingSFINAE;
12418+
bool PrevLastDiagnosticIgnored =
12419+
S.getDiagnostics().isLastDiagnosticIgnored();
12420+
sema::TemplateDeductionInfo *DeductionInfo = nullptr;
12421+
12422+
SFINAETrap(Sema &S, sema::TemplateDeductionInfo *Info,
12423+
bool ForValidityCheck)
12424+
: SFINAEContextBase(S, this), DeductionInfo(Info) {
12425+
S.AccessCheckingSFINAE = ForValidityCheck;
12426+
}
1240612427

1240712428
public:
1240812429
/// \param ForValidityCheck If true, discard all diagnostics (from the
1240912430
/// immediate context) instead of adding them to the currently active
12410-
/// \ref TemplateDeductionInfo (as returned by \ref isSFINAEContext).
12411-
explicit SFINAETrap(Sema &SemaRef, bool ForValidityCheck = false)
12412-
: SemaRef(SemaRef), PrevSFINAEErrors(SemaRef.NumSFINAEErrors),
12413-
PrevInNonInstantiationSFINAEContext(
12414-
SemaRef.InNonInstantiationSFINAEContext),
12415-
PrevAccessCheckingSFINAE(SemaRef.AccessCheckingSFINAE),
12416-
PrevLastDiagnosticIgnored(
12417-
SemaRef.getDiagnostics().isLastDiagnosticIgnored()) {
12418-
if (ForValidityCheck || !SemaRef.isSFINAEContext())
12419-
SemaRef.InNonInstantiationSFINAEContext = true;
12420-
SemaRef.AccessCheckingSFINAE = ForValidityCheck;
12421-
}
12431+
/// \ref TemplateDeductionInfo.
12432+
explicit SFINAETrap(Sema &S, bool ForValidityCheck = false)
12433+
: SFINAETrap(S, /*Info=*/nullptr, ForValidityCheck) {}
12434+
12435+
SFINAETrap(Sema &S, sema::TemplateDeductionInfo &Info)
12436+
: SFINAETrap(S, &Info, /*ForValidityCheck=*/false) {}
1242212437

1242312438
~SFINAETrap() {
12424-
SemaRef.NumSFINAEErrors = PrevSFINAEErrors;
12425-
SemaRef.InNonInstantiationSFINAEContext =
12426-
PrevInNonInstantiationSFINAEContext;
12427-
SemaRef.AccessCheckingSFINAE = PrevAccessCheckingSFINAE;
12428-
SemaRef.getDiagnostics().setLastDiagnosticIgnored(
12429-
PrevLastDiagnosticIgnored);
12439+
S.AccessCheckingSFINAE = PrevAccessCheckingSFINAE;
12440+
S.getDiagnostics().setLastDiagnosticIgnored(PrevLastDiagnosticIgnored);
1243012441
}
1243112442

12432-
/// Determine whether any SFINAE errors have been trapped.
12433-
bool hasErrorOccurred() const {
12434-
return SemaRef.NumSFINAEErrors > PrevSFINAEErrors;
12443+
SFINAETrap(const SFINAETrap &) = delete;
12444+
SFINAETrap &operator=(const SFINAETrap &) = delete;
12445+
12446+
sema::TemplateDeductionInfo *getDeductionInfo() const {
12447+
return DeductionInfo;
1243512448
}
12449+
12450+
/// Determine whether any SFINAE errors have been trapped.
12451+
bool hasErrorOccurred() const { return HasErrorOcurred; }
12452+
void setErrorOccurred() { HasErrorOcurred = true; }
1243612453
};
1243712454

1243812455
/// RAII class used to indicate that we are performing provisional
@@ -13153,9 +13170,6 @@ class Sema final : public SemaBase {
1315313170
PartialOrderingTTP,
1315413171
} Kind;
1315513172

13156-
/// Was the enclosing context a non-instantiation SFINAE context?
13157-
bool SavedInNonInstantiationSFINAEContext;
13158-
1315913173
/// Whether we're substituting into constraints.
1316013174
bool InConstraintSubstitution;
1316113175

@@ -13200,22 +13214,15 @@ class Sema final : public SemaBase {
1320013214
return {TemplateArgs, NumTemplateArgs};
1320113215
}
1320213216

13203-
/// The template deduction info object associated with the
13204-
/// substitution or checking of explicit or deduced template arguments.
13205-
sema::TemplateDeductionInfo *DeductionInfo;
13206-
1320713217
/// The source range that covers the construct that cause
1320813218
/// the instantiation, e.g., the template-id that causes a class
1320913219
/// template instantiation.
1321013220
SourceRange InstantiationRange;
1321113221

1321213222
CodeSynthesisContext()
13213-
: Kind(TemplateInstantiation),
13214-
SavedInNonInstantiationSFINAEContext(false),
13215-
InConstraintSubstitution(false),
13223+
: Kind(TemplateInstantiation), InConstraintSubstitution(false),
1321613224
InParameterMappingSubstitution(false), Entity(nullptr),
13217-
Template(nullptr), TemplateArgs(nullptr), NumTemplateArgs(0),
13218-
DeductionInfo(nullptr) {}
13225+
Template(nullptr), TemplateArgs(nullptr), NumTemplateArgs(0) {}
1321913226

1322013227
/// Determines whether this template is an actual instantiation
1322113228
/// that should be counted toward the maximum instantiation depth.
@@ -13267,15 +13274,13 @@ class Sema final : public SemaBase {
1326713274
FunctionTemplateDecl *FunctionTemplate,
1326813275
ArrayRef<TemplateArgument> TemplateArgs,
1326913276
CodeSynthesisContext::SynthesisKind Kind,
13270-
sema::TemplateDeductionInfo &DeductionInfo,
1327113277
SourceRange InstantiationRange = SourceRange());
1327213278

1327313279
/// Note that we are instantiating as part of template
1327413280
/// argument deduction for a class template declaration.
1327513281
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
1327613282
TemplateDecl *Template,
1327713283
ArrayRef<TemplateArgument> TemplateArgs,
13278-
sema::TemplateDeductionInfo &DeductionInfo,
1327913284
SourceRange InstantiationRange = SourceRange());
1328013285

1328113286
/// Note that we are instantiating as part of template
@@ -13284,7 +13289,6 @@ class Sema final : public SemaBase {
1328413289
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
1328513290
ClassTemplatePartialSpecializationDecl *PartialSpec,
1328613291
ArrayRef<TemplateArgument> TemplateArgs,
13287-
sema::TemplateDeductionInfo &DeductionInfo,
1328813292
SourceRange InstantiationRange = SourceRange());
1328913293

1329013294
/// Note that we are instantiating as part of template
@@ -13293,7 +13297,6 @@ class Sema final : public SemaBase {
1329313297
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
1329413298
VarTemplatePartialSpecializationDecl *PartialSpec,
1329513299
ArrayRef<TemplateArgument> TemplateArgs,
13296-
sema::TemplateDeductionInfo &DeductionInfo,
1329713300
SourceRange InstantiationRange = SourceRange());
1329813301

1329913302
/// Note that we are instantiating a default argument for a function
@@ -13339,7 +13342,6 @@ class Sema final : public SemaBase {
1333913342
/// concept.
1334013343
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
1334113344
ConstraintSubstitution, NamedDecl *Template,
13342-
sema::TemplateDeductionInfo &DeductionInfo,
1334313345
SourceRange InstantiationRange);
1334413346

1334513347
struct ConstraintNormalization {};
@@ -13359,7 +13361,6 @@ class Sema final : public SemaBase {
1335913361
/// a requirement of a requires expression.
1336013362
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
1336113363
concepts::Requirement *Req,
13362-
sema::TemplateDeductionInfo &DeductionInfo,
1336313364
SourceRange InstantiationRange = SourceRange());
1336413365

1336513366
/// \brief Note that we are checking the satisfaction of the constraint
@@ -13371,7 +13372,6 @@ class Sema final : public SemaBase {
1337113372
/// \brief Note that we are checking a requires clause.
1337213373
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
1337313374
const RequiresExpr *E,
13374-
sema::TemplateDeductionInfo &DeductionInfo,
1337513375
SourceRange InstantiationRange);
1337613376

1337713377
struct BuildingDeductionGuidesTag {};
@@ -13404,8 +13404,7 @@ class Sema final : public SemaBase {
1340413404
SourceLocation PointOfInstantiation,
1340513405
SourceRange InstantiationRange, Decl *Entity,
1340613406
NamedDecl *Template = nullptr,
13407-
ArrayRef<TemplateArgument> TemplateArgs = {},
13408-
sema::TemplateDeductionInfo *DeductionInfo = nullptr);
13407+
ArrayRef<TemplateArgument> TemplateArgs = {});
1340913408

1341013409
InstantiatingTemplate(const InstantiatingTemplate &) = delete;
1341113410

@@ -13546,12 +13545,7 @@ class Sema final : public SemaBase {
1354613545
/// recent visible declaration of that namespace.
1354713546
llvm::DenseMap<NamedDecl *, NamedDecl *> VisibleNamespaceCache;
1354813547

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

1355613550
/// The number of \p CodeSynthesisContexts that are not template
1355713551
/// instantiations and, therefore, should not be counted as part of the
@@ -13622,15 +13616,13 @@ class Sema final : public SemaBase {
1362213616
PrintInstantiationStack(getDefaultDiagFunc());
1362313617
}
1362413618

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

1363513627
/// Perform substitution on the type T with a given set of template
1363613628
/// arguments.
@@ -14642,7 +14634,8 @@ class Sema final : public SemaBase {
1464214634
ArrayRef<UnexpandedParameterPack> Unexpanded,
1464314635
const MultiLevelTemplateArgumentList &TemplateArgs,
1464414636
bool FailOnPackProducingTemplates, bool &ShouldExpand,
14645-
bool &RetainExpansion, UnsignedOrNone &NumExpansions);
14637+
bool &RetainExpansion, UnsignedOrNone &NumExpansions,
14638+
bool Diagnose = true);
1464614639

1464714640
/// Determine the number of arguments in the given pack expansion
1464814641
/// type.

clang/lib/Sema/Sema.cpp

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -321,10 +321,10 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
321321
static_cast<unsigned>(ComparisonCategoryType::Last) + 1),
322322
StdSourceLocationImplDecl(nullptr), CXXTypeInfoDecl(nullptr),
323323
GlobalNewDeleteDeclared(false), DisableTypoCorrection(false),
324-
TyposCorrected(0), IsBuildingRecoveryCallExpr(false), NumSFINAEErrors(0),
324+
TyposCorrected(0), IsBuildingRecoveryCallExpr(false),
325325
AccessCheckingSFINAE(false), CurrentInstantiationScope(nullptr),
326-
InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0),
327-
ArgPackSubstIndex(std::nullopt), SatisfactionCache(Context) {
326+
NonInstantiationEntries(0), ArgPackSubstIndex(std::nullopt),
327+
SatisfactionCache(Context) {
328328
assert(pp.TUKind == TUKind);
329329
TUScope = nullptr;
330330

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

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

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

16951698
// Make a copy of this suppressed diagnostic and store it with the
16961699
// template-deduction information.
1697-
if (*Info && !(*Info)->hasSFINAEDiagnostic()) {
1698-
(*Info)->addSFINAEDiagnostic(DiagInfo.getLocation(),
1699-
PartialDiagnostic(DiagInfo, Context.getDiagAllocator()));
1700-
}
1700+
if (Info && !Info->hasSFINAEDiagnostic())
1701+
Info->addSFINAEDiagnostic(
1702+
DiagInfo.getLocation(),
1703+
PartialDiagnostic(DiagInfo, Context.getDiagAllocator()));
17011704

17021705
Diags.setLastDiagnosticIgnored(true);
17031706
return;
@@ -1713,14 +1716,14 @@ void Sema::EmitDiagnostic(unsigned DiagID, const DiagnosticBuilder &DB) {
17131716
SourceLocation Loc = DiagInfo.getLocation();
17141717

17151718
// Suppress this diagnostic.
1716-
++NumSFINAEErrors;
1719+
Trap->setErrorOccurred();
17171720

17181721
// Make a copy of this suppressed diagnostic and store it with the
17191722
// template-deduction information.
1720-
if (*Info && !(*Info)->hasSFINAEDiagnostic()) {
1721-
(*Info)->addSFINAEDiagnostic(DiagInfo.getLocation(),
1722-
PartialDiagnostic(DiagInfo, Context.getDiagAllocator()));
1723-
}
1723+
if (Info && !Info->hasSFINAEDiagnostic())
1724+
Info->addSFINAEDiagnostic(
1725+
DiagInfo.getLocation(),
1726+
PartialDiagnostic(DiagInfo, Context.getDiagAllocator()));
17241727

17251728
Diags.setLastDiagnosticIgnored(true);
17261729

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

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.isSFINAEContext() &&
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)