Improve support for 'decltype(auto)' in template template parameter matching.

A 'decltype(auto)' parameter can match any other kind of non-type template
parameter, so should be usable in place of any other parameter in a template
template argument. The standard is sadly extremely unclear on how this is
supposed to work, but this seems like the obviously-correct result.

It's less clear whether an 'auto' parameter should be able to match
'decltype(auto)', since the former cannot be used if the latter turns out to be
used for a reference type, but if we disallow that then consistency suggests we
should also disallow 'auto' matching 'T' for the same reason, defeating
intended use cases of the feature.

llvm-svn: 295866
This commit is contained in:
Richard Smith 2017-02-22 20:01:55 +00:00
parent f133ccbd8d
commit 4ae5ec8268
2 changed files with 20 additions and 6 deletions

View File

@ -5666,6 +5666,19 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// If the parameter type somehow involves auto, deduce the type now.
if (getLangOpts().CPlusPlus1z && ParamType->isUndeducedType()) {
// During template argument deduction, we allow 'decltype(auto)' to
// match an arbitrary dependent argument.
// FIXME: The language rules don't say what happens in this case.
// FIXME: We get an opaque dependent type out of decltype(auto) if the
// expression is merely instantiation-dependent; is this enough?
if (CTAK == CTAK_Deduced && Arg->isTypeDependent()) {
auto *AT = dyn_cast<AutoType>(ParamType);
if (AT && AT->isDecltypeAuto()) {
Converted = TemplateArgument(Arg);
return Arg;
}
}
// When checking a deduced template argument, deduce from its type even if
// the type is dependent, in order to check the types of non-type template
// arguments line up properly in partial ordering.

View File

@ -103,12 +103,13 @@ namespace Auto {
TDecltypeAuto<Int> dai; // expected-error {{different template parameters}}
TDecltypeAuto<IntPtr> daip; // expected-error {{different template parameters}}
// FIXME: It's completely unclear what should happen here. A case can be made
// that 'auto' is more specialized, because it's always a prvalue, whereas
// 'decltype(auto)' could have any value category. Under that interpretation,
// we get the following results entirely backwards:
TAuto<DecltypeAuto> ada; // expected-error {{different template parameters}}
TAutoPtr<DecltypeAuto> apda; // expected-error {{different template parameters}}
// FIXME: It's completely unclear what should happen here, but these results
// seem at least plausible:
TAuto<DecltypeAuto> ada;
TAutoPtr<DecltypeAuto> apda;
// Perhaps this case should be invalid, as there are valid 'decltype(auto)'
// parameters (such as 'user-defined-type &') that are not valid 'auto'
// parameters.
TDecltypeAuto<Auto> daa;
TDecltypeAuto<AutoPtr> daa; // expected-error {{different template parameters}}