Author: Younan Zhang Date: 2025-01-03T19:10:43+08:00 New Revision: 2e41489d7b1498ec8a18b99e6d7db9e946f2d786
URL: https://github.com/llvm/llvm-project/commit/2e41489d7b1498ec8a18b99e6d7db9e946f2d786 DIFF: https://github.com/llvm/llvm-project/commit/2e41489d7b1498ec8a18b99e6d7db9e946f2d786.diff LOG: [Clang] Fix unexpanded packs in NTTP type constraints (#121296) In the case where a type-constraint on an NTTP contains a pack, we form a PackExpansionType to model it. However, there are a few places expecting it to be a non-pack expansion, and luckily only small changes could make them work. Fixes https://github.com/llvm/llvm-project/issues/88866 Added: Modified: clang/docs/ReleaseNotes.rst clang/lib/AST/ASTContext.cpp clang/lib/Sema/SemaTemplate.cpp clang/lib/Sema/SemaTemplateDeduction.cpp clang/test/SemaCXX/cxx2c-fold-exprs.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 2789a24ebf273d..61d6aa2216cd06 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -886,6 +886,7 @@ Bug Fixes to C++ Support 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) - Fixed a bug where captured structured bindings were modifiable inside non-mutable lambda (#GH95081) +- Clang now identifies unexpanded parameter packs within the type constraint on a non-type template parameter. (#GH88866) - Fixed an issue while resolving type of expression indexing into a pack of values of non-dependent type (#GH121242) Bug Fixes to AST Handling 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 5e7a3c8484c88f..20ec2fbeaa6a8b 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,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/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index fad20b37a7d9a2..1c1f6e30ab7b83 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -857,7 +857,10 @@ class PackDeductionScope { if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>( TemplateParams->getParam(Index))) { if (!NTTP->isExpandedParameterPack()) - if (auto *Expansion = dyn_cast<PackExpansionType>(NTTP->getType())) + // 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()); } // FIXME: Also collect the unexpanded packs in any type and template diff --git a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp index 0674135aac483f..48061439941f23 100644 --- a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp +++ b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp @@ -305,3 +305,82 @@ 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 ExpandsBoth { + +template <typename Indices, InitFunc<Indices> auto... init> +struct LazyLitMatrix; // expected-note {{here}} + +template < + typename...Indices, + InitFunc<index_by<Indices>> auto... 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>, 42>; +// expected-error@-1 {{instantiation of undefined template}} +template struct LazyLitMatrix<index_by<int, char>, 42, 43>; + +} + +namespace ExpandsRespectively { + +template <typename Indices, InitFunc<Indices> auto... init> +struct LazyLitMatrix; + +template < + typename...Indices, + InitFunc<index_by<Indices...>> auto... init +> +struct LazyLitMatrix<index_by<Indices...>, init...> { +}; + +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> { +}; + +} + +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits