Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>()) {
Expand Down
16 changes: 13 additions & 3 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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();
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
79 changes: 79 additions & 0 deletions clang/test/SemaCXX/cxx2c-fold-exprs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
};

}

}
Loading