Skip to content

Commit 38b63c0

Browse files
authored
Merge pull request #51 from zyn0217/fix-concepts-cache
Fix the parameter mapping complexity
2 parents 1650151 + 3b737ae commit 38b63c0

File tree

5 files changed

+156
-41
lines changed

5 files changed

+156
-41
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
#include "clang/Sema/Redeclaration.h"
6666
#include "clang/Sema/Scope.h"
6767
#include "clang/Sema/SemaBase.h"
68+
#include "clang/Sema/SemaConcept.h"
6869
#include "clang/Sema/TypoCorrection.h"
6970
#include "clang/Sema/Weak.h"
7071
#include "llvm/ADT/APInt.h"

clang/include/clang/Sema/SemaConcept.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ struct NormalizedConstraint {
8989

9090
struct ConceptIdBits : AtomicBits {
9191
NormalizedConstraint *Sub;
92+
93+
// Only used for parameter mapping.
94+
const ConceptSpecializationExpr *CSE;
9295
};
9396

9497
struct CompoundBits {
@@ -138,13 +141,15 @@ struct NormalizedConstraint {
138141
NormalizedConstraint(const ConceptReference *ConceptId,
139142
const NamedDecl *ConstraintDecl,
140143
NormalizedConstraint *SubConstraint,
144+
const ConceptSpecializationExpr *CSE,
141145
UnsignedOrNone PackIndex)
142146
: ConceptId{{llvm::to_underlying(ConstraintKind::ConceptId),
143147
/*Placeholder=*/0, PackIndex.toInternalRepresentation(),
144148
/*Indexes=*/{},
145149
/*Args=*/nullptr, /*ParamList=*/nullptr, ConceptId,
146150
ConstraintDecl},
147-
SubConstraint} {}
151+
SubConstraint,
152+
CSE} {}
148153

149154
NormalizedConstraint(NormalizedConstraint *LHS, CompoundConstraintKind CCK,
150155
NormalizedConstraint *RHS)
@@ -357,9 +362,14 @@ class ConceptIdConstraint : public NormalizedConstraintWithParamMapping {
357362
const ConceptReference *ConceptId,
358363
NormalizedConstraint *SubConstraint,
359364
const NamedDecl *ConstraintDecl,
365+
const ConceptSpecializationExpr *CSE,
360366
UnsignedOrNone PackIndex) {
361367
return new (Ctx) ConceptIdConstraint(ConceptId, ConstraintDecl,
362-
SubConstraint, PackIndex);
368+
SubConstraint, CSE, PackIndex);
369+
}
370+
371+
const ConceptSpecializationExpr *getConceptSpecializationExpr() const {
372+
return ConceptId.CSE;
363373
}
364374

365375
const ConceptReference *getConceptId() const {

clang/lib/Sema/SemaConcept.cpp

Lines changed: 141 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "clang/AST/Decl.h"
1818
#include "clang/AST/DeclCXX.h"
1919
#include "clang/AST/DeclTemplate.h"
20+
#include "clang/AST/DependenceFlags.h"
2021
#include "clang/AST/Expr.h"
2122
#include "clang/AST/ExprConcepts.h"
2223
#include "clang/AST/TemplateBase.h"
@@ -35,6 +36,8 @@
3536
#include "llvm/ADT/PointerUnion.h"
3637
#include "llvm/ADT/SmallVector.h"
3738
#include "llvm/ADT/StringExtras.h"
39+
#include "llvm/Support/Timer.h"
40+
#include "llvm/Support/WithColor.h"
3841
#include <cstddef>
3942
#include <optional>
4043

@@ -390,16 +393,23 @@ SubstitutionInTemplateArguments(
390393
Constraint.mappingOccurenceList();
391394
SubstitutedOuterMost =
392395
llvm::to_vector_of<TemplateArgument>(MLTAL.getOutermost());
396+
unsigned Offset = 0;
393397
for (unsigned I = 0, MappedIndex = 0; I < Used.size(); I++) {
394398
TemplateArgument Arg;
395399
if (Used[I])
396400
Arg = S.Context.getCanonicalTemplateArgument(
397401
CTAI.SugaredConverted[MappedIndex++]);
398-
if (I < SubstitutedOuterMost.size())
402+
if (I < SubstitutedOuterMost.size()) {
399403
SubstitutedOuterMost[I] = Arg;
400-
else
404+
Offset = I + 1;
405+
} else {
401406
SubstitutedOuterMost.push_back(Arg);
407+
Offset = SubstitutedOuterMost.size();
408+
}
402409
}
410+
if (Offset < SubstitutedOuterMost.size())
411+
SubstitutedOuterMost.erase(SubstitutedOuterMost.begin() + Offset);
412+
403413
MLTAL.replaceOutermostTemplateArguments(
404414
const_cast<NamedDecl *>(Constraint.getConstraintDecl()),
405415
SubstitutedOuterMost);
@@ -585,6 +595,19 @@ static bool calculateConstraintSatisfaction(
585595
ConstraintSatisfaction &Satisfaction,
586596
UnsignedOrNone PackSubstitutionIndex) {
587597

598+
// If the expression has been calculated, e.g. when we are in a nested
599+
// requirement, do not compute it repeatedly.
600+
if (auto *Expr = Constraint.getConceptSpecializationExpr();
601+
Expr && Expr->getDependence() == ExprDependence::None) {
602+
auto &Calculated = Expr->getSatisfaction();
603+
Satisfaction.ContainsErrors = Calculated.ContainsErrors;
604+
Satisfaction.IsSatisfied = Calculated.IsSatisfied;
605+
Satisfaction.Details.insert(Satisfaction.Details.end(),
606+
Calculated.records().begin(),
607+
Calculated.records().end());
608+
return !Satisfaction.ContainsErrors;
609+
}
610+
588611
Sema::ContextRAII CurContext(
589612
S, Constraint.getConceptId()->getNamedConcept()->getDeclContext(),
590613
/*NewThisContext=*/false);
@@ -765,7 +788,8 @@ static bool CheckConstraintSatisfaction(
765788
if (TopLevelConceptId) {
766789
C = ConceptIdConstraint::Create(S.getASTContext(), TopLevelConceptId,
767790
const_cast<NormalizedConstraint *>(C),
768-
Template, S.ArgPackSubstIndex);
791+
Template, /*CSE=*/nullptr,
792+
S.ArgPackSubstIndex);
769793
}
770794

771795
return !calculateConstraintSatisfaction(
@@ -1535,26 +1559,6 @@ void Sema::DiagnoseUnsatisfiedConstraint(
15351559
ConstraintExpr->getBeginLoc(), First);
15361560
}
15371561

1538-
const NormalizedConstraint *Sema::getNormalizedAssociatedConstraints(
1539-
ConstrainedDeclOrNestedRequirement ConstrainedDeclOrNestedReq,
1540-
ArrayRef<AssociatedConstraint> AssociatedConstraints) {
1541-
if (!ConstrainedDeclOrNestedReq)
1542-
return NormalizedConstraint::fromAssociatedConstraints(
1543-
*this, nullptr, AssociatedConstraints);
1544-
1545-
const NamedDecl *ND =
1546-
ConstrainedDeclOrNestedReq.dyn_cast<const NamedDecl *>();
1547-
auto CacheEntry = NormalizationCache.find(ConstrainedDeclOrNestedReq);
1548-
if (CacheEntry == NormalizationCache.end()) {
1549-
auto *Normalized = NormalizedConstraint::fromAssociatedConstraints(
1550-
*this, ND, AssociatedConstraints);
1551-
CacheEntry =
1552-
NormalizationCache.try_emplace(ConstrainedDeclOrNestedReq, Normalized)
1553-
.first;
1554-
}
1555-
return CacheEntry->second;
1556-
}
1557-
15581562
static bool
15591563
substituteParameterMappings(Sema &S, NormalizedConstraint &N,
15601564
const MultiLevelTemplateArgumentList &MLTAL,
@@ -1591,6 +1595,8 @@ substituteParameterMappings(Sema &S, NormalizedConstraintWithParamMapping &N,
15911595
SourceLocation Loc = ArgsAsWritten->NumTemplateArgs > I
15921596
? ArgsAsWritten->arguments()[I].getLocation()
15931597
: SourceLocation();
1598+
// FIXME: Investigate when we couldn't preserve the SourceLoc. What shall we do??
1599+
// assert(Loc.isValid());
15941600
if (OccurringIndices[I]) {
15951601
NamedDecl *Param = TemplateParams->begin()[I];
15961602
new (&(TempArgs)[J])
@@ -1624,6 +1630,7 @@ substituteParameterMappings(Sema &S, NormalizedConstraintWithParamMapping &N,
16241630
{InstLocBegin, InstLocEnd});
16251631
if (Inst.isInvalid())
16261632
return true;
1633+
16271634
// TransformTemplateArguments is unable to preserve the source location of a
16281635
// pack. The SourceLocation is necessary for the instantiation location.
16291636
// FIXME: The BaseLoc will be used as the location of the pack expansion,
@@ -1646,16 +1653,17 @@ substituteParameterMappings(Sema &S, NormalizedConstraintWithParamMapping &N,
16461653
// If this is an empty pack, we have no corresponding SubstArgs.
16471654
if (I < SubstArgs.size())
16481655
Loc = SubstArgs.arguments()[I].getLocation();
1656+
// assert(Loc.isValid());
16491657
TempArgs[I] = S.getTrivialTemplateArgumentLoc(CTAI.SugaredConverted[I],
16501658
QualType(), Loc);
16511659
}
16521660
// llvm::copy(SubstArgs.arguments(), TempArgs);
16531661
// N.updateParameterMapping(
16541662
// N.mappingOccurenceList(),
16551663
// MutableArrayRef<TemplateArgumentLoc>(TempArgs, SubstArgs.size()));
1656-
N.updateParameterMapping(N.mappingOccurenceList(),
1657-
MutableArrayRef<TemplateArgumentLoc>(
1658-
TempArgs, CTAI.SugaredConverted.size()),
1664+
MutableArrayRef<TemplateArgumentLoc> Mapping(TempArgs,
1665+
CTAI.SugaredConverted.size());
1666+
N.updateParameterMapping(N.mappingOccurenceList(), Mapping,
16591667
N.getUsedTemplateParamList());
16601668
return false;
16611669
}
@@ -1664,14 +1672,59 @@ static bool
16641672
substituteParameterMappings(Sema &S, ConceptIdConstraint &N,
16651673
const MultiLevelTemplateArgumentList &MLTAL,
16661674
const ASTTemplateArgumentListInfo *ArgsAsWritten) {
1667-
1675+
assert(N.getConstraintDecl());
1676+
#if 0
1677+
return substituteParameterMappings(
1678+
S, static_cast<NormalizedConstraintWithParamMapping &>(N), MLTAL,
1679+
ArgsAsWritten);
1680+
#else
1681+
auto TemplateArgs = MLTAL;
16681682
if (N.getConstraintDecl()) {
1669-
substituteParameterMappings(
1670-
S, static_cast<NormalizedConstraintWithParamMapping &>(N), MLTAL,
1671-
ArgsAsWritten);
1683+
if (substituteParameterMappings(
1684+
S, static_cast<NormalizedConstraintWithParamMapping &>(N),
1685+
TemplateArgs, ArgsAsWritten))
1686+
return true;
1687+
auto *CSE = N.getConceptSpecializationExpr();
1688+
assert(CSE);
1689+
TemplateArgumentListInfo Out;
1690+
assert(!N.getBeginLoc().isInvalid());
1691+
// TransformTemplateArguments is unable to preserve the source location of a
1692+
// pack. The SourceLocation is necessary for the instantiation location.
1693+
// FIXME: The BaseLoc will be used as the location of the pack expansion,
1694+
// which is wrong.
1695+
ArgsAsWritten = CSE->getTemplateArgsAsWritten();
1696+
SourceLocation InstLocBegin =
1697+
ArgsAsWritten->arguments().empty()
1698+
? ArgsAsWritten->getLAngleLoc()
1699+
: ArgsAsWritten->arguments().front().getSourceRange().getBegin();
1700+
SourceLocation InstLocEnd =
1701+
ArgsAsWritten->arguments().empty()
1702+
? ArgsAsWritten->getRAngleLoc()
1703+
: ArgsAsWritten->arguments().front().getSourceRange().getEnd();
1704+
Sema::InstantiatingTemplate Inst(
1705+
S, InstLocBegin,
1706+
Sema::InstantiatingTemplate::ParameterMappingSubstitution{},
1707+
const_cast<NamedDecl *>(N.getConstraintDecl()),
1708+
{InstLocBegin, InstLocEnd});
1709+
if (Inst.isInvalid())
1710+
return true;
1711+
1712+
if (S.SubstTemplateArgumentsInParameterMapping(ArgsAsWritten->arguments(),
1713+
N.getBeginLoc(), MLTAL, Out))
1714+
return true;
1715+
Sema::CheckTemplateArgumentInfo CTAI;
1716+
if (S.CheckTemplateArgumentList(CSE->getNamedConcept(),
1717+
CSE->getConceptNameInfo().getLoc(), Out,
1718+
/*DefaultArgs=*/{},
1719+
/*PartialTemplateArgs=*/false, CTAI,
1720+
/*UpdateArgsWithConversions=*/false))
1721+
return true;
1722+
TemplateArgs.replaceOutermostTemplateArguments(
1723+
TemplateArgs.getAssociatedDecl(0).first, CTAI.CanonicalConverted);
16721724
}
1673-
return substituteParameterMappings(S, N.getNormalizedConstraint(), MLTAL,
1674-
ArgsAsWritten);
1725+
return substituteParameterMappings(S, N.getNormalizedConstraint(),
1726+
TemplateArgs, ArgsAsWritten);
1727+
#endif
16751728
}
16761729

16771730
static bool
@@ -1714,10 +1767,40 @@ static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
17141767
// Don't build Subst* nodes to model lambda expressions.
17151768
// The transform of Subst* is oblivious to the lambda type.
17161769
MLTAL.setKind(TemplateSubstitutionKind::Rewrite);
1770+
Sema::InstantiatingTemplate Inst(
1771+
S, N.getBeginLoc(),
1772+
Sema::InstantiatingTemplate::ParameterMappingSubstitution{},
1773+
CSE->getNamedConcept(), {N.getBeginLoc(), N.getEndLoc()});
1774+
if (Inst.isInvalid())
1775+
return true;
1776+
17171777
return substituteParameterMappings(S, N, MLTAL,
17181778
CSE->getTemplateArgsAsWritten());
17191779
}
17201780

1781+
static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N) {
1782+
switch (N.getKind()) {
1783+
case NormalizedConstraint::ConstraintKind::Atomic:
1784+
return false;
1785+
case NormalizedConstraint::ConstraintKind::FoldExpanded: {
1786+
Sema::ArgPackSubstIndexRAII _(S, std::nullopt);
1787+
return substituteParameterMappings(
1788+
S, static_cast<FoldExpandedConstraint &>(N).getNormalizedPattern());
1789+
}
1790+
case NormalizedConstraint::ConstraintKind::ConceptId: {
1791+
auto &CC = static_cast<ConceptIdConstraint &>(N);
1792+
return substituteParameterMappings(S, CC.getNormalizedConstraint(),
1793+
CC.getConceptSpecializationExpr());
1794+
}
1795+
case NormalizedConstraint::ConstraintKind::Compound: {
1796+
auto &Compound = static_cast<CompoundConstraint &>(N);
1797+
if (substituteParameterMappings(S, Compound.getLHS()))
1798+
return true;
1799+
return substituteParameterMappings(S, Compound.getRHS());
1800+
}
1801+
}
1802+
}
1803+
17211804
NormalizedConstraint *NormalizedConstraint::fromAssociatedConstraints(
17221805
Sema &S, const NamedDecl *D, ArrayRef<AssociatedConstraint> ACs) {
17231806
assert(ACs.size() != 0);
@@ -1796,11 +1879,11 @@ NormalizedConstraint *NormalizedConstraint::fromConstraintExpr(
17961879
if (!SubNF)
17971880
return nullptr;
17981881
}
1799-
if (substituteParameterMappings(S, *SubNF, CSE))
1800-
return nullptr;
1882+
// if (substituteParameterMappings(S, *SubNF, CSE))
1883+
// return nullptr;
18011884

18021885
return ConceptIdConstraint::Create(
1803-
S.getASTContext(), CSE->getConceptReference(), SubNF, D, SubstIndex);
1886+
S.getASTContext(), CSE->getConceptReference(), SubNF, D, CSE, SubstIndex);
18041887

18051888
} else if (auto *FE = dyn_cast<const CXXFoldExpr>(E);
18061889
FE && S.getLangOpts().CPlusPlus26 &&
@@ -1842,6 +1925,29 @@ NormalizedConstraint *NormalizedConstraint::fromConstraintExpr(
18421925
return AtomicConstraint::Create(S.getASTContext(), E, D, SubstIndex);
18431926
}
18441927

1928+
const NormalizedConstraint *Sema::getNormalizedAssociatedConstraints(
1929+
ConstrainedDeclOrNestedRequirement ConstrainedDeclOrNestedReq,
1930+
ArrayRef<AssociatedConstraint> AssociatedConstraints) {
1931+
if (!ConstrainedDeclOrNestedReq)
1932+
return NormalizedConstraint::fromAssociatedConstraints(
1933+
*this, nullptr, AssociatedConstraints);
1934+
1935+
// FIXME: ConstrainedDeclOrNestedReq is never a NestedRequirement!
1936+
const NamedDecl *ND =
1937+
ConstrainedDeclOrNestedReq.dyn_cast<const NamedDecl *>();
1938+
auto CacheEntry = NormalizationCache.find(ConstrainedDeclOrNestedReq);
1939+
if (CacheEntry == NormalizationCache.end()) {
1940+
auto *Normalized = NormalizedConstraint::fromAssociatedConstraints(
1941+
*this, ND, AssociatedConstraints);
1942+
CacheEntry =
1943+
NormalizationCache.try_emplace(ConstrainedDeclOrNestedReq, Normalized)
1944+
.first;
1945+
if (!Normalized || substituteParameterMappings(*this, *Normalized))
1946+
return nullptr;
1947+
}
1948+
return CacheEntry->second;
1949+
}
1950+
18451951
bool FoldExpandedConstraint::AreCompatibleForSubsumption(
18461952
const FoldExpandedConstraint &A, const FoldExpandedConstraint &B) {
18471953

clang/lib/Sema/TreeTransform.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3714,10 +3714,6 @@ class TreeTransform {
37143714
ParentContext);
37153715
}
37163716

3717-
/// Build a new Objective-C boxed expression.
3718-
///
3719-
/// By default, performs semantic analysis to build the new expression.
3720-
/// Subclasses may override this routine to provide different behavior.
37213717
ExprResult RebuildConceptSpecializationExpr(NestedNameSpecifierLoc NNS,
37223718
SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
37233719
NamedDecl *FoundDecl, ConceptDecl *NamedConcept,

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
// RUN: %clang_cc1 -std=c++2a -x c++ -verify %s
2+
// FIXME: RUN: %clang_cc1 -std=c++2c -x c++ -verify %s
23

34
template<typename T> concept True = true;
45
template<typename T> concept Foo = True<T*>;
56
template<typename T> concept Bar = Foo<T&>;
67
template<typename T> requires Bar<T> struct S { };
8+
// FIXME: GCC rejects: https://gcc.godbolt.org/z/c9G7G6PTx if the specialization is present.
79
template<typename T> requires Bar<T> && true struct S<T> { };
810

911
template<typename T> concept True2 = sizeof(T) >= 0;

0 commit comments

Comments
 (0)