forked from OSchip/llvm-project
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:
parent
2aae5dc713
commit
de0d34a576
clang
lib/Sema
test
www
|
@ -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,
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue