Ensure that we substitute into the declaration of a template parameter pack

(that is not a pack expansion) during template argument deduction, even if we
deduced that the pack would be empty.

llvm-svn: 259688
This commit is contained in:
Richard Smith
2016-02-03 20:40:30 +00:00
parent 37acb79084
commit df18ee9620
2 changed files with 54 additions and 4 deletions

View File

@@ -2119,8 +2119,25 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
PackedArgsBuilder.push_back(Output.pop_back_val());
}
// FIXME: If the pack is empty and this is a template template parameter,
// we still need to substitute into the parameter itself.
// If the pack is empty, we still need to substitute into the parameter
// itself, in case that substitution fails. For non-type parameters, we did
// this above. For type parameters, no substitution is ever required.
auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param);
if (TTP && PackedArgsBuilder.empty()) {
// Set up a template instantiation context.
LocalInstantiationScope Scope(S);
Sema::InstantiatingTemplate Inst(S, Template->getLocation(), Template,
TTP, Output,
Template->getSourceRange());
if (Inst.isInvalid())
return true;
TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
Output.data(), Output.size());
if (!S.SubstDecl(TTP, S.CurContext,
MultiLevelTemplateArgumentList(TemplateArgs)))
return true;
}
// Create the resulting argument pack.
Output.push_back(
@@ -2808,11 +2825,22 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
Builder.push_back(TemplateArgument(
llvm::makeArrayRef(ExplicitArgs, NumExplicitArgs)));
// Forget the partially-substituted pack; it's substitution is now
// Forget the partially-substituted pack; its substitution is now
// complete.
CurrentInstantiationScope->ResetPartiallySubstitutedPack();
} else {
Builder.push_back(TemplateArgument::getEmptyPack());
// Go through the motions of checking the empty argument pack against
// the parameter pack.
DeducedTemplateArgument DeducedPack(TemplateArgument::getEmptyPack());
if (ConvertDeducedTemplateArgument(*this, Param, DeducedPack,
FunctionTemplate, Info, true,
Builder)) {
Info.Param = makeTemplateParameter(Param);
// FIXME: These template arguments are temporary. Free them!
Info.reset(TemplateArgumentList::CreateCopy(Context, Builder.data(),
Builder.size()));
return TDK_SubstitutionFailure;
}
}
continue;
}

View File

@@ -0,0 +1,22 @@
// RUN: %clang_cc1 -std=c++11 -verify %s
struct Q { typedef int type; };
// "The substitution occurs in all types and expressions that are used in [...]
// template parameter declarations." In particular, we must substitute into the
// type of a parameter pack that is not a pack expansion, even if we know the
// corresponding argument pack is empty.
template<typename T, typename T::type...> void a(T);
int &a(...);
int &a_disabled = a(0);
int &a_enabled = a(Q()); // expected-error {{cannot bind to a temporary of type 'void'}}
template<typename T, template<typename T::type> class ...X> void b(T);
int &b(...);
int &b_disabled = b(0);
int &b_enabled = b(Q()); // expected-error {{cannot bind to a temporary of type 'void'}}
template<typename T, template<typename T::type...> class ...X> void c(T);
int &c(...);
int &c_disabled = c(0);
int &c_enabled = c(Q()); // expected-error {{cannot bind to a temporary of type 'void'}}