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:
@@ -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;
|
||||
}
|
||||
|
||||
22
clang/test/CXX/temp/temp.fct.spec/temp.deduct/p7.cpp
Normal file
22
clang/test/CXX/temp/temp.fct.spec/temp.deduct/p7.cpp
Normal 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'}}
|
||||
Reference in New Issue
Block a user