Fix deduction of type of pack-expanded non-type template parameter.

We need to look through the PackExpansionType in the parameter type when
deducing, and we need to consider the possibility of deducing arguments for
packs that are not lexically mentioned in the pattern (but are nonetheless
deducible) when figuring out which packs are covered by a pack deduction scope.

llvm-svn: 295790
This commit is contained in:
Richard Smith 2017-02-21 23:49:18 +00:00
parent 9417505f7d
commit 130cc445e4
3 changed files with 112 additions and 57 deletions

View File

@ -112,6 +112,15 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
bool NumberOfArgumentsMustMatch);
static void MarkUsedTemplateParameters(ASTContext &Ctx,
const TemplateArgument &TemplateArg,
bool OnlyDeduced, unsigned Depth,
llvm::SmallBitVector &Used);
static void MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
bool OnlyDeduced, unsigned Level,
llvm::SmallBitVector &Deduced);
/// \brief If the given expression is of a form that permits the deduction
/// of a non-type template parameter, return the declaration of that
/// non-type template parameter.
@ -334,12 +343,24 @@ static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument(
if (!S.getLangOpts().CPlusPlus1z)
return Sema::TDK_Success;
if (NTTP->isExpandedParameterPack())
// FIXME: We may still need to deduce parts of the type here! But we
// don't have any way to find which slice of the type to use, and the
// type stored on the NTTP itself is nonsense. Perhaps the type of an
// expanded NTTP should be a pack expansion type?
return Sema::TDK_Success;
// Get the type of the parameter for deduction.
QualType ParamType = NTTP->getType();
if (auto *Expansion = dyn_cast<PackExpansionType>(ParamType))
ParamType = Expansion->getPattern();
// FIXME: It's not clear how deduction of a parameter of reference
// type from an argument (of non-reference type) should be performed.
// For now, we just remove reference types from both sides and let
// the final check for matching types sort out the mess.
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, NTTP->getType().getNonReferenceType(),
S, TemplateParams, ParamType.getNonReferenceType(),
ValueType.getNonReferenceType(), Info, Deduced, TDF_SkipNonDependent,
/*PartialOrdering=*/false,
/*ArrayBound=*/NewDeduced.wasDeducedFromArrayBound());
@ -617,29 +638,68 @@ public:
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
TemplateDeductionInfo &Info, TemplateArgument Pattern)
: S(S), TemplateParams(TemplateParams), Deduced(Deduced), Info(Info) {
// Dig out the partially-substituted pack, if there is one.
const TemplateArgument *PartialPackArgs = nullptr;
unsigned NumPartialPackArgs = 0;
std::pair<unsigned, unsigned> PartialPackDepthIndex(-1u, -1u);
if (auto *Scope = S.CurrentInstantiationScope)
if (auto *Partial = Scope->getPartiallySubstitutedPack(
&PartialPackArgs, &NumPartialPackArgs))
PartialPackDepthIndex = getDepthAndIndex(Partial);
// Compute the set of template parameter indices that correspond to
// parameter packs expanded by the pack expansion.
{
llvm::SmallBitVector SawIndices(TemplateParams->size());
auto AddPack = [&](unsigned Index) {
if (SawIndices[Index])
return;
SawIndices[Index] = true;
// Save the deduced template argument for the parameter pack expanded
// by this pack expansion, then clear out the deduction.
DeducedPack Pack(Index);
Pack.Saved = Deduced[Index];
Deduced[Index] = TemplateArgument();
Packs.push_back(Pack);
};
// First look for unexpanded packs in the pattern.
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]);
if (Depth == Info.getDeducedDepth() && !SawIndices[Index]) {
SawIndices[Index] = true;
// Save the deduced template argument for the parameter pack expanded
// by this pack expansion, then clear out the deduction.
DeducedPack Pack(Index);
Pack.Saved = Deduced[Index];
Deduced[Index] = TemplateArgument();
Packs.push_back(Pack);
}
if (Depth == Info.getDeducedDepth())
AddPack(Index);
}
assert(!Packs.empty() && "Pack expansion without unexpanded packs?");
// This pack expansion will have been partially expanded iff the only
// unexpanded parameter pack within it is the partially-substituted pack.
IsPartiallyExpanded =
Packs.size() == 1 &&
PartialPackDepthIndex ==
std::make_pair(Info.getDeducedDepth(), Packs.front().Index);
// Skip over the pack elements that were expanded into separate arguments.
if (IsPartiallyExpanded)
PackElements += NumPartialPackArgs;
// We can also have deduced template parameters that do not actually
// appear in the pattern, but can be deduced by it (the type of a non-type
// template parameter pack, in particular). These won't have prevented us
// from partially expanding the pack.
llvm::SmallBitVector Used(TemplateParams->size());
MarkUsedTemplateParameters(S.Context, Pattern, /*OnlyDeduced*/true,
Info.getDeducedDepth(), Used);
for (int Index = Used.find_first(); Index != -1;
Index = Used.find_next(Index))
if (TemplateParams->getParam(Index)->isParameterPack())
AddPack(Index);
}
assert(!Packs.empty() && "Pack expansion without unexpanded packs?");
for (auto &Pack : Packs) {
if (Info.PendingDeducedPacks.size() > Pack.Index)
@ -648,18 +708,19 @@ public:
Info.PendingDeducedPacks.resize(Pack.Index + 1);
Info.PendingDeducedPacks[Pack.Index] = &Pack;
if (S.CurrentInstantiationScope) {
// If the template argument pack was explicitly specified, add that to
// the set of deduced arguments.
const TemplateArgument *ExplicitArgs;
unsigned NumExplicitArgs;
NamedDecl *PartiallySubstitutedPack =
S.CurrentInstantiationScope->getPartiallySubstitutedPack(
&ExplicitArgs, &NumExplicitArgs);
if (PartiallySubstitutedPack &&
getDepthAndIndex(PartiallySubstitutedPack) ==
std::make_pair(Info.getDeducedDepth(), Pack.Index))
Pack.New.append(ExplicitArgs, ExplicitArgs + NumExplicitArgs);
if (PartialPackDepthIndex ==
std::make_pair(Info.getDeducedDepth(), Pack.Index)) {
Pack.New.append(PartialPackArgs, PartialPackArgs + NumPartialPackArgs);
// We pre-populate the deduced value of the partially-substituted
// pack with the specified value. This is not entirely correct: the
// value is supposed to have been substituted, not deduced, but the
// cases where this is observable require an exact type match anyway.
//
// FIXME: If we could represent a "depth i, index j, pack elem k"
// parameter, we could substitute the partially-substituted pack
// everywhere and avoid this.
if (Pack.New.size() > PackElements)
Deduced[Pack.Index] = Pack.New[PackElements];
}
}
}
@ -671,16 +732,7 @@ public:
/// Determine whether this pack has already been partially expanded into a
/// sequence of (prior) function parameters / template arguments.
bool isPartiallyExpanded() {
if (Packs.size() != 1 || !S.CurrentInstantiationScope)
return false;
auto *PartiallySubstitutedPack =
S.CurrentInstantiationScope->getPartiallySubstitutedPack();
return PartiallySubstitutedPack &&
getDepthAndIndex(PartiallySubstitutedPack) ==
std::make_pair(Info.getDeducedDepth(), Packs.front().Index);
}
bool isPartiallyExpanded() { return IsPartiallyExpanded; }
/// Move to deducing the next element in each pack that is being deduced.
void nextPackElement() {
@ -692,8 +744,13 @@ public:
if (!Pack.New.empty() || !DeducedArg.isNull()) {
while (Pack.New.size() < PackElements)
Pack.New.push_back(DeducedTemplateArgument());
Pack.New.push_back(DeducedArg);
DeducedArg = DeducedTemplateArgument();
if (Pack.New.size() == PackElements)
Pack.New.push_back(DeducedArg);
else
Pack.New[PackElements] = DeducedArg;
DeducedArg = Pack.New.size() > PackElements + 1
? Pack.New[PackElements + 1]
: DeducedTemplateArgument();
}
}
++PackElements;
@ -784,6 +841,7 @@ private:
SmallVectorImpl<DeducedTemplateArgument> &Deduced;
TemplateDeductionInfo &Info;
unsigned PackElements = 0;
bool IsPartiallyExpanded = false;
SmallVector<DeducedPack, 2> Packs;
};
@ -2591,12 +2649,6 @@ static bool isSimpleTemplateIdType(QualType T) {
return false;
}
static void
MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
bool OnlyDeduced,
unsigned Level,
llvm::SmallBitVector &Deduced);
/// \brief Substitute the explicitly-provided template arguments into the
/// given function template according to C++ [temp.arg.explicit].
///
@ -4894,13 +4946,6 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
return isAtLeastAsSpecializedAs(*this, PType, AType, AArg, Info);
}
static void
MarkUsedTemplateParameters(ASTContext &Ctx,
const TemplateArgument &TemplateArg,
bool OnlyDeduced,
unsigned Depth,
llvm::SmallBitVector &Used);
/// \brief Mark the template parameters that are used by the given
/// expression.
static void

