aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaTemplateInstantiate.cpp
diff options
context:
space:
mode:
authorYounan Zhang <zyn7109@gmail.com>2025-06-02 17:10:07 +0800
committerGitHub <noreply@github.com>2025-06-02 17:10:07 +0800
commite04e140adb600add79b414f137a13af9d89c8c0d (patch)
tree1b351979062c412d51ffc793d7ea71a672b35998 /clang/lib/Sema/SemaTemplateInstantiate.cpp
parente3a0cb8d3f53e6b2d801e2fe732057f94704e6b7 (diff)
downloadllvm-e04e140adb600add79b414f137a13af9d89c8c0d.zip
llvm-e04e140adb600add79b414f137a13af9d89c8c0d.tar.gz
llvm-e04e140adb600add79b414f137a13af9d89c8c0d.tar.bz2
[Clang] Reapply CWG2369 "Ordering between constraints and substitution" (#122423)
The previous approach broke code generation for the MS ABI due to an unintended code path during constraint substitution. This time we address the issue by inspecting the evaluation contexts and thereby avoiding that code path. This reapplies 96eced624 (#102857).
Diffstat (limited to 'clang/lib/Sema/SemaTemplateInstantiate.cpp')
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp109
1 files changed, 98 insertions, 11 deletions
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 3a04a24..a1c7143 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -474,6 +474,21 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
assert((ND || DC) && "Can't find arguments for a decl if one isn't provided");
// Accumulate the set of template argument lists in this structure.
MultiLevelTemplateArgumentList Result;
+ getTemplateInstantiationArgs(
+ Result, ND, DC, Final, Innermost, RelativeToPrimary, Pattern,
+ ForConstraintInstantiation, SkipForSpecialization,
+ ForDefaultArgumentSubstitution);
+ return Result;
+}
+
+void Sema::getTemplateInstantiationArgs(
+ MultiLevelTemplateArgumentList &Result, const NamedDecl *ND,
+ const DeclContext *DC, bool Final,
+ std::optional<ArrayRef<TemplateArgument>> Innermost, bool RelativeToPrimary,
+ const FunctionDecl *Pattern, bool ForConstraintInstantiation,
+ bool SkipForSpecialization, bool ForDefaultArgumentSubstitution) {
+ assert((ND || DC) && "Can't find arguments for a decl if one isn't provided");
+ // Accumulate the set of template argument lists in this structure.
using namespace TemplateInstArgsHelpers;
const Decl *CurDecl = ND;
@@ -533,14 +548,12 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
}
if (R.IsDone)
- return Result;
+ return;
if (R.ClearRelativeToPrimary)
RelativeToPrimary = false;
assert(R.NextDecl);
CurDecl = R.NextDecl;
}
-
- return Result;
}
bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
@@ -609,6 +622,12 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
Inst.NumTemplateArgs = TemplateArgs.size();
Inst.DeductionInfo = DeductionInfo;
Inst.InstantiationRange = InstantiationRange;
+ Inst.InConstraintSubstitution =
+ Inst.Kind == CodeSynthesisContext::ConstraintSubstitution;
+ if (!SemaRef.CodeSynthesisContexts.empty())
+ Inst.InConstraintSubstitution |=
+ SemaRef.CodeSynthesisContexts.back().InConstraintSubstitution;
+
SemaRef.pushCodeSynthesisContext(Inst);
AlreadyInstantiating = !Inst.Entity ? false :
@@ -1375,6 +1394,12 @@ namespace {
// Whether an incomplete substituion should be treated as an error.
bool BailOutOnIncomplete;
+ private:
+ // 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;
@@ -1431,12 +1456,19 @@ namespace {
ArrayRef<UnexpandedParameterPack> Unexpanded,
bool &ShouldExpand, bool &RetainExpansion,
UnsignedOrNone &NumExpansions) {
- return getSema().CheckParameterPacksForExpansion(EllipsisLoc,
- PatternRange, Unexpanded,
- TemplateArgs,
- ShouldExpand,
- RetainExpansion,
- NumExpansions);
+ if (SemaRef.CurrentInstantiationScope &&
+ SemaRef.inConstraintSubstitution()) {
+ 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 getSema().CheckParameterPacksForExpansion(
+ EllipsisLoc, PatternRange, Unexpanded, TemplateArgs, ShouldExpand,
+ RetainExpansion, NumExpansions);
}
void ExpandingFunctionParameterPack(ParmVarDecl *Pack) {
@@ -1920,9 +1952,57 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
// template parameter.
}
+ if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(D);
+ PVD && SemaRef.CurrentInstantiationScope &&
+ SemaRef.inConstraintSubstitution() &&
+ maybeInstantiateFunctionParameterToScope(PVD))
+ return nullptr;
+
return SemaRef.FindInstantiatedDecl(Loc, cast<NamedDecl>(D), TemplateArgs);
}
+bool TemplateInstantiator::maybeInstantiateFunctionParameterToScope(
+ ParmVarDecl *OldParm) {
+ if (SemaRef.CurrentInstantiationScope->getInstantiationOfIfExists(OldParm))
+ return false;
+
+ if (!OldParm->isParameterPack())
+ return !TransformFunctionTypeParam(OldParm, /*indexAdjustment=*/0,
+ /*NumExpansions=*/std::nullopt,
+ /*ExpectParameterPack=*/false);
+
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+
+ // Find the parameter packs that could be expanded.
+ TypeLoc TL = OldParm->getTypeSourceInfo()->getTypeLoc();
+ PackExpansionTypeLoc ExpansionTL = TL.castAs<PackExpansionTypeLoc>();
+ TypeLoc Pattern = ExpansionTL.getPatternLoc();
+ SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded);
+ assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
+
+ bool ShouldExpand = false;
+ bool RetainExpansion = false;
+ UnsignedOrNone OrigNumExpansions =
+ ExpansionTL.getTypePtr()->getNumExpansions();
+ UnsignedOrNone NumExpansions = OrigNumExpansions;
+ if (TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
+ Pattern.getSourceRange(), Unexpanded,
+ ShouldExpand, RetainExpansion, NumExpansions))
+ return true;
+
+ assert(ShouldExpand && !RetainExpansion &&
+ "Shouldn't preserve pack expansion when evaluating constraints");
+ ExpandingFunctionParameterPack(OldParm);
+ for (unsigned I = 0; I != *NumExpansions; ++I) {
+ Sema::ArgPackSubstIndexRAII SubstIndex(getSema(), I);
+ if (!TransformFunctionTypeParam(OldParm, /*indexAdjustment=*/0,
+ /*NumExpansions=*/OrigNumExpansions,
+ /*ExpectParameterPack=*/false))
+ return true;
+ }
+ return false;
+}
+
Decl *TemplateInstantiator::TransformDefinition(SourceLocation Loc, Decl *D) {
Decl *Inst = getSema().SubstDecl(D, getSema().CurContext, TemplateArgs);
if (!Inst)
@@ -4502,9 +4582,8 @@ static const Decl *getCanonicalParmVarDecl(const Decl *D) {
return D;
}
-
llvm::PointerUnion<Decl *, LocalInstantiationScope::DeclArgumentPack *> *
-LocalInstantiationScope::findInstantiationOf(const Decl *D) {
+LocalInstantiationScope::getInstantiationOfIfExists(const Decl *D) {
D = getCanonicalParmVarDecl(D);
for (LocalInstantiationScope *Current = this; Current;
Current = Current->Outer) {
@@ -4529,6 +4608,14 @@ LocalInstantiationScope::findInstantiationOf(const Decl *D) {
break;
}
+ return nullptr;
+}
+
+llvm::PointerUnion<Decl *, LocalInstantiationScope::DeclArgumentPack *> *
+LocalInstantiationScope::findInstantiationOf(const Decl *D) {
+ auto *Result = getInstantiationOfIfExists(D);
+ if (Result)
+ return Result;
// If we're performing a partial substitution during template argument
// deduction, we may not have values for template parameters yet.
if (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||