[clang] [Sema] Guard transformed loop-hint expression before use (PR #182752)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Feb 22 08:29:39 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Tommy Chiang (oToToT)
<details>
<summary>Changes</summary>
`TransformLoopHintAttr` called `TransformExpr(...).get()` without checking that the transformed expression was usable.
For `#pragma GCC unroll v()` instantiated with `v = int`, expression transformation fails and Clang can assert while validating the loop hint.
Check `ExprResult::isUsable()` before calling `get()` and keep the original attribute on failure.
Fixes https://github.com/llvm/llvm-project/issues/49502
---
Patch is 100.93 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/182752.diff
2 Files Affected:
- (modified) clang/lib/Sema/SemaTemplateInstantiate.cpp (+760-790)
- (modified) clang/test/Sema/unroll-template-value-crash.cpp (+10-1)
``````````diff
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 37309d057fbe7..86d55228586a4 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -284,8 +284,9 @@ Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function,
// don't get any template arguments from this function but might get
// some from an enclosing template.
return Response::UseNextDecl(Function);
- } else if (const TemplateArgumentList *TemplateArgs =
- Function->getTemplateSpecializationArgs()) {
+ }
+ if (const TemplateArgumentList *TemplateArgs =
+ Function->getTemplateSpecializationArgs()) {
// Add the template arguments for this specialization.
Result.addOuterTemplateArguments(const_cast<FunctionDecl *>(Function),
TemplateArgs->asArray(),
@@ -651,17 +652,16 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema &SemaRef, SourceLocation PointOfInstantiation, FunctionDecl *Entity,
ExceptionSpecification, SourceRange InstantiationRange)
- : InstantiatingTemplate(
- SemaRef, CodeSynthesisContext::ExceptionSpecInstantiation,
- PointOfInstantiation, InstantiationRange, Entity) {}
+ : InstantiatingTemplate(SemaRef,
+ CodeSynthesisContext::ExceptionSpecInstantiation,
+ PointOfInstantiation, InstantiationRange, Entity) {}
Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateParameter Param,
TemplateDecl *Template, ArrayRef<TemplateArgument> TemplateArgs,
SourceRange InstantiationRange)
: InstantiatingTemplate(
- SemaRef,
- CodeSynthesisContext::DefaultTemplateArgumentInstantiation,
+ SemaRef, CodeSynthesisContext::DefaultTemplateArgumentInstantiation,
PointOfInstantiation, InstantiationRange, getAsNamedDecl(Param),
Template, TemplateArgs) {}
@@ -708,8 +708,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema &SemaRef, SourceLocation PointOfInstantiation, ParmVarDecl *Param,
ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange)
: InstantiatingTemplate(
- SemaRef,
- CodeSynthesisContext::DefaultFunctionArgumentInstantiation,
+ SemaRef, CodeSynthesisContext::DefaultFunctionArgumentInstantiation,
PointOfInstantiation, InstantiationRange, Param, nullptr,
TemplateArgs) {}
@@ -718,8 +717,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
NonTypeTemplateParmDecl *Param, ArrayRef<TemplateArgument> TemplateArgs,
SourceRange InstantiationRange)
: InstantiatingTemplate(
- SemaRef,
- CodeSynthesisContext::PriorTemplateArgumentSubstitution,
+ SemaRef, CodeSynthesisContext::PriorTemplateArgumentSubstitution,
PointOfInstantiation, InstantiationRange, Param, Template,
TemplateArgs) {}
@@ -728,8 +726,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
TemplateTemplateParmDecl *Param, ArrayRef<TemplateArgument> TemplateArgs,
SourceRange InstantiationRange)
: InstantiatingTemplate(
- SemaRef,
- CodeSynthesisContext::PriorTemplateArgumentSubstitution,
+ SemaRef, CodeSynthesisContext::PriorTemplateArgumentSubstitution,
PointOfInstantiation, InstantiationRange, Param, Template,
TemplateArgs) {}
@@ -777,13 +774,12 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
/*Template=*/nullptr, /*TemplateArgs=*/{}) {}
Sema::InstantiatingTemplate::InstantiatingTemplate(
- Sema &SemaRef, SourceLocation PointOfInstantiation,
- ConstraintsCheck, NamedDecl *Template,
- ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange)
- : InstantiatingTemplate(
- SemaRef, CodeSynthesisContext::ConstraintsCheck,
- PointOfInstantiation, InstantiationRange, Template, nullptr,
- TemplateArgs) {}
+ Sema &SemaRef, SourceLocation PointOfInstantiation, ConstraintsCheck,
+ NamedDecl *Template, ArrayRef<TemplateArgument> TemplateArgs,
+ SourceRange InstantiationRange)
+ : InstantiatingTemplate(SemaRef, CodeSynthesisContext::ConstraintsCheck,
+ PointOfInstantiation, InstantiationRange, Template,
+ nullptr, TemplateArgs) {}
Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema &SemaRef, SourceLocation PointOfInstantiation, ConstraintSubstitution,
@@ -793,9 +789,8 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
PointOfInstantiation, InstantiationRange, Template, nullptr, {}) {}
Sema::InstantiatingTemplate::InstantiatingTemplate(
- Sema &SemaRef, SourceLocation PointOfInstantiation,
- ConstraintNormalization, NamedDecl *Template,
- SourceRange InstantiationRange)
+ Sema &SemaRef, SourceLocation PointOfInstantiation, ConstraintNormalization,
+ NamedDecl *Template, SourceRange InstantiationRange)
: InstantiatingTemplate(
SemaRef, CodeSynthesisContext::ConstraintNormalization,
PointOfInstantiation, InstantiationRange, Template) {}
@@ -811,9 +806,9 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateDecl *Entity,
BuildingDeductionGuidesTag, SourceRange InstantiationRange)
- : InstantiatingTemplate(
- SemaRef, CodeSynthesisContext::BuildingDeductionGuides,
- PointOfInstantiation, InstantiationRange, Entity) {}
+ : InstantiatingTemplate(SemaRef,
+ CodeSynthesisContext::BuildingDeductionGuides,
+ PointOfInstantiation, InstantiationRange, Entity) {}
Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema &SemaRef, SourceLocation ArgLoc, PartialOrderingTTP,
@@ -868,8 +863,7 @@ void Sema::popCodeSynthesisContext() {
// If we've left the code synthesis context for the current context stack,
// stop remembering that we've emitted that stack.
- if (CodeSynthesisContexts.size() ==
- LastEmittedCodeSynthesisContextDepth)
+ if (CodeSynthesisContexts.size() == LastEmittedCodeSynthesisContextDepth)
LastEmittedCodeSynthesisContextDepth = 0;
CodeSynthesisContexts.pop_back();
@@ -910,10 +904,9 @@ void Sema::PrintInstantiationStack(InstantiationContextDiagFuncRef DiagFunc) {
// FIXME: In all of these cases, we need to show the template arguments
unsigned InstantiationIdx = 0;
for (SmallVectorImpl<CodeSynthesisContext>::reverse_iterator
- Active = CodeSynthesisContexts.rbegin(),
- ActiveEnd = CodeSynthesisContexts.rend();
- Active != ActiveEnd;
- ++Active, ++InstantiationIdx) {
+ Active = CodeSynthesisContexts.rbegin(),
+ ActiveEnd = CodeSynthesisContexts.rend();
+ Active != ActiveEnd; ++Active, ++InstantiationIdx) {
// Skip this instantiation?
if (InstantiationIdx >= SkipStart && InstantiationIdx < SkipEnd) {
if (InstantiationIdx == SkipStart) {
@@ -1055,8 +1048,8 @@ void Sema::PrintInstantiationStack(InstantiationContextDiagFuncRef DiagFunc) {
TemplateParams = Template->getTemplateParameters();
else
TemplateParams =
- cast<ClassTemplatePartialSpecializationDecl>(Active->Template)
- ->getTemplateParameters();
+ cast<ClassTemplatePartialSpecializationDecl>(Active->Template)
+ ->getTemplateParameters();
DiagFunc(Active->PointOfInstantiation,
PDiag(diag::note_prior_template_arg_substitution)
<< isa<TemplateTemplateParmDecl>(Parm) << Name
@@ -1073,8 +1066,8 @@ void Sema::PrintInstantiationStack(InstantiationContextDiagFuncRef DiagFunc) {
TemplateParams = Template->getTemplateParameters();
else
TemplateParams =
- cast<ClassTemplatePartialSpecializationDecl>(Active->Template)
- ->getTemplateParameters();
+ cast<ClassTemplatePartialSpecializationDecl>(Active->Template)
+ ->getTemplateParameters();
DiagFunc(Active->PointOfInstantiation,
PDiag(diag::note_template_default_arg_checking)
@@ -1269,553 +1262,551 @@ void Sema::PrintInstantiationStack(InstantiationContextDiagFuncRef DiagFunc) {
//===----------------------------------------------------------------------===/
namespace {
- class TemplateInstantiator : public TreeTransform<TemplateInstantiator> {
- const MultiLevelTemplateArgumentList &TemplateArgs;
- SourceLocation Loc;
- DeclarationName Entity;
- // Whether to evaluate the C++20 constraints or simply substitute into them.
- bool EvaluateConstraints = true;
- // Whether Substitution was Incomplete, that is, we tried to substitute in
- // any user provided template arguments which were null.
- bool IsIncomplete = false;
- // Whether an incomplete substituion should be treated as an error.
- bool BailOutOnIncomplete;
-
- // CWG2770: Function parameters should be instantiated when they are
- // needed by a satisfaction check of an atomic constraint or
- // (recursively) by another function parameter.
- bool maybeInstantiateFunctionParameterToScope(ParmVarDecl *OldParm);
-
- public:
- typedef TreeTransform<TemplateInstantiator> inherited;
-
- TemplateInstantiator(Sema &SemaRef,
- const MultiLevelTemplateArgumentList &TemplateArgs,
- SourceLocation Loc, DeclarationName Entity,
- bool BailOutOnIncomplete = false)
- : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
- Entity(Entity), BailOutOnIncomplete(BailOutOnIncomplete) {}
-
- void setEvaluateConstraints(bool B) {
- EvaluateConstraints = B;
- }
- bool getEvaluateConstraints() {
- return EvaluateConstraints;
- }
-
- inline static struct ForParameterMappingSubstitution_t {
- } ForParameterMappingSubstitution;
-
- TemplateInstantiator(ForParameterMappingSubstitution_t, Sema &SemaRef,
- SourceLocation Loc,
- const MultiLevelTemplateArgumentList &TemplateArgs)
- : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
- BailOutOnIncomplete(false) {}
-
- /// Determine whether the given type \p T has already been
- /// transformed.
- ///
- /// For the purposes of template instantiation, a type has already been
- /// transformed if it is NULL or if it is not dependent.
- bool AlreadyTransformed(QualType T);
+class TemplateInstantiator : public TreeTransform<TemplateInstantiator> {
+ const MultiLevelTemplateArgumentList &TemplateArgs;
+ SourceLocation Loc;
+ DeclarationName Entity;
+ // Whether to evaluate the C++20 constraints or simply substitute into them.
+ bool EvaluateConstraints = true;
+ // Whether Substitution was Incomplete, that is, we tried to substitute in
+ // any user provided template arguments which were null.
+ bool IsIncomplete = false;
+ // Whether an incomplete substituion should be treated as an error.
+ bool BailOutOnIncomplete;
+
+ // CWG2770: Function parameters should be instantiated when they are
+ // needed by a satisfaction check of an atomic constraint or
+ // (recursively) by another function parameter.
+ bool maybeInstantiateFunctionParameterToScope(ParmVarDecl *OldParm);
+
+public:
+ typedef TreeTransform<TemplateInstantiator> inherited;
+
+ TemplateInstantiator(Sema &SemaRef,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ SourceLocation Loc, DeclarationName Entity,
+ bool BailOutOnIncomplete = false)
+ : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
+ Entity(Entity), BailOutOnIncomplete(BailOutOnIncomplete) {}
+
+ void setEvaluateConstraints(bool B) { EvaluateConstraints = B; }
+ bool getEvaluateConstraints() { return EvaluateConstraints; }
+
+ inline static struct ForParameterMappingSubstitution_t {
+ } ForParameterMappingSubstitution;
+
+ TemplateInstantiator(ForParameterMappingSubstitution_t, Sema &SemaRef,
+ SourceLocation Loc,
+ const MultiLevelTemplateArgumentList &TemplateArgs)
+ : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
+ BailOutOnIncomplete(false) {}
+
+ /// Determine whether the given type \p T has already been
+ /// transformed.
+ ///
+ /// For the purposes of template instantiation, a type has already been
+ /// transformed if it is NULL or if it is not dependent.
+ bool AlreadyTransformed(QualType T);
+
+ /// Returns the location of the entity being instantiated, if known.
+ SourceLocation getBaseLocation() { return Loc; }
+
+ /// Returns the name of the entity being instantiated, if any.
+ DeclarationName getBaseEntity() { return Entity; }
+
+ /// Returns whether any substitution so far was incomplete.
+ bool getIsIncomplete() const { return IsIncomplete; }
+
+ /// Sets the "base" location and entity when that
+ /// information is known based on another transformation.
+ void setBase(SourceLocation Loc, DeclarationName Entity) {
+ this->Loc = Loc;
+ this->Entity = Entity;
+ }
- /// Returns the location of the entity being instantiated, if known.
- SourceLocation getBaseLocation() { return Loc; }
+ unsigned TransformTemplateDepth(unsigned Depth) {
+ return TemplateArgs.getNewDepth(Depth);
+ }
- /// Returns the name of the entity being instantiated, if any.
- DeclarationName getBaseEntity() { return Entity; }
+ bool TryExpandParameterPacks(SourceLocation EllipsisLoc,
+ SourceRange PatternRange,
+ ArrayRef<UnexpandedParameterPack> Unexpanded,
+ bool FailOnPackProducingTemplates,
+ bool &ShouldExpand, bool &RetainExpansion,
+ UnsignedOrNone &NumExpansions) {
+ if (SemaRef.CurrentInstantiationScope &&
+ (SemaRef.inConstraintSubstitution() ||
+ SemaRef.inParameterMappingSubstitution())) {
+ for (UnexpandedParameterPack ParmPack : Unexpanded) {
+ NamedDecl *VD = ParmPack.first.dyn_cast<NamedDecl *>();
+ if (auto *PVD = dyn_cast_if_present<ParmVarDecl>(VD);
+ PVD && maybeInstantiateFunctionParameterToScope(PVD))
+ return true;
+ }
+ }
- /// Returns whether any substitution so far was incomplete.
- bool getIsIncomplete() const { return IsIncomplete; }
+ return getSema().CheckParameterPacksForExpansion(
+ EllipsisLoc, PatternRange, Unexpanded, TemplateArgs,
+ FailOnPackProducingTemplates, ShouldExpand, RetainExpansion,
+ NumExpansions);
+ }
- /// Sets the "base" location and entity when that
- /// information is known based on another transformation.
- void setBase(SourceLocation Loc, DeclarationName Entity) {
- this->Loc = Loc;
- this->Entity = Entity;
- }
+ void ExpandingFunctionParameterPack(ParmVarDecl *Pack) {
+ SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack(Pack);
+ }
- unsigned TransformTemplateDepth(unsigned Depth) {
- return TemplateArgs.getNewDepth(Depth);
+ TemplateArgument ForgetPartiallySubstitutedPack() {
+ TemplateArgument Result;
+ if (NamedDecl *PartialPack =
+ SemaRef.CurrentInstantiationScope->getPartiallySubstitutedPack()) {
+ MultiLevelTemplateArgumentList &TemplateArgs =
+ const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
+ unsigned Depth, Index;
+ std::tie(Depth, Index) = getDepthAndIndex(PartialPack);
+ if (TemplateArgs.hasTemplateArgument(Depth, Index)) {
+ Result = TemplateArgs(Depth, Index);
+ TemplateArgs.setArgument(Depth, Index, TemplateArgument());
+ } else {
+ IsIncomplete = true;
+ if (BailOutOnIncomplete)
+ return TemplateArgument();
+ }
}
- bool TryExpandParameterPacks(SourceLocation EllipsisLoc,
- SourceRange PatternRange,
- ArrayRef<UnexpandedParameterPack> Unexpanded,
- bool FailOnPackProducingTemplates,
- bool &ShouldExpand, bool &RetainExpansion,
- UnsignedOrNone &NumExpansions) {
- if (SemaRef.CurrentInstantiationScope &&
- (SemaRef.inConstraintSubstitution() ||
- SemaRef.inParameterMappingSubstitution())) {
- for (UnexpandedParameterPack ParmPack : Unexpanded) {
- NamedDecl *VD = ParmPack.first.dyn_cast<NamedDecl *>();
- if (auto *PVD = dyn_cast_if_present<ParmVarDecl>(VD);
- PVD && maybeInstantiateFunctionParameterToScope(PVD))
- return true;
- }
- }
+ return Result;
+ }
- return getSema().CheckParameterPacksForExpansion(
- EllipsisLoc, PatternRange, Unexpanded, TemplateArgs,
- FailOnPackProducingTemplates, ShouldExpand, RetainExpansion,
- NumExpansions);
- }
+ void RememberPartiallySubstitutedPack(TemplateArgument Arg) {
+ if (Arg.isNull())
+ return;
- void ExpandingFunctionParameterPack(ParmVarDecl *Pack) {
- SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack(Pack);
+ if (NamedDecl *PartialPack =
+ SemaRef.CurrentInstantiationScope->getPartiallySubstitutedPack()) {
+ MultiLevelTemplateArgumentList &TemplateArgs =
+ const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
+ unsigned Depth, Index;
+ std::tie(Depth, Index) = getDepthAndIndex(PartialPack);
+ TemplateArgs.setArgument(Depth, Index, Arg);
}
+ }
- TemplateArgument ForgetPartiallySubstitutedPack() {
- TemplateArgument Result;
- if (NamedDecl *PartialPack = SemaRef.CurrentInstantiationScope
- ->getPartiallySubstitutedPack()) {
- MultiLevelTemplateArgumentList &TemplateArgs =
- const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
- unsigned Depth, Index;
- std::tie(Depth, Index) = getDepthAndIndex(PartialPack);
- if (TemplateArgs.hasTemplateArgument(Depth, Index)) {
- Result = TemplateArgs(Depth, Index);
- TemplateArgs.setArgument(Depth, Index, TemplateArgument());
- } else {
- IsIncomplete = true;
- if (BailOutOnIncomplete)
- return TemplateArgument();
- }
- }
+ MultiLevelTemplateArgumentList ForgetSubstitution() {
+ MultiLevelTemplateArgumentList New;
+ New.addOuterRetainedLevels(this->TemplateArgs.getNumLevels());
- return Result;
- }
+ MultiLevelTemplateArgumentList Old =
+ const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
+ const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs) =
+ std::move(New);
+ return Old;
+ }
- void RememberPartiallySubstitutedPack(TemplateArgument Arg) {
- if (Arg.isNull())
- return;
-
- if (NamedDecl *PartialPack = SemaRef.CurrentInstantiationScope
- ->getPartiallySubstitutedPack()) {
- MultiLevelTemplateArgumentList &TemplateArgs =
- const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
- unsigned Depth, Index;
- std::tie(Depth, Index) = getDepthAndIndex(PartialPack);
- TemplateArgs.setArgument(Depth, Index, Arg);
- }
- }
+ void RememberSubstitution(MultiLevelTemplateArgumentList Old) {
+ const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs) =
+ std::move(Old);
+ }
- MultiLevelTemplateArgumentList ForgetSubstitution() {
- MultiLevelTemplateArgumentList New;
- New.addOuterRetainedLevels(this->TemplateArgs.getNumLevels());
+ TemplateArgument
+ getTemplateArgumentPackPatternForRewrite(const TemplateArgument &TA) {
+ if (TA.getKind() != TemplateArgument::Pack)
+ return TA;
+ if (SemaRef.ArgPackSubstIndex)
+ ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/182752
More information about the cfe-commits
mailing list