Implement DR1388 (wg21.link/cwg1388).

This issue clarifies how deduction proceeds past a non-trailing function
parameter pack. Essentially, the pack itself is skipped and consumes no
arguments (except for those implied by an explicitly-specified template
arguments), and nothing is deduced from it. As a small fix to the standard's
rule, we do not allow subsequent deduction to change the length of the function
parameter pack (by preventing extension of the explicitly-specified pack if
present, and otherwise deducing all contained packs to empty packs).

llvm-svn: 291425
This commit is contained in:
Richard Smith 2017-01-09 07:14:40 +00:00
parent 2aae5dc713
commit de0d34a576
5 changed files with 135 additions and 41 deletions
clang
lib/Sema
test
CXX
drs
temp/temp.fct.spec/temp.deduct/temp.deduct.call
SemaTemplate
www

View File

@ -669,6 +669,19 @@ public:
Info.PendingDeducedPacks[Pack.Index] = Pack.Outer;
}
/// 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);
}
/// Move to deducing the next element in each pack that is being deduced.
void nextPackElement() {
// Capture the deduced template arguments for each parameter pack expanded
@ -2552,6 +2565,12 @@ 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].
///
@ -2613,7 +2632,7 @@ Sema::SubstituteExplicitTemplateArguments(
// Enter a new template instantiation context where we check the
// explicitly-specified template arguments against this function template,
// and then substitute them into the function parameter types.
SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end());
SmallVector<TemplateArgument, 4> DeducedArgs;
InstantiatingTemplate Inst(*this, Info.getLocation(), FunctionTemplate,
DeducedArgs,
ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution,
@ -3389,7 +3408,6 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
// Template argument deduction is done by comparing each function template
// parameter type (call it P) with the type of the corresponding argument
// of the call (call it A) as described below.
unsigned CheckArgs = Args.size();
if (Args.size() < Function->getMinRequiredArguments() && !PartialOverloading)
return TDK_TooFewArguments;
else if (TooManyArguments(NumParams, Args.size(), PartialOverloading)) {
@ -3397,9 +3415,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
= Function->getType()->getAs<FunctionProtoType>();
if (Proto->isTemplateVariadic())
/* Do nothing */;
else if (Proto->isVariadic())
CheckArgs = NumParams;
else
else if (!Proto->isVariadic())
return TDK_TooManyArguments;
}
@ -3456,7 +3472,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
dyn_cast<PackExpansionType>(ParamType);
if (!ParamExpansion) {
// Simple case: matching a function parameter to a function argument.
if (ArgIdx >= CheckArgs)
if (ArgIdx >= Args.size())
break;
if (auto Result = DeduceCallArgument(ParamType, ArgIdx++))
@ -3465,36 +3481,47 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
continue;
}
QualType ParamPattern = ParamExpansion->getPattern();
PackDeductionScope PackScope(*this, TemplateParams, Deduced, Info,
ParamPattern);
// C++0x [temp.deduct.call]p1:
// For a function parameter pack that occurs at the end of the
// parameter-declaration-list, the type A of each remaining argument of
// the call is compared with the type P of the declarator-id of the
// function parameter pack. Each comparison deduces template arguments
// for subsequent positions in the template parameter packs expanded by
// the function parameter pack. For a function parameter pack that does
// not occur at the end of the parameter-declaration-list, the type of
// the parameter pack is a non-deduced context.
// FIXME: This does not say that subsequent parameters are also non-deduced.
// See also DR1388 / DR1399, which effectively says we should keep deducing
// after the pack.
if (ParamIdx + 1 < NumParamTypes)
break;
QualType ParamPattern = ParamExpansion->getPattern();
PackDeductionScope PackScope(*this, TemplateParams, Deduced, Info,
ParamPattern);
for (; ArgIdx < Args.size(); PackScope.nextPackElement(), ++ArgIdx)
if (auto Result = DeduceCallArgument(ParamPattern, ArgIdx))
return Result;
// the function parameter pack. When a function parameter pack appears
// in a non-deduced context [not at the end of the list], the type of
// that parameter pack is never deduced.
//
// FIXME: The above rule allows the size of the parameter pack to change
// after we skip it (in the non-deduced case). That makes no sense, so
// we instead notionally deduce the pack against N arguments, where N is
// the length of the explicitly-specified pack if it's expanded by the
// parameter pack and 0 otherwise, and we treat each deduction as a
// non-deduced context.
if (ParamIdx + 1 == NumParamTypes) {
for (; ArgIdx < Args.size(); PackScope.nextPackElement(), ++ArgIdx)
if (auto Result = DeduceCallArgument(ParamPattern, ArgIdx))
return Result;
} else {
// If the parameter type contains an explicitly-specified pack that we
// could not expand, skip the number of parameters notionally created
// by the expansion.
Optional<unsigned> NumExpansions = ParamExpansion->getNumExpansions();
if (NumExpansions && !PackScope.isPartiallyExpanded())
for (unsigned I = 0; I != *NumExpansions && ArgIdx < Args.size();
++I, ++ArgIdx)
// FIXME: Should we add OriginalCallArgs for these? What if the
// corresponding argument is a list?
PackScope.nextPackElement();
}
// Build argument packs for each of the parameter packs expanded by this
// pack expansion.
if (auto Result = PackScope.finish())
return Result;
// After we've matching against a parameter pack, we're done.
break;
}
return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
@ -4230,12 +4257,6 @@ bool Sema::DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
return StillUndeduced;
}
static void
MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
bool OnlyDeduced,
unsigned Level,
llvm::SmallBitVector &Deduced);
/// \brief If this is a non-static member function,
static void
AddImplicitObjectParameterType(ASTContext &Context,

View File

@ -174,3 +174,55 @@ namespace dr1359 { // dr1359: 3.5
constexpr Y y = Y(); // expected-error {{no matching}}
#endif
}
namespace dr1388 { // dr1388: 4.0
template<typename A, typename ...T> void f(T..., A); // expected-note 1+{{candidate}} expected-error 0-1{{C++11}}
template<typename ...T> void g(T..., int); // expected-note 1+{{candidate}} expected-error 0-1{{C++11}}
template<typename ...T, typename A> void h(T..., A); // expected-note 1+{{candidate}} expected-error 0-1{{C++11}}
void test_f() {
f(0); // ok, trailing parameter pack deduced to empty
f(0, 0); // expected-error {{no matching}}
f<int>(0);
f<int>(0, 0); // expected-error {{no matching}}
f<int, int>(0, 0);
f<int, int, int>(0, 0); // expected-error {{no matching}}
g(0);
g(0, 0); // expected-error {{no matching}}
g<>(0);
g<int>(0); // expected-error {{no matching}}
g<int>(0, 0);
h(0);
h(0, 0); // expected-error {{no matching}}
h<int>(0, 0);
h<int, int>(0, 0); // expected-error {{no matching}}
}
// A non-trailing parameter pack is still a non-deduced context, even though
// we know exactly how many arguments correspond to it.
template<typename T, typename U> struct pair {};
template<typename ...T> struct tuple { typedef char type; }; // expected-error 0-2{{C++11}}
template<typename ...T, typename ...U> void f_pair_1(pair<T, U>..., int); // expected-error 0-2{{C++11}} expected-note {{different lengths (2 vs. 0)}}
template<typename ...T, typename U> void f_pair_2(pair<T, char>..., U); // expected-error 0-2{{C++11}}
template<typename ...T, typename ...U> void f_pair_3(pair<T, U>..., tuple<U...>); // expected-error 0-2{{C++11}} expected-note {{different lengths (2 vs. 1)}}
template<typename ...T> void f_pair_4(pair<T, char>..., T...); // expected-error 0-2{{C++11}} expected-note {{<int, long> vs. <int, long, const char *>}}
void g(pair<int, char> a, pair<long, char> b, tuple<char, char> c) {
f_pair_1<int, long>(a, b, 0); // expected-error {{no match}}
f_pair_2<int, long>(a, b, 0);
f_pair_3<int, long>(a, b, c);
f_pair_3<int, long>(a, b, tuple<char>()); // expected-error {{no match}}
f_pair_4<int, long>(a, b, 0, 0L);
f_pair_4<int, long>(a, b, 0, 0L, "foo"); // expected-error {{no match}}
}
}
namespace dr1399 { // dr1399: dup 1388
template<typename ...T> void f(T..., int, T...) {} // expected-note {{candidate}} expected-error 0-1{{C++11}}
void g() {
f(0);
f<int>(0, 0, 0);
f(0, 0, 0); // expected-error {{no match}}
}
}

View File

@ -76,14 +76,17 @@ void test_pair_deduction(int *ip, float *fp, double *dp) {
first_arg_pair(make_pair(ip, 17), 16); // expected-error{{no matching function for call to 'first_arg_pair'}}
}
// For a function parameter pack that does not occur at the end of the
// parameter-declaration-list, the type of the parameter pack is a
// non-deduced context.
// A function parameter pack not at the end of the parameter list is never
// deduced. We interpret this as meaning the types within it are never
// deduced, and thus must match explicitly-specified values.
template<typename ...Types> struct tuple { };
template<typename ...Types>
void pack_not_at_end(tuple<Types...>, Types... values, int);
void pack_not_at_end(tuple<Types...>, Types... values, int); // expected-note {{<int *, double *> vs. <>}}
void test_pack_not_at_end(tuple<int*, double*> t2) {
pack_not_at_end(t2, 0, 0, 0);
pack_not_at_end(t2, 0, 0, 0); // expected-error {{no match}}
// FIXME: Should the "original argument type must match deduced parameter
// type" rule apply here?
pack_not_at_end<int*, double*>(t2, 0, 0, 0); // ok
}

View File

@ -350,17 +350,35 @@ namespace deduction_substitution_failure {
}
namespace deduction_after_explicit_pack {
template<typename ...T, typename U> int *f(T ...t, int &r, U *u) { // expected-note {{couldn't infer template argument 'U'}}
template<typename ...T, typename U> int *f(T ...t, int &r, U *u) {
return u;
}
template<typename U, typename ...T> int *g(T ...t, int &r, U *u) {
return u;
}
void h(float a, double b, int c) {
// FIXME: Under DR1388, this appears to be valid.
f<float&, double&>(a, b, c, &c); // expected-error {{no matching}}
f<float&, double&>(a, b, c, &c); // ok
g<int, float&, double&>(a, b, c, &c); // ok
}
template <typename... T> void i(T..., int, T..., ...); // expected-note 5{{deduced conflicting}}
void j() {
i(0);
i(0, 1); // expected-error {{no match}}
i(0, 1, 2); // expected-error {{no match}}
i<>(0);
i<>(0, 1); // expected-error {{no match}}
i<>(0, 1, 2); // expected-error {{no match}}
i<int, int>(0, 1, 2, 3, 4);
i<int, int>(0, 1, 2, 3, 4, 5); // expected-error {{no match}}
}
// GCC alarmingly accepts this by deducing T={int} by matching the second
// parameter against the first argument, then passing the first argument
// through the first parameter.
template<typename... T> struct X { X(int); operator int(); };
template<typename... T> void p(T..., X<T...>, ...); // expected-note {{deduced conflicting}}
void q() { p(X<int>(0), 0); } // expected-error {{no match}}
}
namespace overload_vs_pack {

View File

@ -8143,7 +8143,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1388">1388</a></td>
<td>CD3</td>
<td>Missing non-deduced context following a function parameter pack</td>
<td class="none" align="center">Unknown</td>
<td class="svn" align="center">SVN</td>
</tr>
<tr id="1389">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1389">1389</a></td>
@ -8209,7 +8209,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1399">1399</a></td>
<td>CD3</td>
<td>Deduction with multiple function parameter packs</td>
<td class="none" align="center">Unknown</td>
<td class="svn" align="center">Duplicate of <a href="#1388">1388</a></td>
</tr>
<tr id="1400">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1400">1400</a></td>