mizvekov updated this revision to Diff 453757.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D128095/new/
https://reviews.llvm.org/D128095
Files:
clang/docs/ReleaseNotes.rst
clang/include/clang/Sema/Sema.h
clang/include/clang/Sema/SemaInternal.h
clang/lib/Sema/SemaTemplateDeduction.cpp
clang/lib/Sema/SemaTemplateVariadic.cpp
clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
clang/test/SemaTemplate/cxx1z-fold-expressions.cpp
clang/test/SemaTemplate/pack-deduction.cpp
Index: clang/test/SemaTemplate/pack-deduction.cpp
===================================================================
--- clang/test/SemaTemplate/pack-deduction.cpp
+++ clang/test/SemaTemplate/pack-deduction.cpp
@@ -134,14 +134,14 @@
template<typename ...T> struct tuple {};
template<typename ...T> struct A {
template<typename ...U> static pair<tuple<T...>, tuple<U...>> f(pair<T, U> ...p);
- // expected-note@-1 {{[with U = <char, double, long>]: pack expansion contains parameter pack 'U' that has a different length (2 vs. 3) from outer parameter packs}}
+ // expected-note@-1 {{[with U = <char, double, long>]: pack expansion contains parameter packs 'T' and 'U' that have different lengths (2 vs. 3)}}
// expected-note@-2 {{[with U = <char, double, void>]: pack expansion contains parameter pack 'U' that has a different length (at least 3 vs. 2) from outer parameter packs}}
template<typename ...U> static pair<tuple<T...>, tuple<U...>> g(pair<T, U> ...p, ...);
- // expected-note@-1 {{[with U = <char, double, long>]: pack expansion contains parameter pack 'U' that has a different length (2 vs. 3) from outer parameter packs}}
+ // expected-note@-1 {{[with U = <char, double, long>]: pack expansion contains parameter packs 'T' and 'U' that have different lengths (2 vs. 3)}}
template<typename ...U> static tuple<U...> h(tuple<pair<T, U>..., pair<int, int>>);
- // expected-note@-1 {{[with U = <int[2]>]: pack expansion contains parameter pack 'U' that has a different length (2 vs. 1) from outer parameter packs}}
+ // expected-note@-1 {{[with U = <int[2]>]: pack expansion contains parameter packs 'T' and 'U' that have different lengths (2 vs. 1)}}
};
pair<tuple<int, float>, tuple<char, double>> k1 = A<int, float>().f<char>(pair<int, char>(), pair<float, double>());
Index: clang/test/SemaTemplate/cxx1z-fold-expressions.cpp
===================================================================
--- clang/test/SemaTemplate/cxx1z-fold-expressions.cpp
+++ clang/test/SemaTemplate/cxx1z-fold-expressions.cpp
@@ -97,7 +97,7 @@
template <int I> struct Constant {};
template <int... Is> struct Sum {
- template <int... Js> using type = Constant<((Is + Js) + ... + 0)>; // expected-error {{pack expansion contains parameter pack 'Js' that has a different length (1 vs. 2) from outer parameter packs}}
+ template <int... Js> using type = Constant<((Is + Js) + ... + 0)>; // expected-error {{pack expansion contains parameter packs 'Is' and 'Js' that have different lengths (1 vs. 2)}}
};
Sum<1>::type<1, 2> x; // expected-note {{instantiation of}}
Index: clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
===================================================================
--- clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
+++ clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
@@ -473,7 +473,7 @@
namespace pr56094 {
template <typename... T> struct D {
template <typename... U> using B = int(int (*...p)(T, U));
- // expected-error@-1 {{pack expansion contains parameter pack 'U' that has a different length (1 vs. 2) from outer parameter packs}}
+ // expected-error@-1 {{pack expansion contains parameter packs 'T' and 'U' that have different lengths (1 vs. 2)}}
template <typename U1, typename U2> D(B<U1, U2> *);
// expected-note@-1 {{in instantiation of template type alias 'B' requested here}}
};
@@ -484,7 +484,7 @@
template <class...> struct G {};
template <bool... I> struct E {
template <bool... U> using B = G<F<I, U>...>;
- // expected-error@-1 {{pack expansion contains parameter pack 'U' that has a different length (1 vs. 2) from outer parameter packs}}
+ // expected-error@-1 {{pack expansion contains parameter packs 'I' and 'U' that have different lengths (1 vs. 2)}}
template <bool U1, bool U2> E(B<U1, U2> *);
// expected-note@-1 {{in instantiation of template type alias 'B' requested here}}
};
Index: clang/lib/Sema/SemaTemplateVariadic.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateVariadic.cpp
+++ clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -88,6 +88,23 @@
return true;
}
+ bool
+ VisitSubstTemplateTypeParmPackTypeLoc(SubstTemplateTypeParmPackTypeLoc TL) {
+ Unexpanded.push_back({TL.getTypePtr(), TL.getNameLoc()});
+ return true;
+ }
+
+ bool VisitSubstTemplateTypeParmPackType(SubstTemplateTypeParmPackType *T) {
+ Unexpanded.push_back({T, SourceLocation()});
+ return true;
+ }
+
+ bool
+ VisitSubstNonTypeTemplateParmPackExpr(SubstNonTypeTemplateParmPackExpr *E) {
+ Unexpanded.push_back({E, E->getParameterPackLocation()});
+ return true;
+ }
+
/// Record occurrences of function and non-type template
/// parameter packs in an expression.
bool VisitDeclRefExpr(DeclRefExpr *E) {
@@ -306,7 +323,8 @@
auto *TTPD = dyn_cast<TemplateTypeParmDecl>(LocalPack);
return TTPD && TTPD->getTypeForDecl() == TTPT;
}
- return declaresSameEntity(Pack.first.get<NamedDecl *>(), LocalPack);
+ return declaresSameEntity(Pack.first.get<const NamedDecl *>(),
+ LocalPack);
};
if (llvm::any_of(LSI->LocalPacks, DeclaresThisPack))
LambdaParamPackReferences.push_back(Pack);
@@ -358,7 +376,7 @@
= Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>())
Name = TTP->getIdentifier();
else
- Name = Unexpanded[I].first.get<NamedDecl *>()->getIdentifier();
+ Name = Unexpanded[I].first.get<const NamedDecl *>()->getIdentifier();
if (Name && NamesKnown.insert(Name).second)
Names.push_back(Name);
@@ -421,7 +439,7 @@
llvm::SmallPtrSet<NamedDecl*, 8> ParmSet(Parms.begin(), Parms.end());
SmallVector<UnexpandedParameterPack, 2> UnexpandedParms;
for (auto Parm : Unexpanded)
- if (ParmSet.contains(Parm.first.dyn_cast<NamedDecl*>()))
+ if (ParmSet.contains(Parm.first.dyn_cast<const NamedDecl *>()))
UnexpandedParms.push_back(Parm);
if (UnexpandedParms.empty())
return false;
@@ -673,50 +691,58 @@
ShouldExpand = true;
RetainExpansion = false;
std::pair<IdentifierInfo *, SourceLocation> FirstPack;
- bool HaveFirstPack = false;
- Optional<unsigned> NumPartialExpansions;
+ Optional<unsigned> CurNumExpansions, NumPartialExpansions;
SourceLocation PartiallySubstitutedPackLoc;
for (UnexpandedParameterPack ParmPack : Unexpanded) {
// Compute the depth and index for this parameter pack.
unsigned Depth = 0, Index = 0;
IdentifierInfo *Name;
- bool IsVarDeclPack = false;
+ unsigned NewPackSize;
+ bool NotPack = true;
- if (const TemplateTypeParmType *TTP =
+ if (const auto *TTP =
ParmPack.first.dyn_cast<const TemplateTypeParmType *>()) {
Depth = TTP->getDepth();
Index = TTP->getIndex();
Name = TTP->getIdentifier();
+ } else if (const auto *STP =
+ ParmPack.first
+ .dyn_cast<const SubstTemplateTypeParmPackType *>()) {
+ NewPackSize = STP->getNumArgs();
+ Name = STP->getIdentifier();
+ NotPack = false;
+ } else if (const auto *SEP =
+ ParmPack.first
+ .dyn_cast<const SubstNonTypeTemplateParmPackExpr *>()) {
+ NewPackSize = SEP->getArgumentPack().pack_size();
+ Name = SEP->getParameterPack()->getIdentifier();
+ NotPack = false;
} else {
- NamedDecl *ND = ParmPack.first.get<NamedDecl *>();
- if (isa<VarDecl>(ND))
- IsVarDeclPack = true;
- else
+ const auto *ND = ParmPack.first.get<const NamedDecl *>();
+ if (isa<VarDecl>(ND)) {
+ // Figure out whether we're instantiating to an argument pack or not.
+ using DeclArgumentPack = LocalInstantiationScope::DeclArgumentPack;
+ llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation =
+ CurrentInstantiationScope->findInstantiationOf(
+ ParmPack.first.get<const NamedDecl *>());
+ if (Instantiation->is<DeclArgumentPack *>()) {
+ // We could expand this function parameter pack.
+ NewPackSize = Instantiation->get<DeclArgumentPack *>()->size();
+ } else {
+ // We can't expand this function parameter pack, so we can't expand
+ // the pack expansion.
+ ShouldExpand = false;
+ continue;
+ }
+ NotPack = false;
+ } else {
std::tie(Depth, Index) = getDepthAndIndex(ND);
-
+ }
Name = ND->getIdentifier();
}
- // Determine the size of this argument pack.
- unsigned NewPackSize;
- if (IsVarDeclPack) {
- // Figure out whether we're instantiating to an argument pack or not.
- typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
-
- llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation =
- CurrentInstantiationScope->findInstantiationOf(
- ParmPack.first.get<NamedDecl *>());
- if (Instantiation->is<DeclArgumentPack *>()) {
- // We could expand this function parameter pack.
- NewPackSize = Instantiation->get<DeclArgumentPack *>()->size();
- } else {
- // We can't expand this function parameter pack, so we can't expand
- // the pack expansion.
- ShouldExpand = false;
- continue;
- }
- } else {
+ if (NotPack) {
// If we don't have a template argument at this depth/index, then we
// cannot expand the pack expansion. Make a note of this, but we still
// want to check any parameter packs we *do* have arguments for.
@@ -725,56 +751,55 @@
ShouldExpand = false;
continue;
}
-
// Determine the size of the argument pack.
NewPackSize = TemplateArgs(Depth, Index).pack_size();
- }
-
- // C++0x [temp.arg.explicit]p9:
- // Template argument deduction can extend the sequence of template
- // arguments corresponding to a template parameter pack, even when the
- // sequence contains explicitly specified template arguments.
- if (!IsVarDeclPack && CurrentInstantiationScope) {
- if (NamedDecl *PartialPack
- = CurrentInstantiationScope->getPartiallySubstitutedPack()){
- unsigned PartialDepth, PartialIndex;
- std::tie(PartialDepth, PartialIndex) = getDepthAndIndex(PartialPack);
- if (PartialDepth == Depth && PartialIndex == Index) {
- RetainExpansion = true;
- // We don't actually know the new pack size yet.
- NumPartialExpansions = NewPackSize;
- PartiallySubstitutedPackLoc = ParmPack.second;
- continue;
+ // C++0x [temp.arg.explicit]p9:
+ // Template argument deduction can extend the sequence of template
+ // arguments corresponding to a template parameter pack, even when the
+ // sequence contains explicitly specified template arguments.
+ if (CurrentInstantiationScope)
+ if (NamedDecl *PartialPack =
+ CurrentInstantiationScope->getPartiallySubstitutedPack()) {
+ unsigned PartialDepth, PartialIndex;
+ std::tie(PartialDepth, PartialIndex) = getDepthAndIndex(PartialPack);
+ if (PartialDepth == Depth && PartialIndex == Index) {
+ RetainExpansion = true;
+ // We don't actually know the new pack size yet.
+ NumPartialExpansions = NewPackSize;
+ PartiallySubstitutedPackLoc = ParmPack.second;
+ continue;
+ }
}
- }
}
- if (!NumExpansions) {
+ if (!CurNumExpansions) {
// The is the first pack we've seen for which we have an argument.
// Record it.
- NumExpansions = NewPackSize;
+ CurNumExpansions = NewPackSize;
FirstPack.first = Name;
FirstPack.second = ParmPack.second;
- HaveFirstPack = true;
continue;
}
- if (NewPackSize != *NumExpansions) {
+ if (NewPackSize != *CurNumExpansions) {
// C++0x [temp.variadic]p5:
// All of the parameter packs expanded by a pack expansion shall have
// the same number of arguments specified.
- if (HaveFirstPack)
- Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict)
- << FirstPack.first << Name << *NumExpansions << NewPackSize
- << SourceRange(FirstPack.second) << SourceRange(ParmPack.second);
- else
- Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_multilevel)
- << Name << *NumExpansions << NewPackSize
- << SourceRange(ParmPack.second);
+ Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict)
+ << FirstPack.first << Name << *CurNumExpansions << NewPackSize
+ << SourceRange(FirstPack.second) << SourceRange(ParmPack.second);
return true;
}
}
+ if (NumExpansions && CurNumExpansions &&
+ *NumExpansions != *CurNumExpansions) {
+ Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_multilevel)
+ << FirstPack.first << *CurNumExpansions << *NumExpansions
+ << SourceRange(FirstPack.second);
+ return true;
+ }
+
// If we're performing a partial expansion but we also have a full expansion,
// expand to the number of common arguments. For example, given:
//
@@ -785,16 +810,18 @@
// ... a call to 'A<int, int>().f<int>' should expand the pack once and
// retain an expansion.
if (NumPartialExpansions) {
- if (NumExpansions && *NumExpansions < *NumPartialExpansions) {
+ if (CurNumExpansions && *CurNumExpansions < *NumPartialExpansions) {
NamedDecl *PartialPack =
CurrentInstantiationScope->getPartiallySubstitutedPack();
Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_partial)
- << PartialPack << *NumPartialExpansions << *NumExpansions
- << SourceRange(PartiallySubstitutedPackLoc);
+ << PartialPack << *NumPartialExpansions << *CurNumExpansions
+ << SourceRange(PartiallySubstitutedPackLoc);
return true;
}
NumExpansions = NumPartialExpansions;
+ } else {
+ NumExpansions = CurNumExpansions;
}
return false;
@@ -807,32 +834,47 @@
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseType(Pattern);
Optional<unsigned> Result;
+ auto setResult = [&Result](unsigned Size) {
+ assert((!Result || *Result == Size) && "inconsistent pack sizes");
+ Result = Size;
+ };
+
for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
// Compute the depth and index for this parameter pack.
unsigned Depth;
unsigned Index;
- if (const TemplateTypeParmType *TTP
- = Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) {
+ if (const auto *TTP =
+ Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) {
Depth = TTP->getDepth();
Index = TTP->getIndex();
+ } else if (const auto *STP =
+ Unexpanded[I]
+ .first
+ .dyn_cast<const SubstTemplateTypeParmPackType *>()) {
+ setResult(STP->getNumArgs());
+ continue;
+ } else if (const auto *SEP =
+ Unexpanded[I]
+ .first
+ .dyn_cast<const SubstNonTypeTemplateParmPackExpr *>()) {
+ setResult(SEP->getArgumentPack().pack_size());
+ continue;
} else {
- NamedDecl *ND = Unexpanded[I].first.get<NamedDecl *>();
+ const auto *ND = Unexpanded[I].first.get<const NamedDecl *>();
if (isa<VarDecl>(ND)) {
// Function parameter pack or init-capture pack.
typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
- llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation
- = CurrentInstantiationScope->findInstantiationOf(
- Unexpanded[I].first.get<NamedDecl *>());
+ llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation =
+ CurrentInstantiationScope->findInstantiationOf(
+ Unexpanded[I].first.get<const NamedDecl *>());
if (Instantiation->is<Decl*>())
// The pattern refers to an unexpanded pack. We're not ready to expand
// this pack yet.
return None;
- unsigned Size = Instantiation->get<DeclArgumentPack *>()->size();
- assert((!Result || *Result == Size) && "inconsistent pack sizes");
- Result = Size;
+ setResult(Instantiation->get<DeclArgumentPack *>()->size());
continue;
}
@@ -845,9 +887,7 @@
return None;
// Determine the size of the argument pack.
- unsigned Size = TemplateArgs(Depth, Index).pack_size();
- assert((!Result || *Result == Size) && "inconsistent pack sizes");
- Result = Size;
+ setResult(TemplateArgs(Depth, Index).pack_size());
}
return Result;
Index: clang/lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateDeduction.cpp
+++ clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -738,8 +738,11 @@
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
- unsigned Depth, Index;
- std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]);
+ UnexpandedParameterPack U = Unexpanded[I];
+ if (U.first.is<const SubstTemplateTypeParmPackType *>() ||
+ U.first.is<const SubstNonTypeTemplateParmPackExpr *>())
+ continue;
+ auto [Depth, Index] = getDepthAndIndex(U);
if (Depth == Info.getDeducedDepth())
AddPack(Index);
}
Index: clang/include/clang/Sema/SemaInternal.h
===================================================================
--- clang/include/clang/Sema/SemaInternal.h
+++ clang/include/clang/Sema/SemaInternal.h
@@ -62,7 +62,7 @@
}
/// Retrieve the depth and index of a template parameter.
-inline std::pair<unsigned, unsigned> getDepthAndIndex(NamedDecl *ND) {
+inline std::pair<unsigned, unsigned> getDepthAndIndex(const NamedDecl *ND) {
if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(ND))
return std::make_pair(TTP->getDepth(), TTP->getIndex());
@@ -79,7 +79,7 @@
if (const auto *TTP = UPP.first.dyn_cast<const TemplateTypeParmType *>())
return std::make_pair(TTP->getDepth(), TTP->getIndex());
- return getDepthAndIndex(UPP.first.get<NamedDecl *>());
+ return getDepthAndIndex(UPP.first.get<const NamedDecl *>());
}
class TypoCorrectionConsumer : public VisibleDeclConsumer {
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -238,8 +238,11 @@
// FIXME: No way to easily map from TemplateTypeParmTypes to
// TemplateTypeParmDecls, so we have this horrible PointerUnion.
-typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType*, NamedDecl*>,
- SourceLocation> UnexpandedParameterPack;
+using UnexpandedParameterPack = std::pair<
+ llvm::PointerUnion<
+ const TemplateTypeParmType *, const SubstTemplateTypeParmPackType *,
+ const SubstNonTypeTemplateParmPackExpr *, const NamedDecl *>,
+ SourceLocation>;
/// Describes whether we've seen any nullability information for the given
/// file.
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -101,6 +101,8 @@
- Clang will now print more information about failed static assertions. In
particular, simple static assertion expressions are evaluated to their
compile-time value and printed out if the assertion fails.
+- When diagnosing multi-level pack expansions of mismatched lengths, Clang will
+ now, in most cases, be able to point to the relevant outer parameter.
Non-comprehensive list of changes in this release
-------------------------------------------------
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits