Skip to content

Commit df18ee9

Browse files
committed
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
1 parent 37acb79 commit df18ee9

File tree

2 files changed

+54
-4
lines changed

2 files changed

+54
-4
lines changed

clang/lib/Sema/SemaTemplateDeduction.cpp

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2119,8 +2119,25 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
21192119
PackedArgsBuilder.push_back(Output.pop_back_val());
21202120
}
21212121

2122-
// FIXME: If the pack is empty and this is a template template parameter,
2123-
// we still need to substitute into the parameter itself.
2122+
// If the pack is empty, we still need to substitute into the parameter
2123+
// itself, in case that substitution fails. For non-type parameters, we did
2124+
// this above. For type parameters, no substitution is ever required.
2125+
auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param);
2126+
if (TTP && PackedArgsBuilder.empty()) {
2127+
// Set up a template instantiation context.
2128+
LocalInstantiationScope Scope(S);
2129+
Sema::InstantiatingTemplate Inst(S, Template->getLocation(), Template,
2130+
TTP, Output,
2131+
Template->getSourceRange());
2132+
if (Inst.isInvalid())
2133+
return true;
2134+
2135+
TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
2136+
Output.data(), Output.size());
2137+
if (!S.SubstDecl(TTP, S.CurContext,
2138+
MultiLevelTemplateArgumentList(TemplateArgs)))
2139+
return true;
2140+
}
21242141

21252142
// Create the resulting argument pack.
21262143
Output.push_back(
@@ -2808,11 +2825,22 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
28082825
Builder.push_back(TemplateArgument(
28092826
llvm::makeArrayRef(ExplicitArgs, NumExplicitArgs)));
28102827

2811-
// Forget the partially-substituted pack; it's substitution is now
2828+
// Forget the partially-substituted pack; its substitution is now
28122829
// complete.
28132830
CurrentInstantiationScope->ResetPartiallySubstitutedPack();
28142831
} else {
2815-
Builder.push_back(TemplateArgument::getEmptyPack());
2832+
// Go through the motions of checking the empty argument pack against
2833+
// the parameter pack.
2834+
DeducedTemplateArgument DeducedPack(TemplateArgument::getEmptyPack());
2835+
if (ConvertDeducedTemplateArgument(*this, Param, DeducedPack,
2836+
FunctionTemplate, Info, true,
2837+
Builder)) {
2838+
Info.Param = makeTemplateParameter(Param);
2839+
// FIXME: These template arguments are temporary. Free them!
2840+
Info.reset(TemplateArgumentList::CreateCopy(Context, Builder.data(),
2841+
Builder.size()));
2842+
return TDK_SubstitutionFailure;
2843+
}
28162844
}
28172845
continue;
28182846
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %clang_cc1 -std=c++11 -verify %s
2+
3+
struct Q { typedef int type; };
4+
5+
// "The substitution occurs in all types and expressions that are used in [...]
6+
// template parameter declarations." In particular, we must substitute into the
7+
// type of a parameter pack that is not a pack expansion, even if we know the
8+
// corresponding argument pack is empty.
9+
template<typename T, typename T::type...> void a(T);
10+
int &a(...);
11+
int &a_disabled = a(0);
12+
int &a_enabled = a(Q()); // expected-error {{cannot bind to a temporary of type 'void'}}
13+
14+
template<typename T, template<typename T::type> class ...X> void b(T);
15+
int &b(...);
16+
int &b_disabled = b(0);
17+
int &b_enabled = b(Q()); // expected-error {{cannot bind to a temporary of type 'void'}}
18+
19+
template<typename T, template<typename T::type...> class ...X> void c(T);
20+
int &c(...);
21+
int &c_disabled = c(0);
22+
int &c_enabled = c(Q()); // expected-error {{cannot bind to a temporary of type 'void'}}

0 commit comments

Comments
 (0)