Revert two patches to fix GH58452 regression

GH58452 is a regression in the 16.0 release branch caused by both:
b8a1b698af and
3a0309c536

This patch reverts both of those to make the 'valid' code stop
diagnosing
at the expense of crashes on invalid + unclear diagnostics.

This patch also adds the tests from GH58452 to prevent any
re-application from breaking this again.

Revert "[clang] Improve diagnostics for expansion length mismatch"
This reverts commit 3a0309c536.
Revert "[clang] fix missing initialization of original number of expansions"
This reverts commit b8a1b698af.

Differential Revision: https://reviews.llvm.org/D145605
This commit is contained in:
Erich Keane 2023-03-08 12:12:33 -08:00
parent 9c645a99e4
commit acecf68c8b
8 changed files with 172 additions and 190 deletions

View File

@ -238,11 +238,9 @@ namespace threadSafety {
// FIXME: No way to easily map from TemplateTypeParmTypes to
// TemplateTypeParmDecls, so we have this horrible PointerUnion.
using UnexpandedParameterPack = std::pair<
llvm::PointerUnion<
const TemplateTypeParmType *, const SubstTemplateTypeParmPackType *,
const SubstNonTypeTemplateParmPackExpr *, const NamedDecl *>,
SourceLocation>;
typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType *, NamedDecl *>,
SourceLocation>
UnexpandedParameterPack;
/// Describes whether we've seen any nullability information for the given
/// file.

View File

@ -62,7 +62,7 @@ inline InheritableAttr *getDLLAttr(Decl *D) {
}
/// Retrieve the depth and index of a template parameter.
inline std::pair<unsigned, unsigned> getDepthAndIndex(const NamedDecl *ND) {
inline std::pair<unsigned, unsigned> getDepthAndIndex(NamedDecl *ND) {
if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(ND))
return std::make_pair(TTP->getDepth(), TTP->getIndex());
@ -79,7 +79,7 @@ getDepthAndIndex(UnexpandedParameterPack UPP) {
if (const auto *TTP = UPP.first.dyn_cast<const TemplateTypeParmType *>())
return std::make_pair(TTP->getDepth(), TTP->getIndex());
return getDepthAndIndex(UPP.first.get<const NamedDecl *>());
return getDepthAndIndex(UPP.first.get<NamedDecl *>());
}
class TypoCorrectionConsumer : public VisibleDeclConsumer {

View File

@ -756,11 +756,8 @@ private:
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
UnexpandedParameterPack U = Unexpanded[I];
if (U.first.is<const SubstTemplateTypeParmPackType *>() ||
U.first.is<const SubstNonTypeTemplateParmPackExpr *>())
continue;
auto [Depth, Index] = getDepthAndIndex(U);
unsigned Depth, Index;
std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]);
if (Depth == Info.getDeducedDepth())
AddPack(Index);
}

View File

