[clang] 92d8313 - [Clang] Fix concept paramater mapping and caching (#161994)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Oct 4 22:04:41 PDT 2025
Author: Younan Zhang
Date: 2025-10-05T13:04:36+08:00
New Revision: 92d83134b44161cad50198e663b543b46d25b45a
URL: https://github.com/llvm/llvm-project/commit/92d83134b44161cad50198e663b543b46d25b45a
DIFF: https://github.com/llvm/llvm-project/commit/92d83134b44161cad50198e663b543b46d25b45a.diff
LOG: [Clang] Fix concept paramater mapping and caching (#161994)
This expression is not handled by default in RAV, so our parameter
mapping and cache mechanism don't work when it appears in a template
argument list.
There are a few other expressions, such as PackIndexingExpr and
FunctionParmPackExpr, which are also no-ops by default. I don't have a
test case for them now, so let's leave those until users complain :/
There was also a bug in updating the parameter mapping, where the
AssociatedDecl was not updated accordingly.
Also also, this fixes another regression reported in
https://github.com/llvm/llvm-project/pull/161671#issuecomment-3367225480,
where we failed to account for the variable initializer in cache
profiling.
Relies on #161671
Fixes https://github.com/llvm/llvm-project/issues/161983
Fixes https://github.com/llvm/llvm-project/issues/161987
Added:
Modified:
clang/lib/Sema/SemaConcept.cpp
clang/lib/Sema/SemaTemplateDeduction.cpp
clang/test/SemaTemplate/concepts.cpp
Removed:
################################################################################
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 8413090e7ebd1..11d2d5c3938c1 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -264,14 +264,6 @@ class HashParameterMapping : public RecursiveASTVisitor<HashParameterMapping> {
UnsignedOrNone OuterPackSubstIndex;
- TemplateArgument getPackSubstitutedTemplateArgument(TemplateArgument Arg) {
- assert(*SemaRef.ArgPackSubstIndex < Arg.pack_size());
- Arg = Arg.pack_begin()[*SemaRef.ArgPackSubstIndex];
- if (Arg.isPackExpansion())
- Arg = Arg.getPackExpansionPattern();
- return Arg;
- }
-
bool shouldVisitTemplateInstantiations() const { return true; }
public:
@@ -294,7 +286,7 @@ class HashParameterMapping : public RecursiveASTVisitor<HashParameterMapping> {
assert(Arg.getKind() == TemplateArgument::Pack &&
"Missing argument pack");
- Arg = getPackSubstitutedTemplateArgument(Arg);
+ Arg = SemaRef.getPackSubstitutedTemplateArgument(Arg);
}
UsedTemplateArgs.push_back(
@@ -312,7 +304,7 @@ class HashParameterMapping : public RecursiveASTVisitor<HashParameterMapping> {
if (NTTP->isParameterPack() && SemaRef.ArgPackSubstIndex) {
assert(Arg.getKind() == TemplateArgument::Pack &&
"Missing argument pack");
- Arg = getPackSubstitutedTemplateArgument(Arg);
+ Arg = SemaRef.getPackSubstitutedTemplateArgument(Arg);
}
UsedTemplateArgs.push_back(
@@ -325,8 +317,11 @@ class HashParameterMapping : public RecursiveASTVisitor<HashParameterMapping> {
}
bool TraverseDecl(Decl *D) {
- if (auto *VD = dyn_cast<ValueDecl>(D))
+ if (auto *VD = dyn_cast<ValueDecl>(D)) {
+ if (auto *Var = dyn_cast<VarDecl>(VD))
+ TraverseStmt(Var->getInit());
return TraverseType(VD->getType());
+ }
return inherited::TraverseDecl(D);
}
@@ -363,6 +358,14 @@ class HashParameterMapping : public RecursiveASTVisitor<HashParameterMapping> {
return inherited::TraverseTemplateArgument(Arg);
}
+ bool TraverseSizeOfPackExpr(SizeOfPackExpr *SOPE) {
+ return TraverseDecl(SOPE->getPack());
+ }
+
+ bool VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *E) {
+ return inherited::TraverseStmt(E->getReplacement());
+ }
+
void VisitConstraint(const NormalizedConstraintWithParamMapping &Constraint) {
if (!Constraint.hasParameterMapping()) {
for (const auto &List : TemplateArgs)
@@ -2083,8 +2086,8 @@ bool SubstituteParameterMappings::substitute(ConceptIdConstraint &CC) {
/*UpdateArgsWithConversions=*/false))
return true;
auto TemplateArgs = *MLTAL;
- TemplateArgs.replaceOutermostTemplateArguments(
- TemplateArgs.getAssociatedDecl(0).first, CTAI.SugaredConverted);
+ TemplateArgs.replaceOutermostTemplateArguments(CSE->getNamedConcept(),
+ CTAI.SugaredConverted);
return SubstituteParameterMappings(SemaRef, &TemplateArgs, ArgsAsWritten,
InFoldExpr)
.substitute(CC.getNormalizedConstraint());
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 6bba505ece07d..3baa9775a49e4 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -6718,6 +6718,10 @@ struct MarkUsedTemplateParameterVisitor : DynamicRecursiveASTVisitor {
}
return true;
}
+
+ bool TraverseSizeOfPackExpr(SizeOfPackExpr *SOPE) override {
+ return TraverseDecl(SOPE->getPack());
+ }
};
}
diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp
index 6d29f8b798e73..e5e081ffb9d0f 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -1333,4 +1333,75 @@ static_assert(__cpp17_iterator<not_move_constructible>); \
// expected-note@#is_move_constructible_v {{because 'is_move_constructible_v<parameter_mapping_regressions::case3::not_move_constructible>' evaluated to false}}
}
+namespace case4 {
+
+template<bool b>
+concept bool_ = b;
+
+template<typename... Ts>
+concept unary = bool_<sizeof...(Ts) == 1>;
+
+static_assert(!unary<>);
+static_assert(unary<void>);
+
+}
+
+namespace case5 {
+
+template<int size>
+concept true1 = size == size;
+
+template<typename... Ts>
+concept true2 = true1<sizeof...(Ts)>;
+
+template<typename... Ts>
+concept true3 = true2<Ts...>;
+
+static_assert(true3<void>);
+
+}
+
+namespace case6 {
+
+namespace std {
+template <int __v>
+struct integral_constant {
+ static const int value = __v;
+};
+
+template <class _Tp, class... _Args>
+constexpr bool is_constructible_v = __is_constructible(_Tp, _Args...);
+
+template <class _From, class _To>
+constexpr bool is_convertible_v = __is_convertible(_From, _To);
+
+template <class>
+struct tuple_size;
+
+template <class _Tp>
+constexpr decltype(sizeof(int)) tuple_size_v = tuple_size<_Tp>::value;
+} // namespace std
+
+template <int N, int X>
+concept FixedExtentConstructibleFromExtent = X == N;
+
+template <int Extent>
+struct span {
+ int static constexpr extent = Extent;
+ template <typename R, int N = std::tuple_size_v<R>>
+ requires(FixedExtentConstructibleFromExtent<extent, N>)
+ span(R);
+};
+
+template <class, int>
+struct array {};
+
+template <class _Tp, decltype(sizeof(int)) _Size>
+struct std::tuple_size<array<_Tp, _Size>> : integral_constant<_Size> {};
+
+static_assert(std::is_convertible_v<array<int, 3>, span<3>>);
+static_assert(!std::is_constructible_v<span<4>, array<int, 3>>);
+
+}
+
}
More information about the cfe-commits
mailing list