Skip to content

Commit 514f112

Browse files
committed
Refactor substituteParameterMappings. NFC
1 parent 006334e commit 514f112

File tree

4 files changed

+273
-18
lines changed

4 files changed

+273
-18
lines changed

clang/include/clang/Sema/SemaConcept.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ struct NormalizedConstraint {
6767
unsigned Kind : 5;
6868
unsigned Placeholder : 1;
6969
unsigned PackSubstitutionIndex : 26;
70-
llvm::SmallBitVector Indexes;
70+
OccurenceList Indexes;
7171
TemplateArgumentLoc *Args;
7272
TemplateParameterList *ParamList;
7373
ExprOrConcept ConstraintExpr;
@@ -79,7 +79,7 @@ struct NormalizedConstraint {
7979
unsigned Kind : 5;
8080
LLVM_PREFERRED_TYPE(FoldOperatorKind)
8181
unsigned FoldOperator : 1;
82-
unsigned Placeholder : 26;
82+
unsigned NumExpansions : 26;
8383
OccurenceList Indexes;
8484
TemplateArgumentLoc *Args;
8585
TemplateParameterList *ParamList;
@@ -131,7 +131,7 @@ struct NormalizedConstraint {
131131
NormalizedConstraint *Constraint)
132132
: FoldExpanded{llvm::to_underlying(ConstraintKind::FoldExpanded),
133133
llvm::to_underlying(OpKind),
134-
/*Placeholder=*/0,
134+
/*NumExpansions=*/0,
135135
/*Indexes=*/{},
136136
/*Args=*/nullptr,
137137
/*ParamList=*/nullptr,

clang/lib/Sema/SemaConcept.cpp

Lines changed: 259 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1639,6 +1639,258 @@ void Sema::DiagnoseUnsatisfiedConstraint(
16391639
ConstraintExpr->getBeginLoc(), First);
16401640
}
16411641

1642+
namespace {
1643+
1644+
class SubstituteParameterMappings {
1645+
Sema &SemaRef;
1646+
1647+
const MultiLevelTemplateArgumentList *MLTAL;
1648+
const ASTTemplateArgumentListInfo *ArgsAsWritten;
1649+
1650+
SubstituteParameterMappings(Sema &SemaRef,
1651+
const MultiLevelTemplateArgumentList *MLTAL,
1652+
const ASTTemplateArgumentListInfo *ArgsAsWritten)
1653+
: SemaRef(SemaRef), MLTAL(MLTAL), ArgsAsWritten(ArgsAsWritten) {}
1654+
1655+
void buildParameterMapping(NormalizedConstraintWithParamMapping &N);
1656+
1657+
bool substitute(NormalizedConstraintWithParamMapping &N);
1658+
1659+
bool substitute(ConceptIdConstraint &CC);
1660+
1661+
public:
1662+
SubstituteParameterMappings(Sema &SemaRef)
1663+
: SemaRef(SemaRef), MLTAL(nullptr), ArgsAsWritten(nullptr) {}
1664+
1665+
bool substitute(NormalizedConstraint &N);
1666+
};
1667+
1668+
void SubstituteParameterMappings::buildParameterMapping(
1669+
NormalizedConstraintWithParamMapping &N) {
1670+
TemplateParameterList *TemplateParams =
1671+
cast<TemplateDecl>(N.getConstraintDecl())->getTemplateParameters();
1672+
1673+
llvm::SmallBitVector OccurringIndices(TemplateParams->size());
1674+
1675+
if (N.getKind() == NormalizedConstraint::ConstraintKind::Atomic) {
1676+
SemaRef.MarkUsedTemplateParameters(
1677+
static_cast<AtomicConstraint &>(N).getConstraintExpr(),
1678+
/*OnlyDeduced=*/false,
1679+
/*Depth=*/0, OccurringIndices);
1680+
} else if (N.getKind() == NormalizedConstraint::ConstraintKind::ConceptId) {
1681+
auto *Args = static_cast<ConceptIdConstraint &>(N)
1682+
.getConceptId()
1683+
->getTemplateArgsAsWritten();
1684+
if (Args)
1685+
SemaRef.MarkUsedTemplateParameters(Args->arguments(),
1686+
/*Depth=*/0, OccurringIndices);
1687+
}
1688+
TemplateArgumentLoc *TempArgs =
1689+
new (SemaRef.Context) TemplateArgumentLoc[OccurringIndices.count()];
1690+
llvm::SmallVector<NamedDecl *> UsedParams;
1691+
for (unsigned I = 0, J = 0, C = TemplateParams->size(); I != C; ++I) {
1692+
SourceLocation Loc = ArgsAsWritten->NumTemplateArgs > I
1693+
? ArgsAsWritten->arguments()[I].getLocation()
1694+
: SourceLocation();
1695+
// FIXME: Investigate why we couldn't always preserve the SourceLoc. We
1696+
// can't assert Loc.isValid() now.
1697+
if (OccurringIndices[I]) {
1698+
NamedDecl *Param = TemplateParams->begin()[I];
1699+
new (&(TempArgs)[J]) TemplateArgumentLoc(
1700+
SemaRef.getIdentityTemplateArgumentLoc(Param, Loc));
1701+
UsedParams.push_back(Param);
1702+
J++;
1703+
}
1704+
}
1705+
auto *UsedList = TemplateParameterList::Create(
1706+
SemaRef.Context, TemplateParams->getTemplateLoc(),
1707+
TemplateParams->getLAngleLoc(), UsedParams,
1708+
/*RAngleLoc=*/SourceLocation(),
1709+
/*RequiresClause=*/nullptr);
1710+
N.updateParameterMapping(
1711+
OccurringIndices,
1712+
MutableArrayRef<TemplateArgumentLoc>{TempArgs, OccurringIndices.count()},
1713+
UsedList);
1714+
}
1715+
1716+
bool SubstituteParameterMappings::substitute(
1717+
NormalizedConstraintWithParamMapping &N) {
1718+
if (!N.hasParameterMapping())
1719+
buildParameterMapping(N);
1720+
1721+
SourceLocation InstLocBegin, InstLocEnd;
1722+
llvm::ArrayRef Arguments = ArgsAsWritten->arguments();
1723+
if (Arguments.empty()) {
1724+
InstLocBegin = ArgsAsWritten->getLAngleLoc();
1725+
InstLocEnd = ArgsAsWritten->getRAngleLoc();
1726+
} else {
1727+
// FIXME: Is it useful?
1728+
auto SR = Arguments[0].getSourceRange();
1729+
InstLocBegin = SR.getBegin();
1730+
InstLocEnd = SR.getEnd();
1731+
}
1732+
Sema::InstantiatingTemplate Inst(
1733+
SemaRef, InstLocBegin,
1734+
Sema::InstantiatingTemplate::ParameterMappingSubstitution{},
1735+
const_cast<NamedDecl *>(N.getConstraintDecl()),
1736+
{InstLocBegin, InstLocEnd});
1737+
if (Inst.isInvalid())
1738+
return true;
1739+
1740+
// TransformTemplateArguments is unable to preserve the source location of a
1741+
// pack. The SourceLocation is necessary for the instantiation location.
1742+
// FIXME: The BaseLoc will be used as the location of the pack expansion,
1743+
// which is wrong.
1744+
TemplateArgumentListInfo SubstArgs;
1745+
if (SemaRef.SubstTemplateArgumentsInParameterMapping(
1746+
N.getParameterMapping(), N.getBeginLoc(), *MLTAL, SubstArgs))
1747+
return true;
1748+
Sema::CheckTemplateArgumentInfo CTAI;
1749+
auto *TD =
1750+
const_cast<TemplateDecl *>(cast<TemplateDecl>(N.getConstraintDecl()));
1751+
if (SemaRef.CheckTemplateArgumentList(TD, N.getUsedTemplateParamList(),
1752+
TD->getLocation(), SubstArgs,
1753+
/*DefaultArguments=*/{},
1754+
/*PartialTemplateArgs=*/false, CTAI))
1755+
return true;
1756+
1757+
TemplateArgumentLoc *TempArgs =
1758+
new (SemaRef.Context) TemplateArgumentLoc[CTAI.SugaredConverted.size()];
1759+
1760+
for (unsigned I = 0; I < CTAI.SugaredConverted.size(); ++I) {
1761+
SourceLocation Loc;
1762+
// If this is an empty pack, we have no corresponding SubstArgs.
1763+
if (I < SubstArgs.size())
1764+
Loc = SubstArgs.arguments()[I].getLocation();
1765+
1766+
TempArgs[I] = SemaRef.getTrivialTemplateArgumentLoc(
1767+
CTAI.SugaredConverted[I], QualType(), Loc);
1768+
}
1769+
1770+
MutableArrayRef<TemplateArgumentLoc> Mapping(TempArgs,
1771+
CTAI.SugaredConverted.size());
1772+
N.updateParameterMapping(N.mappingOccurenceList(), Mapping,
1773+
N.getUsedTemplateParamList());
1774+
return false;
1775+
}
1776+
1777+
bool SubstituteParameterMappings::substitute(ConceptIdConstraint &CC) {
1778+
assert(CC.getConstraintDecl() && MLTAL && ArgsAsWritten);
1779+
1780+
if (substitute(static_cast<NormalizedConstraintWithParamMapping &>(CC)))
1781+
return true;
1782+
1783+
auto *CSE = CC.getConceptSpecializationExpr();
1784+
assert(CSE);
1785+
assert(!CC.getBeginLoc().isInvalid());
1786+
1787+
SourceLocation InstLocBegin, InstLocEnd;
1788+
if (llvm::ArrayRef Arguments = ArgsAsWritten->arguments();
1789+
Arguments.empty()) {
1790+
InstLocBegin = ArgsAsWritten->getLAngleLoc();
1791+
InstLocEnd = ArgsAsWritten->getRAngleLoc();
1792+
} else {
1793+
// FIXME: Is it useful?
1794+
auto SR = Arguments[0].getSourceRange();
1795+
InstLocBegin = SR.getBegin();
1796+
InstLocEnd = SR.getEnd();
1797+
}
1798+
// This is useful for name lookup across modules; see Sema::getLookupModules.
1799+
Sema::InstantiatingTemplate Inst(
1800+
SemaRef, InstLocBegin,
1801+
Sema::InstantiatingTemplate::ParameterMappingSubstitution{},
1802+
const_cast<NamedDecl *>(CC.getConstraintDecl()),
1803+
{InstLocBegin, InstLocEnd});
1804+
if (Inst.isInvalid())
1805+
return true;
1806+
1807+
TemplateArgumentListInfo Out;
1808+
// TransformTemplateArguments is unable to preserve the source location of a
1809+
// pack. The SourceLocation is necessary for the instantiation location.
1810+
// FIXME: The BaseLoc will be used as the location of the pack expansion,
1811+
// which is wrong.
1812+
const ASTTemplateArgumentListInfo *ArgsAsWritten =
1813+
CSE->getTemplateArgsAsWritten();
1814+
if (SemaRef.SubstTemplateArgumentsInParameterMapping(
1815+
ArgsAsWritten->arguments(), CC.getBeginLoc(), *MLTAL, Out))
1816+
return true;
1817+
Sema::CheckTemplateArgumentInfo CTAI;
1818+
if (SemaRef.CheckTemplateArgumentList(CSE->getNamedConcept(),
1819+
CSE->getConceptNameInfo().getLoc(), Out,
1820+
/*DefaultArgs=*/{},
1821+
/*PartialTemplateArgs=*/false, CTAI,
1822+
/*UpdateArgsWithConversions=*/false))
1823+
return true;
1824+
auto TemplateArgs = *MLTAL;
1825+
TemplateArgs.replaceOutermostTemplateArguments(
1826+
TemplateArgs.getAssociatedDecl(0).first, CTAI.SugaredConverted);
1827+
return SubstituteParameterMappings(SemaRef, &TemplateArgs, ArgsAsWritten)
1828+
.substitute(CC.getNormalizedConstraint());
1829+
}
1830+
1831+
bool SubstituteParameterMappings::substitute(NormalizedConstraint &N) {
1832+
switch (N.getKind()) {
1833+
case NormalizedConstraint::ConstraintKind::Atomic: {
1834+
if (!MLTAL) {
1835+
assert(!ArgsAsWritten);
1836+
return false;
1837+
}
1838+
return substitute(static_cast<NormalizedConstraintWithParamMapping &>(N));
1839+
}
1840+
case NormalizedConstraint::ConstraintKind::FoldExpanded: {
1841+
auto &FE = static_cast<FoldExpandedConstraint &>(N);
1842+
if (!MLTAL) {
1843+
assert(!ArgsAsWritten);
1844+
return substitute(FE.getNormalizedPattern());
1845+
}
1846+
// FIXME: This is not used.
1847+
ConstraintSatisfaction CS;
1848+
UnsignedOrNone PackSize = EvaluateFoldExpandedConstraintSize(
1849+
SemaRef, FE, /*Template=*/nullptr, /*TemplateNameLoc=*/SourceLocation(),
1850+
*MLTAL, CS);
1851+
if (!PackSize)
1852+
return true;
1853+
1854+
// Do we need to do something else when pack is empty?
1855+
if (!*PackSize)
1856+
return false;
1857+
Sema::ArgPackSubstIndexRAII _(SemaRef, std::nullopt);
1858+
return substitute(FE.getNormalizedPattern());
1859+
}
1860+
case NormalizedConstraint::ConstraintKind::ConceptId: {
1861+
auto &CC = static_cast<ConceptIdConstraint &>(N);
1862+
if (MLTAL) {
1863+
assert(ArgsAsWritten);
1864+
return substitute(CC);
1865+
}
1866+
assert(!ArgsAsWritten);
1867+
const ConceptSpecializationExpr *CSE = CC.getConceptSpecializationExpr();
1868+
ConceptDecl *Concept = CSE->getNamedConcept();
1869+
MultiLevelTemplateArgumentList MLTAL = SemaRef.getTemplateInstantiationArgs(
1870+
Concept, Concept->getLexicalDeclContext(),
1871+
/*Final=*/true, CSE->getTemplateArguments(),
1872+
/*RelativeToPrimary=*/true,
1873+
/*Pattern=*/nullptr,
1874+
/*ForConstraintInstantiation=*/true);
1875+
1876+
// Don't build Subst* nodes to model lambda expressions.
1877+
// The transform of Subst* is oblivious to the lambda type.
1878+
MLTAL.setKind(TemplateSubstitutionKind::Rewrite);
1879+
return SubstituteParameterMappings(SemaRef, &MLTAL,
1880+
CSE->getTemplateArgsAsWritten())
1881+
.substitute(CC.getNormalizedConstraint());
1882+
}
1883+
case NormalizedConstraint::ConstraintKind::Compound: {
1884+
auto &Compound = static_cast<CompoundConstraint &>(N);
1885+
if (substitute(Compound.getLHS()))
1886+
return true;
1887+
return substitute(Compound.getRHS());
1888+
}
1889+
}
1890+
}
1891+
1892+
} // namespace
1893+
#if 0
16421894
static bool
16431895
substituteParameterMappings(Sema &S, NormalizedConstraint &N,
16441896
const MultiLevelTemplateArgumentList &MLTAL,
@@ -1831,9 +2083,8 @@ substituteParameterMappings(Sema &S, NormalizedConstraint &N,
18312083
if (!*PackSize)
18322084
return false;
18332085
Sema::ArgPackSubstIndexRAII _(S, std::nullopt);
1834-
return substituteParameterMappings(
1835-
S, static_cast<FoldExpandedConstraint &>(N).getNormalizedPattern(),
1836-
MLTAL, ArgsAsWritten);
2086+
return substituteParameterMappings(S, FE.getNormalizedPattern(), MLTAL,
2087+
ArgsAsWritten);
18372088
}
18382089
case NormalizedConstraint::ConstraintKind::ConceptId:
18392090
return substituteParameterMappings(S, static_cast<ConceptIdConstraint &>(N),
@@ -1893,6 +2144,7 @@ static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N) {
18932144
}
18942145
}
18952146
}
2147+
#endif
18962148

18972149
NormalizedConstraint *NormalizedConstraint::fromAssociatedConstraints(
18982150
Sema &S, const NamedDecl *D, ArrayRef<AssociatedConstraint> ACs) {
@@ -2024,7 +2276,8 @@ const NormalizedConstraint *Sema::getNormalizedAssociatedConstraints(
20242276
if (!ConstrainedDeclOrNestedReq) {
20252277
auto *Normalized = NormalizedConstraint::fromAssociatedConstraints(
20262278
*this, nullptr, AssociatedConstraints);
2027-
if (!Normalized || substituteParameterMappings(*this, *Normalized))
2279+
if (!Normalized ||
2280+
SubstituteParameterMappings(*this).substitute(*Normalized))
20282281
return nullptr;
20292282

20302283
return Normalized;
@@ -2040,7 +2293,8 @@ const NormalizedConstraint *Sema::getNormalizedAssociatedConstraints(
20402293
CacheEntry =
20412294
NormalizationCache.try_emplace(ConstrainedDeclOrNestedReq, Normalized)
20422295
.first;
2043-
if (!Normalized || substituteParameterMappings(*this, *Normalized))
2296+
if (!Normalized ||
2297+
SubstituteParameterMappings(*this).substitute(*Normalized))
20442298
return nullptr;
20452299
}
20462300
return CacheEntry->second;

clang/lib/Sema/SemaTemplateVariadic.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -836,8 +836,6 @@ bool Sema::CheckParameterPacksForExpansion(
836836
continue;
837837
}
838838

839-
// TemplateArgs(Depth, Index).dump();
840-
841839
// Determine the size of the argument pack.
842840
ArrayRef<TemplateArgument> Pack =
843841
TemplateArgs(Depth, Index).getPackAsArray();

clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ template<typename T> concept True = true;
55
template<typename T> concept Foo = True<T*>; // #Foo
66
template<typename T> concept Bar = Foo<T&>; // #Bar
77
template<typename T> requires Bar<T> struct S { }; // #S
8-
template<typename T> requires Bar<T> && true struct S<T> { };
8+
template<typename T> requires Bar<T> && true struct S<T> { }; // #SpecS
99
// expected-error@-1 {{class template partial specialization is not more specialized than the primary template}}
1010
// expected-error@#Foo 2{{'type name' declared as a pointer to a reference of type 'T &'}}
11-
// expected-note@#Foo 2{{while substituting into concept arguments here}}
11+
// expected-note@#SpecS {{while substituting into concept arguments here}}
12+
// expected-note@#S {{while substituting into concept arguments here}}
1213
// expected-note@#Bar 2{{while substituting into concept arguments here}}
1314
// expected-note@#S {{template is declared here}}
1415

@@ -19,9 +20,9 @@ template<typename T> concept Foo2 = True2<T*>; // #Foo2
1920

2021
template<typename T> concept Bar2 = Foo2<T&>; // #Bar2
2122
// expected-note@-1 3{{while substituting into concept arguments here; substitution failures not allowed in concept arguments}}
22-
template<typename T> requires Bar2<T> struct S2 { };
23+
template<typename T> requires Bar2<T> struct S2 { }; // #SpecS2_1
2324
// expected-note@-1{{template is declared here}}
24-
template<typename T> requires Bar2<T> && true struct S2<T> { };
25+
template<typename T> requires Bar2<T> && true struct S2<T> { }; // #SpecS2_2
2526
// expected-error@-1{{class template partial specialization is not more specialized than the primary template}}
2627
// expected-error@#Foo2{{'type name' declared as a pointer to a reference of type 'T &'}}
2728

@@ -80,24 +81,26 @@ namespace non_type_pack {
8081
namespace PR47174 {
8182
// This checks that we don't crash with a failed substitution on the first constrained argument when
8283
// performing normalization.
83-
template <Bar2 T, True U>
84+
template <Bar2 T, True U> // #S3_Header
8485
requires true struct S3; // expected-note {{template is declared here}}
8586
template <True T, True U>
8687
requires true struct S3<T, U>;
8788
// expected-error@-1 {{class template partial specialization is not more specialized than the primary template}}
8889
// expected-error@#Foo2 2{{'type name' declared as a pointer to a reference of type 'T &'}}
89-
// expected-note@#Foo2 2{{while substituting into concept arguments here}}
90+
// expected-note@#SpecS2_1 {{while substituting into concept arguments here}}
91+
// expected-note@#SpecS2_2 {{while substituting into concept arguments here}}
92+
// expected-note@#S3_Header {{while substituting into concept arguments here}}
9093
// expected-note@#Bar2 {{while substituting into concept arguments here}}
9194

9295

9396
// Same as above, for the second position (but this was already working).
94-
template <True T, Bar2 U>
97+
template <True T, Bar2 U> // #S4_Header
9598
requires true struct S4; // #S4
9699
template <True T, True U>
97100
requires true struct S4<T, U>; // #S4-spec
98101
// expected-error@-1 {{class template partial specialization is not more specialized than the primary template}}
99102
// expected-error@#Foo2 {{'type name' declared as a pointer to a reference of type 'U &'}}
100-
// expected-note@#Foo2 2{{while substituting into concept arguments here}}
103+
// expected-note@#S4_Header {{while substituting into concept arguments here}}
101104
// expected-note@#S4 {{template is declared here}}
102105
// expected-note@#S4 {{similar constraint expressions not considered equivalent}}
103106
// expected-note@#S4-spec {{similar constraint expression here}}

0 commit comments

Comments
 (0)