unsigned NumExpansions);
using TemplateParmPosition::getDepth;
+ using TemplateParmPosition::setDepth;
using TemplateParmPosition::getPosition;
using TemplateParmPosition::setPosition;
using TemplateParmPosition::getIndex;
/// \brief The template argument lists, stored from the innermost template
/// argument list (first) to the outermost template argument list (last).
SmallVector<ArgList, 4> TemplateArgumentLists;
+
+ /// \brief The number of outer levels of template arguments that are not
+ /// being substituted.
+ unsigned NumRetainedOuterLevels = 0;
public:
/// \brief Construct an empty set of template argument lists.
/// \brief Determine the number of levels in this template argument
/// list.
- unsigned getNumLevels() const { return TemplateArgumentLists.size(); }
-
+ unsigned getNumLevels() const {
+ return TemplateArgumentLists.size() + NumRetainedOuterLevels;
+ }
+
+ /// \brief Determine the number of substituted levels in this template
+ /// argument list.
+ unsigned getNumSubstitutedLevels() const {
+ return TemplateArgumentLists.size();
+ }
+
/// \brief Retrieve the template argument at a given depth and index.
const TemplateArgument &operator()(unsigned Depth, unsigned Index) const {
- assert(Depth < TemplateArgumentLists.size());
+ assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels());
assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].size());
return TemplateArgumentLists[getNumLevels() - Depth - 1][Index];
}
///
/// There must exist a template argument list at the given depth.
bool hasTemplateArgument(unsigned Depth, unsigned Index) const {
- assert(Depth < TemplateArgumentLists.size());
+ assert(Depth < getNumLevels());
+
+ if (Depth < NumRetainedOuterLevels)
+ return false;
if (Index >= TemplateArgumentLists[getNumLevels() - Depth - 1].size())
return false;
/// \brief Clear out a specific template argument.
void setArgument(unsigned Depth, unsigned Index,
TemplateArgument Arg) {
- assert(Depth < TemplateArgumentLists.size());
+ assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels());
assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].size());
const_cast<TemplateArgument&>(
TemplateArgumentLists[getNumLevels() - Depth - 1][Index])
/// \brief Add a new outmost level to the multi-level template argument
/// list.
void addOuterTemplateArguments(ArgList Args) {
+ assert(!NumRetainedOuterLevels &&
+ "substituted args outside retained args?");
TemplateArgumentLists.push_back(Args);
}
+ /// \brief Add an outermost level that we are not substituting. We have no
+ /// arguments at this level, and do not remove it from the depth of inner
+ /// template parameters that we instantiate.
+ void addOuterRetainedLevel() {
+ ++NumRetainedOuterLevels;
+ }
+
/// \brief Retrieve the innermost template argument list.
const ArgList &getInnermost() const {
return TemplateArgumentLists.front();
CXXConstructorDecl *CD) {
SmallVector<TemplateArgument, 16> SubstArgs;
+ LocalInstantiationScope Scope(SemaRef);
+
// C++ [over.match.class.deduct]p1:
// -- For each constructor of the class template designated by the
// template-name, a function template with the following properties:
for (NamedDecl *Param : *InnerParams) {
MultiLevelTemplateArgumentList Args;
Args.addOuterTemplateArguments(SubstArgs);
- Args.addOuterTemplateArguments(None);
+ Args.addOuterRetainedLevel();
NamedDecl *NewParam = transformTemplateParameter(Param, Args);
if (!NewParam)
return nullptr;
MultiLevelTemplateArgumentList Args;
if (FTD) {
Args.addOuterTemplateArguments(SubstArgs);
- Args.addOuterTemplateArguments(None);
+ Args.addOuterRetainedLevel();
}
FunctionProtoTypeLoc FPTL = CD->getTypeSourceInfo()->getTypeLoc()
if (InstantiatedDefaultArg)
NewTTP->setDefaultArgument(InstantiatedDefaultArg);
}
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(TemplateParam,
+ NewTTP);
return NewTTP;
}
return E;
TemplateArgument Arg = TemplateArgs(NTTP->getDepth(), NTTP->getPosition());
+
+ if (TemplateArgs.getNumLevels() != TemplateArgs.getNumSubstitutedLevels()) {
+ // We're performing a partial substitution, so the substituted argument
+ // could be dependent. As a result we can't create a SubstNonType*Expr
+ // node now, since that represents a fully-substituted argument.
+ // FIXME: We should have some AST representation for this.
+ if (Arg.getKind() == TemplateArgument::Pack) {
+ // FIXME: This won't work for alias templates.
+ assert(Arg.pack_size() == 1 && Arg.pack_begin()->isPackExpansion() &&
+ "unexpected pack arguments in partial substitution");
+ Arg = Arg.pack_begin()->getPackExpansionPattern();
+ }
+ assert(Arg.getKind() == TemplateArgument::Expression &&
+ "unexpected nontype template argument kind in partial substitution");
+ return Arg.getAsExpr();
+ }
+
if (NTTP->isParameterPack()) {
assert(Arg.getKind() == TemplateArgument::Pack &&
"Missing argument pack");
NewTTPDecl = cast_or_null<TemplateTypeParmDecl>(
TransformDecl(TL.getNameLoc(), OldTTPDecl));
- QualType Result
- = getSema().Context.getTemplateTypeParmType(T->getDepth()
- - TemplateArgs.getNumLevels(),
- T->getIndex(),
- T->isParameterPack(),
- NewTTPDecl);
+ QualType Result = getSema().Context.getTemplateTypeParmType(
+ T->getDepth() - TemplateArgs.getNumSubstitutedLevels(), T->getIndex(),
+ T->isParameterPack(), NewTTPDecl);
TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
return Result;
// TODO: don't always clone when decls are refcounted.
assert(D->getTypeForDecl()->isTemplateTypeParmType());
- TemplateTypeParmDecl *Inst =
- TemplateTypeParmDecl::Create(SemaRef.Context, Owner,
- D->getLocStart(), D->getLocation(),
- D->getDepth() - TemplateArgs.getNumLevels(),
- D->getIndex(), D->getIdentifier(),
- D->wasDeclaredWithTypename(),
- D->isParameterPack());
+ TemplateTypeParmDecl *Inst = TemplateTypeParmDecl::Create(
+ SemaRef.Context, Owner, D->getLocStart(), D->getLocation(),
+ D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), D->getIndex(),
+ D->getIdentifier(), D->wasDeclaredWithTypename(), D->isParameterPack());
Inst->setAccess(AS_public);
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
if (IsExpandedParameterPack)
Param = NonTypeTemplateParmDecl::Create(
SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(),
- D->getDepth() - TemplateArgs.getNumLevels(), D->getPosition(),
- D->getIdentifier(), T, DI, ExpandedParameterPackTypes,
+ D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
+ D->getPosition(), D->getIdentifier(), T, DI, ExpandedParameterPackTypes,
ExpandedParameterPackTypesAsWritten);
else
- Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner,
- D->getInnerLocStart(),
- D->getLocation(),
- D->getDepth() - TemplateArgs.getNumLevels(),
- D->getPosition(),
- D->getIdentifier(), T,
- D->isParameterPack(), DI);
+ Param = NonTypeTemplateParmDecl::Create(
+ SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(),
+ D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
+ D->getPosition(), D->getIdentifier(), T, D->isParameterPack(), DI);
Param->setAccess(AS_public);
if (Invalid)
// Build the template template parameter.
TemplateTemplateParmDecl *Param;
if (IsExpandedParameterPack)
- Param = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner,
- D->getLocation(),
- D->getDepth() - TemplateArgs.getNumLevels(),
- D->getPosition(),
- D->getIdentifier(), InstParams,
- ExpandedParams);
+ Param = TemplateTemplateParmDecl::Create(
+ SemaRef.Context, Owner, D->getLocation(),
+ D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
+ D->getPosition(), D->getIdentifier(), InstParams, ExpandedParams);
else
- Param = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner,
- D->getLocation(),
- D->getDepth() - TemplateArgs.getNumLevels(),
- D->getPosition(),
- D->isParameterPack(),
- D->getIdentifier(), InstParams);
+ Param = TemplateTemplateParmDecl::Create(
+ SemaRef.Context, Owner, D->getLocation(),
+ D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
+ D->getPosition(), D->isParameterPack(), D->getIdentifier(), InstParams);
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
NestedNameSpecifierLoc QualifierLoc =
D->getDefaultArgument().getTemplateQualifierLoc();
template <class A> struct T { template<typename B> T(A = 0, B = 0) {} };
T t(0, 0);
}
+
+namespace transform_params {
+ template<typename T, T N, template<T (*v)[N]> typename U, T (*X)[N]>
+ struct A { // expected-note 2{{candidate}}
+ template<typename V, V M, V (*Y)[M], template<V (*v)[M]> typename W>
+ A(U<X>, W<Y>); // expected-note {{[with V = int, M = 12, Y = &transform_params::n]}}
+
+ static constexpr T v = N;
+ };
+
+ int n[12];
+ template<int (*)[12]> struct Q {};
+ Q<&n> qn;
+ // FIXME: The class template argument deduction result here is correct, but
+ // we incorrectly fail to deduce arguments for the constructor!
+ A a(qn, qn); // expected-error {{no matching constructor for initialization of 'transform_params::A<int, 12, Q, &transform_params::n>'}}
+ static_assert(a.v == 12);
+
+ // FIXME: This causes a crash right now (not class template deduction related).
+#if 0
+ template<typename ...T> struct B {
+ template<T ...V> B(T (&...p)[V]);
+ };
+ B b({1, 2, 3}, {"foo", "bar"}, {'x', 'y', 'z', 'w'});
+#endif
+}
int n;
void h() { g<0>(Y<0, &n>()); } // expected-error {{no matching function}}
}
+
+namespace dependent_template_template_param_non_type_param_type {
+ template<int N> struct A { // expected-note 2{{candidate}}
+ template<typename V = int, V M = 12, V (*Y)[M], template<V (*v)[M]> class W>
+ A(W<Y>); // expected-note {{[with V = int, M = 12, Y = &dependent_template_template_param_non_type_param_type::n]}}
+ };
+
+ int n[12];
+ template<int (*)[12]> struct Q {};
+ Q<&n> qn;
+ // FIXME: This should be accepted, but we somehow fail to deduce W.
+ A<0> a(qn); // expected-error {{no matching constructor for initialization}}
+}