https://github.com/zyn0217 updated https://github.com/llvm/llvm-project/pull/161994
>From db646e20fe7acb1a88205dbf0821db02d17ed08d Mon Sep 17 00:00:00 2001 From: Younan Zhang <[email protected]> Date: Sun, 5 Oct 2025 11:56:32 +0800 Subject: [PATCH 1/2] [Clang] Fix concept paramater mapping for SizeOfPackExpr 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 complain :/ There was also a bug in updating the parameter mapping, where the AssociatedDecl was not updated accordingly. --- clang/lib/Sema/SemaConcept.cpp | 20 +++++++---------- clang/lib/Sema/SemaTemplateDeduction.cpp | 4 ++++ clang/test/SemaTemplate/concepts.cpp | 28 ++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 8413090e7ebd1..0b70f61028e49 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( @@ -363,6 +355,10 @@ class HashParameterMapping : public RecursiveASTVisitor<HashParameterMapping> { return inherited::TraverseTemplateArgument(Arg); } + bool TraverseSizeOfPackExpr(SizeOfPackExpr *SOPE) { + return TraverseDecl(SOPE->getPack()); + } + void VisitConstraint(const NormalizedConstraintWithParamMapping &Constraint) { if (!Constraint.hasParameterMapping()) { for (const auto &List : TemplateArgs) @@ -2083,8 +2079,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..e3b9f9d26bfaf 100644 --- a/clang/test/SemaTemplate/concepts.cpp +++ b/clang/test/SemaTemplate/concepts.cpp @@ -1333,4 +1333,32 @@ 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>); + +} + } >From 2ae72e12e495fc4ec81bbb0fa309542c168de52d Mon Sep 17 00:00:00 2001 From: Younan Zhang <[email protected]> Date: Sun, 5 Oct 2025 12:39:45 +0800 Subject: [PATCH 2/2] Handle initializer in concept cache --- clang/lib/Sema/SemaConcept.cpp | 9 +++++- clang/test/SemaTemplate/concepts.cpp | 43 ++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 0b70f61028e49..11d2d5c3938c1 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -317,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); } @@ -359,6 +362,10 @@ class HashParameterMapping : public RecursiveASTVisitor<HashParameterMapping> { 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) diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp index e3b9f9d26bfaf..e5e081ffb9d0f 100644 --- a/clang/test/SemaTemplate/concepts.cpp +++ b/clang/test/SemaTemplate/concepts.cpp @@ -1361,4 +1361,47 @@ 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>>); + +} + } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
