https://github.com/zyn0217 updated https://github.com/llvm/llvm-project/pull/121296
>From 102e031cae56c130f48f08bcb316b6f451facf49 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Sun, 29 Dec 2024 23:13:52 +0800 Subject: [PATCH 1/5] [Clang] Diagnose unexpanded packs for NTTP type constraints --- clang/docs/ReleaseNotes.rst | 1 + clang/lib/Sema/SemaTemplate.cpp | 12 +++++-- clang/test/SemaCXX/cxx2c-fold-exprs.cpp | 43 +++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 8b984ecaefecaf..78ae4c8cab3a9e 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -885,6 +885,7 @@ Bug Fixes to C++ Support - Fixed recognition of ``std::initializer_list`` when it's surrounded with ``extern "C++"`` and exported out of a module (which is the case e.g. in MSVC's implementation of ``std`` module). (#GH118218) - Fixed a pack expansion issue in checking unexpanded parameter sizes. (#GH17042) +- Clang now identifies unexpanded parameter packs within the type constraint on a non-type template parameter. (#GH88866) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 5e7a3c8484c88f..eac184d468ce9a 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1530,9 +1530,17 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, Param->setAccess(AS_public); if (AutoTypeLoc TL = TInfo->getTypeLoc().getContainedAutoTypeLoc()) - if (TL.isConstrained()) - if (AttachTypeConstraint(TL, Param, Param, D.getEllipsisLoc())) + if (TL.isConstrained()) { + if (const ASTTemplateArgumentListInfo *ArgumentList = + TL.getConceptReference()->getTemplateArgsAsWritten()) + for (const TemplateArgumentLoc &Loc : ArgumentList->arguments()) { + Invalid |= DiagnoseUnexpandedParameterPack( + Loc, UnexpandedParameterPackContext::UPPC_TypeConstraint); + } + if (!Invalid && + AttachTypeConstraint(TL, Param, Param, D.getEllipsisLoc())) Invalid = true; + } if (Invalid) Param->setInvalidDecl(); diff --git a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp index 0674135aac483f..00236a8a839135 100644 --- a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp +++ b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp @@ -305,3 +305,46 @@ static_assert(__is_same_as(_Three_way_comparison_result_with_tuple_like<tuple<in static_assert(__is_same_as(_Three_way_comparison_result_with_tuple_like<tuple<int>, 0>::type, long)); } + +namespace GH88866 { + +template <typename...Ts> struct index_by; + +template <typename T, typename Indices> +concept InitFunc = true; + +namespace Invalid { + +template <typename Indices, InitFunc<Indices> auto... init> +struct LazyLitMatrix; + +template < + typename...Indices, + InitFunc<index_by<Indices>> auto... init + // expected-error@-1 {{type constraint contains unexpanded parameter pack 'Indices'}} +> +struct LazyLitMatrix<index_by<Indices...>, init...> { +}; + +static_assert( + !__is_same(LazyLitMatrix<index_by<int, char>, 42, 43>, LazyLitMatrix<index_by<int, char>, 42, 43>)); +// expected-error@-1 {{static assertion failed}} +} + +namespace Valid { + +template <typename Indices, InitFunc<Indices> auto... init> +struct LazyLitMatrix; + +template < + typename...Indices, + InitFunc<index_by<Indices...>> auto... init +> +struct LazyLitMatrix<index_by<Indices...>, init...> { +}; + +static_assert(__is_same(LazyLitMatrix<index_by<int, char>, 42, 43>, + LazyLitMatrix<index_by<int, char>, 42, 43>)); +} + +} >From 111d1002e081322fdb5f3fa8e94b15b99817b3b9 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Sun, 29 Dec 2024 23:30:57 +0800 Subject: [PATCH 2/5] Simplify the test --- clang/test/SemaCXX/cxx2c-fold-exprs.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp index 00236a8a839135..509922c0a8f4fe 100644 --- a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp +++ b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp @@ -326,9 +326,8 @@ template < struct LazyLitMatrix<index_by<Indices...>, init...> { }; -static_assert( - !__is_same(LazyLitMatrix<index_by<int, char>, 42, 43>, LazyLitMatrix<index_by<int, char>, 42, 43>)); -// expected-error@-1 {{static assertion failed}} +using T = LazyLitMatrix<index_by<int, char>, 42, 43>; + } namespace Valid { @@ -343,8 +342,8 @@ template < struct LazyLitMatrix<index_by<Indices...>, init...> { }; -static_assert(__is_same(LazyLitMatrix<index_by<int, char>, 42, 43>, - LazyLitMatrix<index_by<int, char>, 42, 43>)); +using T = LazyLitMatrix<index_by<int, char>, 42, 43>; + } } >From 144f3c997def0a4d746edb111f2e7f90797b153e Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Tue, 31 Dec 2024 16:13:46 +0800 Subject: [PATCH 3/5] Let ... expand NTTP constraints --- clang/lib/AST/ASTContext.cpp | 2 +- clang/lib/Sema/SemaTemplate.cpp | 14 +++----------- clang/lib/Sema/SemaTemplateDeduction.cpp | 3 ++- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 8b4ae58e8427a9..a9ecb4ee9c76b2 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -6376,7 +6376,7 @@ ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, } QualType ASTContext::getUnconstrainedType(QualType T) const { - QualType CanonT = T.getCanonicalType(); + QualType CanonT = T.getNonPackExpansionType().getCanonicalType(); // Remove a type-constraint from a top-level auto or decltype(auto). if (auto *AT = CanonT->getAs<AutoType>()) { diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index eac184d468ce9a..2e4a3060c0b391 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1228,7 +1228,7 @@ bool Sema::AttachTypeConstraint(AutoTypeLoc TL, NonTypeTemplateParmDecl *NewConstrainedParm, NonTypeTemplateParmDecl *OrigConstrainedParm, SourceLocation EllipsisLoc) { - if (NewConstrainedParm->getType() != TL.getType() || + if (NewConstrainedParm->getType().getNonPackExpansionType() != TL.getType() || TL.getAutoKeyword() != AutoTypeKeyword::Auto) { Diag(NewConstrainedParm->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), diag::err_unsupported_placeholder_constraint) @@ -1530,17 +1530,9 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, Param->setAccess(AS_public); if (AutoTypeLoc TL = TInfo->getTypeLoc().getContainedAutoTypeLoc()) - if (TL.isConstrained()) { - if (const ASTTemplateArgumentListInfo *ArgumentList = - TL.getConceptReference()->getTemplateArgsAsWritten()) - for (const TemplateArgumentLoc &Loc : ArgumentList->arguments()) { - Invalid |= DiagnoseUnexpandedParameterPack( - Loc, UnexpandedParameterPackContext::UPPC_TypeConstraint); - } - if (!Invalid && - AttachTypeConstraint(TL, Param, Param, D.getEllipsisLoc())) + if (TL.isConstrained()) + if (AttachTypeConstraint(TL, Param, Param, D.getEllipsisLoc())) Invalid = true; - } if (Invalid) Param->setInvalidDecl(); diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index fad20b37a7d9a2..b4a4ab35478a1b 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -857,7 +857,8 @@ class PackDeductionScope { if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>( TemplateParams->getParam(Index))) { if (!NTTP->isExpandedParameterPack()) - if (auto *Expansion = dyn_cast<PackExpansionType>(NTTP->getType())) + if (auto *Expansion = dyn_cast<PackExpansionType>( + S.Context.getUnconstrainedType(NTTP->getType()))) ExtraDeductions.push_back(Expansion->getPattern()); } // FIXME: Also collect the unexpanded packs in any type and template >From 2cb3e542e431f23e7827e939a066217524b9f0ae Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Tue, 31 Dec 2024 16:44:56 +0800 Subject: [PATCH 4/5] Additional tests --- clang/lib/Sema/SemaTemplate.cpp | 14 ++++++- clang/test/SemaCXX/cxx2c-fold-exprs.cpp | 49 ++++++++++++++++++++++--- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 2e4a3060c0b391..20ec2fbeaa6a8b 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1530,9 +1530,19 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, Param->setAccess(AS_public); if (AutoTypeLoc TL = TInfo->getTypeLoc().getContainedAutoTypeLoc()) - if (TL.isConstrained()) - if (AttachTypeConstraint(TL, Param, Param, D.getEllipsisLoc())) + if (TL.isConstrained()) { + if (D.getEllipsisLoc().isInvalid() && + T->containsUnexpandedParameterPack()) { + assert(TL.getConceptReference()->getTemplateArgsAsWritten()); + for (auto &Loc : + TL.getConceptReference()->getTemplateArgsAsWritten()->arguments()) + Invalid |= DiagnoseUnexpandedParameterPack( + Loc, UnexpandedParameterPackContext::UPPC_TypeConstraint); + } + if (!Invalid && + AttachTypeConstraint(TL, Param, Param, D.getEllipsisLoc())) Invalid = true; + } if (Invalid) Param->setInvalidDecl(); diff --git a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp index 509922c0a8f4fe..48061439941f23 100644 --- a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp +++ b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp @@ -313,24 +313,26 @@ template <typename...Ts> struct index_by; template <typename T, typename Indices> concept InitFunc = true; -namespace Invalid { +namespace ExpandsBoth { template <typename Indices, InitFunc<Indices> auto... init> -struct LazyLitMatrix; +struct LazyLitMatrix; // expected-note {{here}} template < typename...Indices, InitFunc<index_by<Indices>> auto... init - // expected-error@-1 {{type constraint contains unexpanded parameter pack 'Indices'}} > struct LazyLitMatrix<index_by<Indices...>, init...> { }; -using T = LazyLitMatrix<index_by<int, char>, 42, 43>; +// FIXME: Explain why we didn't pick up the partial specialization - pack sizes don't match. +template struct LazyLitMatrix<index_by<int, char>, 42>; +// expected-error@-1 {{instantiation of undefined template}} +template struct LazyLitMatrix<index_by<int, char>, 42, 43>; } -namespace Valid { +namespace ExpandsRespectively { template <typename Indices, InitFunc<Indices> auto... init> struct LazyLitMatrix; @@ -342,7 +344,42 @@ template < struct LazyLitMatrix<index_by<Indices...>, init...> { }; -using T = LazyLitMatrix<index_by<int, char>, 42, 43>; +template struct LazyLitMatrix<index_by<int, char>, 42>; +template struct LazyLitMatrix<index_by<int, char>, 42, 43>; + +} + +namespace TypeParameter { + +template <typename Indices, InitFunc<Indices>... init> +struct LazyLitMatrix; // expected-note {{here}} + +template < + typename...Indices, + InitFunc<index_by<Indices>>... init +> +struct LazyLitMatrix<index_by<Indices...>, init...> { +}; + +// FIXME: Explain why we didn't pick up the partial specialization - pack sizes don't match. +template struct LazyLitMatrix<index_by<int, char>, float>; +// expected-error@-1 {{instantiation of undefined template}} +template struct LazyLitMatrix<index_by<int, char>, unsigned, float>; + +} + +namespace Invalid { + +template <typename Indices, InitFunc<Indices>... init> +struct LazyLitMatrix; + +template < + typename...Indices, + InitFunc<index_by<Indices>> init + // expected-error@-1 {{unexpanded parameter pack 'Indices'}} +> +struct LazyLitMatrix<index_by<Indices...>, init> { +}; } >From 88beac3af22b8f5a5ea58a31f4f0d13aafe1f0fc Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Fri, 3 Jan 2025 13:22:36 +0800 Subject: [PATCH 5/5] Add a note for CWG2982 --- clang/lib/Sema/SemaTemplateDeduction.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index b4a4ab35478a1b..1c1f6e30ab7b83 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -857,6 +857,8 @@ class PackDeductionScope { if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>( TemplateParams->getParam(Index))) { if (!NTTP->isExpandedParameterPack()) + // FIXME: CWG2982 suggests a type-constraint forms a non-deduced + // context, however it is not yet resolved. if (auto *Expansion = dyn_cast<PackExpansionType>( S.Context.getUnconstrainedType(NTTP->getType()))) ExtraDeductions.push_back(Expansion->getPattern()); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits