Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
a8c391c
Use normalization for concept satisfaction
cor3ntin Sep 9, 2025
bfcad78
more build failures
cor3ntin Sep 9, 2025
7d66cd8
I accidentally disabled caching
cor3ntin Sep 9, 2025
ccb3eb0
fix libcxx test
cor3ntin Sep 9, 2025
7ff50be
fix windows build
cor3ntin Sep 9, 2025
badb3f2
format
cor3ntin Sep 9, 2025
3e37bd4
fix libc++ test
cor3ntin Sep 10, 2025
e412201
cleanups
cor3ntin Sep 10, 2025
fc0e116
add fixmes
cor3ntin Sep 10, 2025
e8d251b
fix windows build
cor3ntin Sep 10, 2025
da2022a
more cleanups
cor3ntin Sep 10, 2025
eb3922e
remove some whitespace changes
cor3ntin Sep 10, 2025
90b7a28
fix doc
cor3ntin Sep 10, 2025
d2e310e
more cleanups
cor3ntin Sep 11, 2025
5f239d4
remove some duplication
cor3ntin Sep 11, 2025
c5a8c31
Cache satisfaction of ConceptIdConstraint.
cor3ntin Sep 11, 2025
9361310
more caching
cor3ntin Sep 11, 2025
3aec41a
Fix stdexec regressions (#59)
zyn0217 Sep 12, 2025
aa79712
more cleanups
cor3ntin Sep 12, 2025
905de97
Release note
cor3ntin Sep 12, 2025
7237aaa
Use ordinary substitution for parameter mapping (#60)
zyn0217 Sep 15, 2025
e11c377
fix typos
cor3ntin Sep 15, 2025
0eec94b
fix tests after rebase
cor3ntin Sep 16, 2025
8dc536c
address some of Erich's feedback
cor3ntin Sep 19, 2025
b01c7f5
fix rebase
cor3ntin Sep 19, 2025
56aaa21
remove comment (moved to doc)
cor3ntin Sep 19, 2025
5454d00
Make sure the SubstitutionDiagnostic alias is used consistently
cor3ntin Sep 19, 2025
f2bf57c
fix typos, fix merge
cor3ntin Sep 19, 2025
99b62f0
fix docs
cor3ntin Sep 19, 2025
a160c64
remove unused code
cor3ntin Sep 19, 2025
95911f1
remove more unused code
cor3ntin Sep 19, 2025
536b281
fix docs
cor3ntin Sep 19, 2025
7ecf194
format
cor3ntin Sep 19, 2025
3604567
Deal with parameters used, but not referenced by an atomic constraint
cor3ntin Sep 24, 2025
2843ad3
oups
cor3ntin Sep 24, 2025
a1eb5b5
Fix assert, address feedback, add tests
cor3ntin Sep 24, 2025
ebe396b
pack tests, remove dead code
cor3ntin Sep 24, 2025
38c43e1
fix tests for c++20
cor3ntin Sep 24, 2025
81413f0
restore code that was actually useful
cor3ntin Sep 24, 2025
ab3f023
Merge remote-tracking branch 'llvm_be_very_careful/main' into corenti…
cor3ntin Sep 28, 2025
aa7fcb9
Merge remote-tracking branch 'llvm_be_very_careful/main' into corenti…
cor3ntin Sep 29, 2025
cde4bb7
format
cor3ntin Sep 29, 2025
fdb9bfb
Merge remote-tracking branch 'llvm_be_very_careful/main' into corenti…
cor3ntin Oct 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -12776,6 +12776,18 @@ class Sema final : public SemaBase {
void MarkUsedTemplateParameters(const Expr *E, bool OnlyDeduced,
unsigned Depth, llvm::SmallBitVector &Used);

/// Mark which template parameters are named in a given expression.
///
/// Unlike MarkUsedTemplateParameters, this excludes parameter that
/// are used but not directly named by an expression - ie it excludes
/// any template parameter that denotes the type of a referenced NTTP.
///
/// \param Used a bit vector whose elements will be set to \c true
/// to indicate when the corresponding template parameter will be
/// deduced.
void MarkUsedTemplateParametersForSubsumptionParameterMapping(
const Expr *E, unsigned Depth, llvm::SmallBitVector &Used);

/// Mark which template parameters can be deduced from a given
/// template argument list.
///
Expand Down
36 changes: 32 additions & 4 deletions clang/include/clang/Sema/SemaConcept.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,15 @@ struct NormalizedConstraint {
unsigned Kind : 5;
unsigned Placeholder : 1;
unsigned PackSubstitutionIndex : 26;
// Indexes and Args are part of the common initial sequences
// of constraints that do have a mapping.
// Indexes, IndexesForSubsumption, and Args are part of the common initial
// sequences of constraints that do have a mapping.

// Indexes of the parameters used in a constraint expression.
OccurenceList Indexes;
// Indexes of the parameters named directly in a constraint expression.
// FIXME: we should try to reduce the size of this struct?
OccurenceList IndexesForSubsumption;

TemplateArgumentLoc *Args;
TemplateParameterList *ParamList;
ExprOrConcept ConstraintExpr;
Expand All @@ -77,6 +83,7 @@ struct NormalizedConstraint {
unsigned FoldOperator : 1;
unsigned Placeholder : 26;
OccurenceList Indexes;
OccurenceList IndexesForSubsumption;
TemplateArgumentLoc *Args;
TemplateParameterList *ParamList;
const Expr *Pattern;
Expand Down Expand Up @@ -119,6 +126,7 @@ struct NormalizedConstraint {
/*Placeholder=*/0,
PackIndex.toInternalRepresentation(),
/*Indexes=*/{},
/*IndexesForSubsumption=*/{},
/*Args=*/nullptr,
/*ParamList=*/nullptr,
ConstraintExpr,
Expand All @@ -131,6 +139,7 @@ struct NormalizedConstraint {
llvm::to_underlying(OpKind),
/*Placeholder=*/0,
/*Indexes=*/{},
/*IndexesForSubsumption=*/{},
/*Args=*/nullptr,
/*ParamList=*/nullptr,
Pattern,
Expand All @@ -145,6 +154,7 @@ struct NormalizedConstraint {
: ConceptId{{llvm::to_underlying(ConstraintKind::ConceptId),
/*Placeholder=*/0, PackIndex.toInternalRepresentation(),
/*Indexes=*/{},
/*IndexesForSubsumption=*/{},
/*Args=*/nullptr, /*ParamList=*/nullptr, ConceptId,
ConstraintDecl},
SubConstraint,
Expand All @@ -166,6 +176,11 @@ struct NormalizedConstraint {
return Atomic.Indexes;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not there yet, but exposing the OccurenceList outside of this type seems like a mistake. Can we instead have this interface let you 'ask' the questions you mean?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's copied entirely in in SubstituteParameterMappings::substitute, so it needs to be exposed

}

const OccurenceList &mappingOccurenceListForSubsumption() const {
assert(hasParameterMapping() && "This constraint has no parameter mapping");
return Atomic.IndexesForSubsumption;
}

llvm::MutableArrayRef<TemplateArgumentLoc> getParameterMapping() const {
return {Atomic.Args, Atomic.Indexes.count()};
}
Expand All @@ -175,11 +190,16 @@ struct NormalizedConstraint {
}

void updateParameterMapping(OccurenceList Indexes,
OccurenceList IndexesForSubsumption,
llvm::MutableArrayRef<TemplateArgumentLoc> Args,
TemplateParameterList *ParamList) {
assert(getKind() != ConstraintKind::Compound);
assert(Indexes.count() == Args.size());
Atomic.Indexes = Indexes;
assert(IndexesForSubsumption.size() == Indexes.size());
assert((Indexes & IndexesForSubsumption) == Indexes);

Atomic.IndexesForSubsumption = std::move(IndexesForSubsumption);
Atomic.Indexes = std::move(Indexes);
Atomic.Args = Args.data();
Atomic.ParamList = ParamList;
}
Expand All @@ -198,10 +218,17 @@ struct NormalizedConstraint {
llvm::ArrayRef<TemplateArgumentLoc> OtherParameterMapping =
Other.getParameterMapping();

const OccurenceList &Indexes = mappingOccurenceListForSubsumption();
const OccurenceList &OtherIndexes =
Other.mappingOccurenceListForSubsumption();

if (ParameterMapping.size() != OtherParameterMapping.size())
return false;

for (unsigned I = 0, S = ParameterMapping.size(); I < S; ++I) {
if (Indexes[I] != OtherIndexes[I])
return false;
if (!Indexes[I])
continue;
llvm::FoldingSetNodeID IDA, IDB;
C.getCanonicalTemplateArgument(ParameterMapping[I].getArgument())
.Profile(IDA, C);
Expand Down Expand Up @@ -296,6 +323,7 @@ class NormalizedConstraintWithParamMapping : public NormalizedConstraint {
using NormalizedConstraint::hasMatchingParameterMapping;
using NormalizedConstraint::hasParameterMapping;
using NormalizedConstraint::mappingOccurenceList;
using NormalizedConstraint::mappingOccurenceListForSubsumption;
using NormalizedConstraint::updateParameterMapping;

const NamedDecl *getConstraintDecl() const { return Atomic.ConstraintDecl; }
Expand Down
33 changes: 20 additions & 13 deletions clang/lib/Sema/SemaConcept.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1919,25 +1919,28 @@ void SubstituteParameterMappings::buildParameterMapping(
cast<TemplateDecl>(N.getConstraintDecl())->getTemplateParameters();

llvm::SmallBitVector OccurringIndices(TemplateParams->size());
llvm::SmallBitVector OccurringIndicesForSubsumption(TemplateParams->size());

if (N.getKind() == NormalizedConstraint::ConstraintKind::Atomic) {
SemaRef.MarkUsedTemplateParameters(
static_cast<AtomicConstraint &>(N).getConstraintExpr(),
/*OnlyDeduced=*/false,
/*Depth=*/0, OccurringIndices);

SemaRef.MarkUsedTemplateParametersForSubsumptionParameterMapping(
static_cast<AtomicConstraint &>(N).getConstraintExpr(),
/*Depth=*/0, OccurringIndicesForSubsumption);

Comment on lines +1929 to +1933
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think this is applicable to FoldExprs?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did some testing and i can't get it to failed without it, so I removed it!

} else if (N.getKind() ==
NormalizedConstraint::ConstraintKind::FoldExpanded) {
SemaRef.MarkUsedTemplateParameters(
static_cast<FoldExpandedConstraint &>(N).getPattern(),
/*OnlyDeduced=*/false,
/*Depth=*/0, OccurringIndices);
} else if (N.getKind() == NormalizedConstraint::ConstraintKind::ConceptId) {
auto *Args = static_cast<ConceptIdConstraint &>(N)
.getConceptId()
->getTemplateArgsAsWritten();
if (Args)
SemaRef.MarkUsedTemplateParameters(Args->arguments(),
/*Depth=*/0, OccurringIndices);

SemaRef.MarkUsedTemplateParametersForSubsumptionParameterMapping(
static_cast<FoldExpandedConstraint &>(N).getPattern(),
/*Depth=*/0, OccurringIndicesForSubsumption);
}
TemplateArgumentLoc *TempArgs =
new (SemaRef.Context) TemplateArgumentLoc[OccurringIndices.count()];
Expand All @@ -1962,7 +1965,7 @@ void SubstituteParameterMappings::buildParameterMapping(
/*RAngleLoc=*/SourceLocation(),
/*RequiresClause=*/nullptr);
N.updateParameterMapping(
OccurringIndices,
std::move(OccurringIndices), std::move(OccurringIndicesForSubsumption),
MutableArrayRef<TemplateArgumentLoc>{TempArgs, OccurringIndices.count()},
UsedList);
}
Expand Down Expand Up @@ -2023,7 +2026,8 @@ bool SubstituteParameterMappings::substitute(

MutableArrayRef<TemplateArgumentLoc> Mapping(TempArgs,
CTAI.SugaredConverted.size());
N.updateParameterMapping(N.mappingOccurenceList(), Mapping,
N.updateParameterMapping(N.mappingOccurenceList(),
N.mappingOccurenceListForSubsumption(), Mapping,
N.getUsedTemplateParamList());
return false;
}
Expand Down Expand Up @@ -2481,10 +2485,13 @@ auto SubsumptionChecker::find(const AtomicConstraint *Ori) -> Literal {
ID.AddBoolean(Ori->hasParameterMapping());
if (Ori->hasParameterMapping()) {
const auto &Mapping = Ori->getParameterMapping();
for (const TemplateArgumentLoc &TAL : Mapping) {
SemaRef.getASTContext()
.getCanonicalTemplateArgument(TAL.getArgument())
.Profile(ID, SemaRef.getASTContext());
const NormalizedConstraint::OccurenceList &Indexes =
Ori->mappingOccurenceListForSubsumption();
for (auto [Idx, TAL] : llvm::enumerate(Mapping)) {
if (Indexes[Idx])
SemaRef.getASTContext()
.getCanonicalTemplateArgument(TAL.getArgument())
.Profile(ID, SemaRef.getASTContext());
}
}
auto It = Elems.find(ID);
Expand Down
17 changes: 13 additions & 4 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6702,10 +6702,11 @@ namespace {
struct MarkUsedTemplateParameterVisitor : DynamicRecursiveASTVisitor {
llvm::SmallBitVector &Used;
unsigned Depth;
bool VisitDeclRefTypes = true;

MarkUsedTemplateParameterVisitor(llvm::SmallBitVector &Used,
unsigned Depth)
: Used(Used), Depth(Depth) { }
MarkUsedTemplateParameterVisitor(llvm::SmallBitVector &Used, unsigned Depth,
bool VisitDeclRefTypes = true)
: Used(Used), Depth(Depth), VisitDeclRefTypes(VisitDeclRefTypes) {}

bool VisitTemplateTypeParmType(TemplateTypeParmType *T) override {
if (T->getDepth() == Depth)
Expand All @@ -6726,7 +6727,8 @@ struct MarkUsedTemplateParameterVisitor : DynamicRecursiveASTVisitor {
if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(E->getDecl()))
if (NTTP->getDepth() == Depth)
Used[NTTP->getIndex()] = true;
DynamicRecursiveASTVisitor::TraverseType(E->getType());
if (VisitDeclRefTypes)
DynamicRecursiveASTVisitor::TraverseType(E->getType());
return true;
}

Expand Down Expand Up @@ -7176,6 +7178,13 @@ Sema::MarkUsedTemplateParameters(const Expr *E, bool OnlyDeduced,
::MarkUsedTemplateParameters(Context, E, OnlyDeduced, Depth, Used);
}

void Sema::MarkUsedTemplateParametersForSubsumptionParameterMapping(
const Expr *E, unsigned Depth, llvm::SmallBitVector &Used) {
MarkUsedTemplateParameterVisitor(Used, Depth, /*VisitDeclRefTypes=*/false)
.TraverseStmt(const_cast<Expr *>(E));
return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return;

}

void
Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
bool OnlyDeduced, unsigned Depth,
Expand Down
7 changes: 2 additions & 5 deletions clang/test/SemaTemplate/instantiate-template-argument.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,17 @@ constexpr int foo() requires C2<int, W> { return 1; } // #cand1
// sizeof(U) >= 4 [U = W (decltype(int{}))]

template<char X>
// expected-note@+1{{candidate function}}
constexpr int foo() requires C1<1, X> && true { return 2; } // #cand2
// sizeof(U) >= 4 [U = X (decltype(1))]

static_assert(foo<'a'>() == 2);
// expected-error@-1 {{call to 'foo' is ambiguous}}
// expected-note@#cand1 {{candidate function}}
// expected-note@#cand2 {{candidate function}}


template<char Z>
constexpr int foo() requires C2<long long, Z> && true { return 3; } // #cand3
// sizeof(U) >= 4 [U = Z (decltype(long long{}))]

static_assert(foo<'a'>() == 3);
// expected-error@-1{{call to 'foo' is ambiguous}}
// expected-note@#cand1 {{candidate function}}
// expected-note@#cand2 {{candidate function}}
// expected-note@#cand3 {{candidate function}}
Loading