@ -89,23 +89,6 @@ namespace {
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) {
@ -324,8 +307,7 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
auto *TTPD = dyn_cast<TemplateTypeParmDecl>(LocalPack);
return TTPD && TTPD->getTypeForDecl() == TTPT;
}
return declaresSameEntity(Pack.first.get<const NamedDecl *>(),
LocalPack);
return declaresSameEntity(Pack.first.get<NamedDecl *>(), LocalPack);
};
if (llvm::any_of(LSI->LocalPacks, DeclaresThisPack))
LambdaParamPackReferences.push_back(Pack);
@ -377,7 +359,7 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
= Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>())
Name = TTP->getIdentifier();
else
Name = Unexpanded[I].first.get<const NamedDecl *>()->getIdentifier();
Name = Unexpanded[I].first.get<NamedDecl *>()->getIdentifier();
if (Name && NamesKnown.insert(Name).second)
Names.push_back(Name);
@ -440,7 +422,7 @@ bool Sema::DiagnoseUnexpandedParameterPackInRequiresExpr(RequiresExpr *RE) {
llvm::SmallPtrSet<NamedDecl*, 8> ParmSet(Parms.begin(), Parms.end());
SmallVector<UnexpandedParameterPack, 2> UnexpandedParms;
for (auto Parm : Unexpanded)
if (ParmSet.contains(Parm.first.dyn_cast<const NamedDecl *>()))
if (ParmSet.contains(Parm.first.dyn_cast<NamedDecl *>()))
UnexpandedParms.push_back(Parm);
if (UnexpandedParms.empty())
return false;
@ -692,95 +674,109 @@ bool Sema::CheckParameterPacksForExpansion(
bool &RetainExpansion, std::optional<unsigned> &NumExpansions) {
ShouldExpand = true;
RetainExpansion = false;
std::pair<const IdentifierInfo *, SourceLocation> FirstPack;
std::optional<std::pair<unsigned, SourceLocation>> PartialExpansion;
std::optional<unsigned> CurNumExpansions;
std::pair<IdentifierInfo *, SourceLocation> FirstPack;
bool HaveFirstPack = false;
std::optional<unsigned> NumPartialExpansions;
SourceLocation PartiallySubstitutedPackLoc;
for (auto [P, Loc] : Unexpanded) {
for (UnexpandedParameterPack ParmPack : Unexpanded) {
// Compute the depth and index for this parameter pack.
std::optional<std::pair<unsigned, unsigned>> Pos;
unsigned Depth = 0, Index = 0;
IdentifierInfo *Name;
bool IsVarDeclPack = false;
if (const TemplateTypeParmType *TTP =
ParmPack.first.dyn_cast<const TemplateTypeParmType *>()) {
Depth = TTP->getDepth();
Index = TTP->getIndex();
Name = TTP->getIdentifier();
} else {
NamedDecl *ND = ParmPack.first.get<NamedDecl *>();
if (isa<VarDecl>(ND))
IsVarDeclPack = true;
else
std::tie(Depth, Index) = getDepthAndIndex(ND);
Name = ND->getIdentifier();
}
// Determine the size of this argument pack.
unsigned NewPackSize;
const auto *ND = P.dyn_cast<const NamedDecl *>();
if (ND && isa<VarDecl>(ND)) {
const auto *DAP =
CurrentInstantiationScope->findInstantiationOf(ND)
->dyn_cast<LocalInstantiationScope::DeclArgumentPack *>();
if (!DAP) {
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;
}
NewPackSize = DAP->size();
} else if (ND) {
Pos = getDepthAndIndex(ND);
} else if (const auto *TTP = P.dyn_cast<const TemplateTypeParmType *>()) {
Pos = {TTP->getDepth(), TTP->getIndex()};
ND = TTP->getDecl();
// FIXME: We either should have some fallback for canonical TTP, or
// never have canonical TTP here.
} else if (const auto *STP =
P.dyn_cast<const SubstTemplateTypeParmPackType *>()) {
NewPackSize = STP->getNumArgs();
ND = STP->getReplacedParameter();
} else {
const auto *SEP = P.get<const SubstNonTypeTemplateParmPackExpr *>();
NewPackSize = SEP->getArgumentPack().pack_size();
ND = SEP->getParameterPack();
}
if (Pos) {
// 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.
if (Pos->first >= TemplateArgs.getNumLevels() ||
!TemplateArgs.hasTemplateArgument(Pos->first, Pos->second)) {
if (Depth >= TemplateArgs.getNumLevels() ||
!TemplateArgs.hasTemplateArgument(Depth, Index)) {
ShouldExpand = false;
continue;
}
// Determine the size of the argument pack.
NewPackSize = TemplateArgs(Pos->first, Pos->second).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 (CurrentInstantiationScope)
if (const NamedDecl *PartialPack =
CurrentInstantiationScope->getPartiallySubstitutedPack();
PartialPack && getDepthAndIndex(PartialPack) == *Pos) {
RetainExpansion = true;
// We don't actually know the new pack size yet.
PartialExpansion = {NewPackSize, Loc};
continue;
}
NewPackSize = TemplateArgs(Depth, Index).pack_size();
}
// FIXME: Workaround for Canonical TTP.
const IdentifierInfo *Name = ND ? ND->getIdentifier() : nullptr;
if (!CurNumExpansions) {
// 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;
}
}
}
if (!NumExpansions) {
// The is the first pack we've seen for which we have an argument.
// Record it.
CurNumExpansions = NewPackSize;
FirstPack = {Name, Loc};
} else if (NewPackSize != *CurNumExpansions) {
NumExpansions = NewPackSize;
FirstPack.first = Name;
FirstPack.second = ParmPack.second;
HaveFirstPack = true;
continue;
}
if (NewPackSize != *NumExpansions) {
// C++0x [temp.variadic]p5:
// All of the parameter packs expanded by a pack expansion shall have
// the same number of arguments specified.
Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict)
<< FirstPack.first << Name << *CurNumExpansions << NewPackSize
<< SourceRange(FirstPack.second) << SourceRange(Loc);
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);
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:
//
@ -790,18 +786,17 @@ bool Sema::CheckParameterPacksForExpansion(
//
// ... a call to 'A<int, int>().f<int>' should expand the pack once and
// retain an expansion.
if (PartialExpansion) {
if (CurNumExpansions && *CurNumExpansions < PartialExpansion->first) {
if (NumPartialExpansions) {
if (NumExpansions && *NumExpansions < *NumPartialExpansions) {
NamedDecl *PartialPack =
CurrentInstantiationScope->getPartiallySubstitutedPack();
Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_partial)
<< PartialPack << PartialExpansion->first << *CurNumExpansions
<< SourceRange(PartialExpansion->second);
<< PartialPack << *NumPartialExpansions << *NumExpansions
<< SourceRange(PartiallySubstitutedPackLoc);
return true;
}
NumExpansions = PartialExpansion->first;
} else {
NumExpansions = CurNumExpansions;
NumExpansions = NumPartialExpansions;
}
return false;
@ -814,48 +809,47 @@ std::optional<unsigned> Sema::getNumArgumentsInExpansion(
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseType(Pattern);
std::optional<unsigned> Result;
auto setResultSz = [&Result](unsigned Size) {
assert((!Result || *Result == Size) && "inconsistent pack sizes");
Result = Size;
};
auto setResultPos = [&](const std::pair<unsigned, unsigned> &Pos) -> bool {
unsigned Depth = Pos.first, Index = Pos.second;
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 *>()) {
Depth = TTP->getDepth();
Index = TTP->getIndex();
} else {
NamedDecl *ND = Unexpanded[I].first.get<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 *>());
if (Instantiation->is<Decl *>())
// The pattern refers to an unexpanded pack. We're not ready to expand
// this pack yet.
return std::nullopt;
unsigned Size = Instantiation->get<DeclArgumentPack *>()->size();
assert((!Result || *Result == Size) && "inconsistent pack sizes");
Result = Size;
continue;
}
std::tie(Depth, Index) = getDepthAndIndex(ND);
}
if (Depth >= TemplateArgs.getNumLevels() ||
!TemplateArgs.hasTemplateArgument(Depth, Index))
// The pattern refers to an unknown template argument. We're not ready to
// expand this pack yet.
return true;
// Determine the size of the argument pack.
setResultSz(TemplateArgs(Depth, Index).pack_size());
return false;
};
return std::nullopt;
for (auto [I, _] : Unexpanded) {
if (const auto *TTP = I.dyn_cast<const TemplateTypeParmType *>()) {
if (setResultPos({TTP->getDepth(), TTP->getIndex()}))
return std::nullopt;
} else if (const auto *STP =
I.dyn_cast<const SubstTemplateTypeParmPackType *>()) {
setResultSz(STP->getNumArgs());
} else if (const auto *SEP =
I.dyn_cast<const SubstNonTypeTemplateParmPackExpr *>()) {
setResultSz(SEP->getArgumentPack().pack_size());
} else {
const auto *ND = I.get<const NamedDecl *>();
// Function parameter pack or init-capture pack.
if (isa<VarDecl>(ND)) {
const auto *DAP =
CurrentInstantiationScope->findInstantiationOf(ND)
->dyn_cast<LocalInstantiationScope::DeclArgumentPack *>();
if (!DAP)
// The pattern refers to an unexpanded pack. We're not ready to expand
// this pack yet.
return std::nullopt;
setResultSz(DAP->size());
} else if (setResultPos(getDepthAndIndex(ND))) {
return std::nullopt;
}
}
// Determine the size of the argument pack.
unsigned Size = TemplateArgs(Depth, Index).pack_size();
assert((!Result || *Result == Size) && "inconsistent pack sizes");
Result = Size;
}
return Result;

View File

@ -5897,7 +5897,6 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams(
= dyn_cast<PackExpansionType>(OldType)) {
// We have a function parameter pack that may need to be expanded.
QualType Pattern = Expansion->getPattern();
NumExpansions = Expansion->getNumExpansions();
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded);

View File

@ -473,51 +473,45 @@ int fn() {
}
}
namespace pr56094 {
template <typename... T> struct D {
template <typename... U> using B = int(int (*...p)(T, U));
// 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}}
};
using t1 = D<float>::B<int>;
// expected-note@-1 {{in instantiation of template class 'pr56094::D<float>' requested here}}
template <bool...> struct F {};
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 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}}
};
using t2 = E<true>::B<false>;
// expected-note@-1 {{in instantiation of template class 'pr56094::E<true>' requested here}}
} // namespace pr56094
namespace GH56094 {
#if __cplusplus >= 201402L
template <class> struct A; // expected-note {{template is declared here}}
template <class> using B = char;
template <class ...Cs> int C{ A<B<Cs>>{}... }; // expected-error {{implicit instantiation of undefined template}}
#endif
} // namespace GH56094
namespace GH58679 {
#if __cplusplus >= 201402L
template <class> constexpr int A = 1;
template <int> struct B;
template <> struct B<1> { using b1 = void; };
template <class> using C = char;
template <class... Ds> int D{ B<A<C<Ds>>>{}... };
struct E {
template <class E1, class = typename B<A<E1>>::b1> E(E1);
namespace GH58452 {
template <typename... As> struct A {
template <typename... Bs> using B = void(As...(Bs));
};
template <typename... Es> int F{ E(C<Es>{})... };
#endif
} // namespace GH58679
template <typename... Cs> struct C {
template <typename... Ds> using D = typename A<Cs...>::template B<Ds...>;
};
using t1 = C<int, int>::template D<float, float>;
template <typename A, typename B>
using ConditionalRewrite = B;
template <typename T>
using SignatureType = int;
template <typename... Args>
struct Type1 {
template <typename... Params>
using Return = SignatureType<int(ConditionalRewrite<Args, Params>...)>;
};
template <typename... Args>
struct Type2 {
using T1 = Type1<Args...>;
template <typename... Params>
using Return = typename T1::template Return<Params...>;
};
template <typename T>
typename T::template Return<int, int> InvokeMethod() {
return 3;
}
int Function1() {
return InvokeMethod<Type2<int, int>>();
}
}

View File

@ -97,7 +97,7 @@ namespace PR41845 {
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 packs 'Is' and 'Js' that have different lengths (1 vs. 2)}}
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}}
};
Sum<1>::type<1, 2> x; // expected-note {{instantiation of}}

View File

@ -134,14 +134,14 @@ namespace partial_full_mix {
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 packs 'T' and 'U' that have different lengths (2 vs. 3)}}
// 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@-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 packs 'T' and 'U' that have different lengths (2 vs. 3)}}
// 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}}
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 packs 'T' and 'U' that have different lengths (2 vs. 1)}}
// 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}}
};
pair<tuple<int, float>, tuple<char, double>> k1 = A<int, float>().f<char>(pair<int, char>(), pair<float, double>());