View File

@ -203,13 +203,19 @@ namespace transform_params {
};
B b({1, 2, 3}, "foo", {'x', 'y', 'z', 'w'}); // ok
// This should be accepted once -std=c++1z implies
// -frelaxed-template-template-args. Without that, a template template
// parameter 'template<int, int, int> typename' cannot bind to a template
// template argument 'template<int...> typename'.
template<typename ...T> struct C { // expected-note {{candidate}}
template<T ...V, template<T...> typename X>
C(X<V...>); // expected-note {{substitution failure [with T = <>, V = <0, 1, 2>]}}
C(X<V...>); // expected-note {{substitution failure [with T = <int, int, int>, V = <0, 1, 2>]}}
};
template<int...> struct Y {};
// FIXME: This incorrectly deduces T = <>, rather than deducing
// T = <int, int, int> from the types of the elements of V.
// (This failure is not related to class template argument deduction.)
C c(Y<0, 1, 2>{}); // expected-error {{no viable constructor or deduction guide}}
template<typename ...T> struct D {
template<T ...V> D(Y<V...>);
};
D d(Y<0, 1, 2>{});
}

View File

@ -526,13 +526,17 @@ namespace dependent_list_deduction {
static_assert(is_same<X<T...>, X<int, char, char>>::value, "");
static_assert(is_same<Y<V...>, Y<3, 2, 4>>::value, "");
}
template<typename ...T, T ...V> void g(const T (&...p)[V]) { // expected-note {{deduced incomplete pack}}
template<typename ...T, T ...V> void g(const T (&...p)[V]) {
static_assert(is_same<X<T...>, X<int, decltype(sizeof(0))>>::value, "");
static_assert(is_same<Y<V...>, Y<2, 3>>::value, "");
}
void h() {
f({1, 2, 3}, {'a', 'b'}, "foo");
// FIXME: Deduction in this case should succeed.
g({1, 2}, {{}, {}, {}}); // expected-error {{no match}}
g({1, 2}, {{}, {}, {}});
#if __cplusplus <= 201402
// expected-error@-2 {{no match}}
// expected-note@-9 {{deduced incomplete pack}}
// We deduce V$1 = (size_t)3, which in C++1z also deduces T$1 = size_t.
#endif
}
}