-
Notifications
You must be signed in to change notification settings - Fork 15.1k
[clang] SFINAE context refactor #164703
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
[clang] SFINAE context refactor #164703
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -11309,9 +11309,6 @@ class Sema final : public SemaBase { | |||||
| InventedParameterInfos.end()); | ||||||
| } | ||||||
|
|
||||||
| /// The number of SFINAE diagnostics that have been trapped. | ||||||
| unsigned NumSFINAEErrors; | ||||||
|
|
||||||
| ArrayRef<sema::FunctionScopeInfo *> getFunctionScopes() const { | ||||||
| return llvm::ArrayRef(FunctionScopes.begin() + FunctionScopesStart, | ||||||
| FunctionScopes.end()); | ||||||
|
|
@@ -12385,49 +12382,65 @@ class Sema final : public SemaBase { | |||||
| ///@{ | ||||||
|
|
||||||
| public: | ||||||
| /// When true, access checking violations are treated as SFINAE | ||||||
| /// failures rather than hard errors. | ||||||
| bool AccessCheckingSFINAE; | ||||||
| class SFINAETrap; | ||||||
|
|
||||||
| struct SFINAEContextBase { | ||||||
| SFINAEContextBase(Sema &S, SFINAETrap *Cur) | ||||||
| : S(S), Prev(std::exchange(S.CurrentSFINAEContext, Cur)) {} | ||||||
|
|
||||||
| protected: | ||||||
| Sema &S; | ||||||
| ~SFINAEContextBase() { S.CurrentSFINAEContext = Prev; } | ||||||
|
|
||||||
| private: | ||||||
| SFINAETrap *Prev; | ||||||
| }; | ||||||
|
|
||||||
| struct NonSFINAEContext : SFINAEContextBase { | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Maybe that would be clearer?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think having both the 'Context' and 'RAII' qualifiers would be a bit too much, feels redundant to me.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You wanted to rename
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not a bad idea! |
||||||
| NonSFINAEContext(Sema &S) : SFINAEContextBase(S, nullptr) {} | ||||||
| }; | ||||||
|
|
||||||
| /// RAII class used to determine whether SFINAE has | ||||||
| /// trapped any errors that occur during template argument | ||||||
| /// deduction. | ||||||
| class SFINAETrap { | ||||||
| Sema &SemaRef; | ||||||
| unsigned PrevSFINAEErrors; | ||||||
| bool PrevInNonInstantiationSFINAEContext; | ||||||
| bool PrevAccessCheckingSFINAE; | ||||||
| bool PrevLastDiagnosticIgnored; | ||||||
| class SFINAETrap : SFINAEContextBase { | ||||||
| bool HasErrorOcurred = false; | ||||||
| bool WithAccessChecking = false; | ||||||
| bool PrevLastDiagnosticIgnored = | ||||||
| S.getDiagnostics().isLastDiagnosticIgnored(); | ||||||
| sema::TemplateDeductionInfo *DeductionInfo = nullptr; | ||||||
|
|
||||||
| SFINAETrap(Sema &S, sema::TemplateDeductionInfo *Info, | ||||||
| bool WithAccessChecking) | ||||||
| : SFINAEContextBase(S, this), WithAccessChecking(WithAccessChecking), | ||||||
| DeductionInfo(Info) {} | ||||||
|
|
||||||
| public: | ||||||
| /// \param ForValidityCheck If true, discard all diagnostics (from the | ||||||
| /// \param WithAccessChecking If true, discard all diagnostics (from the | ||||||
| /// immediate context) instead of adding them to the currently active | ||||||
| /// \ref TemplateDeductionInfo (as returned by \ref isSFINAEContext). | ||||||
| explicit SFINAETrap(Sema &SemaRef, bool ForValidityCheck = false) | ||||||
| : SemaRef(SemaRef), PrevSFINAEErrors(SemaRef.NumSFINAEErrors), | ||||||
| PrevInNonInstantiationSFINAEContext( | ||||||
| SemaRef.InNonInstantiationSFINAEContext), | ||||||
| PrevAccessCheckingSFINAE(SemaRef.AccessCheckingSFINAE), | ||||||
| PrevLastDiagnosticIgnored( | ||||||
| SemaRef.getDiagnostics().isLastDiagnosticIgnored()) { | ||||||
| if (ForValidityCheck || !SemaRef.isSFINAEContext()) | ||||||
| SemaRef.InNonInstantiationSFINAEContext = true; | ||||||
| SemaRef.AccessCheckingSFINAE = ForValidityCheck; | ||||||
| } | ||||||
| /// \ref TemplateDeductionInfo. | ||||||
| explicit SFINAETrap(Sema &S, bool WithAccessChecking = false) | ||||||
| : SFINAETrap(S, /*Info=*/nullptr, WithAccessChecking) {} | ||||||
|
|
||||||
| SFINAETrap(Sema &S, sema::TemplateDeductionInfo &Info) | ||||||
| : SFINAETrap(S, &Info, /*WithAccessChecking=*/false) {} | ||||||
|
|
||||||
| ~SFINAETrap() { | ||||||
| SemaRef.NumSFINAEErrors = PrevSFINAEErrors; | ||||||
| SemaRef.InNonInstantiationSFINAEContext = | ||||||
| PrevInNonInstantiationSFINAEContext; | ||||||
| SemaRef.AccessCheckingSFINAE = PrevAccessCheckingSFINAE; | ||||||
| SemaRef.getDiagnostics().setLastDiagnosticIgnored( | ||||||
| PrevLastDiagnosticIgnored); | ||||||
| S.getDiagnostics().setLastDiagnosticIgnored(PrevLastDiagnosticIgnored); | ||||||
| } | ||||||
|
|
||||||
| /// Determine whether any SFINAE errors have been trapped. | ||||||
| bool hasErrorOccurred() const { | ||||||
| return SemaRef.NumSFINAEErrors > PrevSFINAEErrors; | ||||||
| SFINAETrap(const SFINAETrap &) = delete; | ||||||
| SFINAETrap &operator=(const SFINAETrap &) = delete; | ||||||
|
|
||||||
| sema::TemplateDeductionInfo *getDeductionInfo() const { | ||||||
| return DeductionInfo; | ||||||
| } | ||||||
|
|
||||||
| /// Determine whether any SFINAE errors have been trapped. | ||||||
| bool hasErrorOccurred() const { return HasErrorOcurred; } | ||||||
| void setErrorOccurred() { HasErrorOcurred = true; } | ||||||
|
|
||||||
| bool withAccessChecking() const { return WithAccessChecking; } | ||||||
| }; | ||||||
|
|
||||||
| /// RAII class used to indicate that we are performing provisional | ||||||
|
|
@@ -13148,9 +13161,6 @@ class Sema final : public SemaBase { | |||||
| PartialOrderingTTP, | ||||||
| } Kind; | ||||||
|
|
||||||
| /// Was the enclosing context a non-instantiation SFINAE context? | ||||||
| bool SavedInNonInstantiationSFINAEContext; | ||||||
|
|
||||||
| /// Whether we're substituting into constraints. | ||||||
| bool InConstraintSubstitution; | ||||||
|
|
||||||
|
|
@@ -13195,22 +13205,15 @@ class Sema final : public SemaBase { | |||||
| return {TemplateArgs, NumTemplateArgs}; | ||||||
| } | ||||||
|
|
||||||
| /// The template deduction info object associated with the | ||||||
| /// substitution or checking of explicit or deduced template arguments. | ||||||
| sema::TemplateDeductionInfo *DeductionInfo; | ||||||
|
|
||||||
| /// The source range that covers the construct that cause | ||||||
| /// the instantiation, e.g., the template-id that causes a class | ||||||
| /// template instantiation. | ||||||
| SourceRange InstantiationRange; | ||||||
|
|
||||||
| CodeSynthesisContext() | ||||||
| : Kind(TemplateInstantiation), | ||||||
| SavedInNonInstantiationSFINAEContext(false), | ||||||
| InConstraintSubstitution(false), | ||||||
| : Kind(TemplateInstantiation), InConstraintSubstitution(false), | ||||||
| InParameterMappingSubstitution(false), Entity(nullptr), | ||||||
| Template(nullptr), TemplateArgs(nullptr), NumTemplateArgs(0), | ||||||
| DeductionInfo(nullptr) {} | ||||||
| Template(nullptr), TemplateArgs(nullptr), NumTemplateArgs(0) {} | ||||||
|
|
||||||
| /// Determines whether this template is an actual instantiation | ||||||
| /// that should be counted toward the maximum instantiation depth. | ||||||
|
|
@@ -13262,15 +13265,13 @@ class Sema final : public SemaBase { | |||||
| FunctionTemplateDecl *FunctionTemplate, | ||||||
| ArrayRef<TemplateArgument> TemplateArgs, | ||||||
| CodeSynthesisContext::SynthesisKind Kind, | ||||||
| sema::TemplateDeductionInfo &DeductionInfo, | ||||||
| SourceRange InstantiationRange = SourceRange()); | ||||||
|
|
||||||
| /// Note that we are instantiating as part of template | ||||||
| /// argument deduction for a class template declaration. | ||||||
| InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, | ||||||
| TemplateDecl *Template, | ||||||
| ArrayRef<TemplateArgument> TemplateArgs, | ||||||
| sema::TemplateDeductionInfo &DeductionInfo, | ||||||
| SourceRange InstantiationRange = SourceRange()); | ||||||
|
|
||||||
| /// Note that we are instantiating as part of template | ||||||
|
|
@@ -13279,7 +13280,6 @@ class Sema final : public SemaBase { | |||||
| InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, | ||||||
| ClassTemplatePartialSpecializationDecl *PartialSpec, | ||||||
| ArrayRef<TemplateArgument> TemplateArgs, | ||||||
| sema::TemplateDeductionInfo &DeductionInfo, | ||||||
| SourceRange InstantiationRange = SourceRange()); | ||||||
|
|
||||||
| /// Note that we are instantiating as part of template | ||||||
|
|
@@ -13288,7 +13288,6 @@ class Sema final : public SemaBase { | |||||
| InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, | ||||||
| VarTemplatePartialSpecializationDecl *PartialSpec, | ||||||
| ArrayRef<TemplateArgument> TemplateArgs, | ||||||
| sema::TemplateDeductionInfo &DeductionInfo, | ||||||
| SourceRange InstantiationRange = SourceRange()); | ||||||
|
|
||||||
| /// Note that we are instantiating a default argument for a function | ||||||
|
|
@@ -13334,7 +13333,6 @@ class Sema final : public SemaBase { | |||||
| /// concept. | ||||||
| InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, | ||||||
| ConstraintSubstitution, NamedDecl *Template, | ||||||
| sema::TemplateDeductionInfo &DeductionInfo, | ||||||
| SourceRange InstantiationRange); | ||||||
|
|
||||||
| struct ConstraintNormalization {}; | ||||||
|
|
@@ -13354,7 +13352,6 @@ class Sema final : public SemaBase { | |||||
| /// a requirement of a requires expression. | ||||||
| InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, | ||||||
| concepts::Requirement *Req, | ||||||
| sema::TemplateDeductionInfo &DeductionInfo, | ||||||
| SourceRange InstantiationRange = SourceRange()); | ||||||
|
|
||||||
| /// \brief Note that we are checking the satisfaction of the constraint | ||||||
|
|
@@ -13366,7 +13363,6 @@ class Sema final : public SemaBase { | |||||
| /// \brief Note that we are checking a requires clause. | ||||||
| InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, | ||||||
| const RequiresExpr *E, | ||||||
| sema::TemplateDeductionInfo &DeductionInfo, | ||||||
| SourceRange InstantiationRange); | ||||||
|
|
||||||
| struct BuildingDeductionGuidesTag {}; | ||||||
|
|
@@ -13399,8 +13395,7 @@ class Sema final : public SemaBase { | |||||
| SourceLocation PointOfInstantiation, | ||||||
| SourceRange InstantiationRange, Decl *Entity, | ||||||
| NamedDecl *Template = nullptr, | ||||||
| ArrayRef<TemplateArgument> TemplateArgs = {}, | ||||||
| sema::TemplateDeductionInfo *DeductionInfo = nullptr); | ||||||
| ArrayRef<TemplateArgument> TemplateArgs = {}); | ||||||
|
|
||||||
| InstantiatingTemplate(const InstantiatingTemplate &) = delete; | ||||||
|
|
||||||
|
|
@@ -13541,12 +13536,7 @@ class Sema final : public SemaBase { | |||||
| /// recent visible declaration of that namespace. | ||||||
| llvm::DenseMap<NamedDecl *, NamedDecl *> VisibleNamespaceCache; | ||||||
|
|
||||||
| /// Whether we are in a SFINAE context that is not associated with | ||||||
| /// template instantiation. | ||||||
| /// | ||||||
| /// This is used when setting up a SFINAE trap (\c see SFINAETrap) outside | ||||||
| /// of a template instantiation or template argument deduction. | ||||||
| bool InNonInstantiationSFINAEContext; | ||||||
| SFINAETrap *CurrentSFINAEContext = nullptr; | ||||||
|
|
||||||
| /// The number of \p CodeSynthesisContexts that are not template | ||||||
| /// instantiations and, therefore, should not be counted as part of the | ||||||
|
|
@@ -13617,15 +13607,13 @@ class Sema final : public SemaBase { | |||||
| PrintInstantiationStack(getDefaultDiagFunc()); | ||||||
| } | ||||||
|
|
||||||
| /// Determines whether we are currently in a context where | ||||||
| /// template argument substitution failures are not considered | ||||||
| /// errors. | ||||||
| /// | ||||||
| /// \returns An empty \c Optional if we're not in a SFINAE context. | ||||||
| /// Otherwise, contains a pointer that, if non-NULL, contains the nearest | ||||||
| /// template-deduction context object, which can be used to capture | ||||||
| /// diagnostics that will be suppressed. | ||||||
| std::optional<sema::TemplateDeductionInfo *> isSFINAEContext() const; | ||||||
| /// Returns a pointer to the current SFINAE context, if any. | ||||||
| [[nodiscard]] SFINAETrap *getSFINAEContext() const { | ||||||
| return CurrentSFINAEContext; | ||||||
| } | ||||||
mizvekov marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
| [[nodiscard]] bool isSFINAEContext() const { | ||||||
| return CurrentSFINAEContext != nullptr; | ||||||
| } | ||||||
|
|
||||||
| /// Perform substitution on the type T with a given set of template | ||||||
| /// arguments. | ||||||
|
|
@@ -14637,7 +14625,8 @@ class Sema final : public SemaBase { | |||||
| ArrayRef<UnexpandedParameterPack> Unexpanded, | ||||||
| const MultiLevelTemplateArgumentList &TemplateArgs, | ||||||
| bool FailOnPackProducingTemplates, bool &ShouldExpand, | ||||||
| bool &RetainExpansion, UnsignedOrNone &NumExpansions); | ||||||
| bool &RetainExpansion, UnsignedOrNone &NumExpansions, | ||||||
| bool Diagnose = true); | ||||||
|
|
||||||
| /// Determine the number of arguments in the given pack expansion | ||||||
| /// type. | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks weird to have a sub-class's pointer in a base class. Though this is not a blocker
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does allow to share the
CurrentSFINAEContextsetup between all derived classes.If you have a better idea I am all ears.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems that doing so makes clients enough simple, though I don't think I have better ideas yet :(
@cor3ntin
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The alternative would be
SFINAEContext _(S, SFINAEContext::NoSFINAE)- that would also make sense to me.I don't have strong feelings