def note_partial_spec_deduct_instantiation_here : Note<
"during template argument deduction for class template partial "
"specialization %0, here">;
+def note_prior_template_arg_substitution : Note<
+ "while substituting prior template arguments into %select{non-type|template}0"
+ " template parameter%1 %2">;
+
def err_field_instantiates_to_function : Error<
"data member instantiated with function type %0">;
def err_nested_name_spec_non_tag : Error<
std::string
getTemplateArgumentBindingsText(const TemplateParameterList *Params,
const TemplateArgumentList &Args);
+
+ std::string
+ getTemplateArgumentBindingsText(const TemplateParameterList *Params,
+ const TemplateArgument *Args,
+ unsigned NumArgs);
/// \brief Describes the result of template argument deduction.
///
/// partial specialization or a function template. The
/// Entity is either a ClassTemplatePartialSpecializationDecl or
/// a FunctionTemplateDecl.
- DeducedTemplateArgumentSubstitution
+ DeducedTemplateArgumentSubstitution,
+
+ /// We are substituting prior template arguments into a new
+ /// template parameter. The template parameter itself is either a
+ /// NonTypeTemplateParmDecl or a TemplateTemplateParmDecl.
+ PriorTemplateArgumentSubstitution
} Kind;
/// \brief The point of instantiation within the source code.
SourceLocation PointOfInstantiation;
+ /// \brief The template in which we are performing the instantiation,
+ /// for substitutions of prior template arguments.
+ TemplateDecl *Template;
+
/// \brief The entity that is being instantiated.
uintptr_t Entity;
- // \brief If this the instantiation of a default template
- // argument, the list of template arguments.
+ /// \brief The list of template arguments we are substituting, if they
+ /// are not part of the entity.
const TemplateArgument *TemplateArgs;
/// \brief The number of template arguments in TemplateArgs.
/// template instantiation.
SourceRange InstantiationRange;
- ActiveTemplateInstantiation() : Kind(TemplateInstantiation), Entity(0),
- TemplateArgs(0), NumTemplateArgs(0) {}
+ ActiveTemplateInstantiation()
+ : Kind(TemplateInstantiation), Template(0), Entity(0), TemplateArgs(0),
+ NumTemplateArgs(0) {}
friend bool operator==(const ActiveTemplateInstantiation &X,
const ActiveTemplateInstantiation &Y) {
case TemplateInstantiation:
return true;
+ case PriorTemplateArgumentSubstitution:
+ if (X.Template != Y.Template)
+ return false;
+
+ // Fall through
+
case DefaultTemplateArgumentInstantiation:
case ExplicitTemplateArgumentSubstitution:
case DeducedTemplateArgumentSubstitution:
unsigned NumTemplateArgs,
SourceRange InstantiationRange = SourceRange());
+ /// \brief Note that we are substituting prior template arguments into a
+ /// non-type or template template parameter.
+ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ TemplateDecl *Template,
+ NonTypeTemplateParmDecl *Param,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceRange InstantiationRange);
+
+ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ TemplateDecl *Template,
+ TemplateTemplateParmDecl *Param,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceRange InstantiationRange);
+
/// \brief Note that we have finished instantiating this template.
void Clear();
// A template-parameter shall not be used in its own default argument.
// FIXME: Implement this check! Needs a recursive walk over the types.
- // Check the well-formedness of the template argument.
+ // Check only that we have a template template argument. We don't want to
+ // try to check well-formedness now, because our template template parameter
+ // might have dependent types in its template parameters, which we wouldn't
+ // be able to match now.
+ //
+ // If none of the template template parameter's template arguments mention
+ // other template parameters, we could actually perform more checking here.
+ // However, it isn't worth doing.
TemplateArgumentLoc DefaultArg = translateTemplateArgument(*this, Default);
- if (CheckTemplateArgument(TemplateParm, DefaultArg)) {
- TemplateParm->setInvalidDecl();
+ if (DefaultArg.getArgument().getAsTemplate().isNull()) {
+ Diag(DefaultArg.getLocation(), diag::err_template_arg_not_class_template)
+ << DefaultArg.getSourceRange();
return;
}
-
+
TemplateParm->setDefaultArgument(DefaultArg);
}
QualType NTTPType = NTTP->getType();
if (NTTPType->isDependentType()) {
// Do substitution on the type of the non-type template parameter.
- InstantiatingTemplate Inst(*this, TemplateLoc,
- Template, Converted.getFlatArguments(),
+ InstantiatingTemplate Inst(*this, TemplateLoc, Template,
+ NTTP, Converted.getFlatArguments(),
Converted.flatSize(),
SourceRange(TemplateLoc, RAngleLoc));
TemplateTemplateParmDecl *TempParm
= cast<TemplateTemplateParmDecl>(*Param);
+ // Substitute into the template parameter list of the template
+ // template parameter, since previously-supplied template arguments
+ // may appear within the template template parameter.
+ {
+ // Set up a template instantiation context.
+ LocalInstantiationScope Scope(*this);
+ InstantiatingTemplate Inst(*this, TemplateLoc, Template,
+ TempParm, Converted.getFlatArguments(),
+ Converted.flatSize(),
+ SourceRange(TemplateLoc, RAngleLoc));
+
+ TemplateArgumentList TemplateArgs(Context, Converted,
+ /*TakeArgs=*/false);
+ TempParm = cast_or_null<TemplateTemplateParmDecl>(
+ SubstDecl(TempParm, CurContext,
+ MultiLevelTemplateArgumentList(TemplateArgs)));
+ if (!TempParm) {
+ Invalid = true;
+ break;
+ }
+
+ // FIXME: TempParam is leaked.
+ }
+
switch (Arg.getArgument().getKind()) {
case TemplateArgument::Null:
assert(false && "Should never see a NULL template argument here");
NextDiag = diag::note_template_param_different_kind;
}
Diag((*NewParm)->getLocation(), NextDiag)
- << IsTemplateTemplateParm;
+ << IsTemplateTemplateParm;
Diag((*OldParm)->getLocation(), diag::note_template_prev_declaration)
- << IsTemplateTemplateParm;
+ << IsTemplateTemplateParm;
}
return false;
}
if (isa<TemplateTypeParmDecl>(*OldParm)) {
// Okay; all template type parameters are equivalent (since we
// know we're at the same index).
-#if 0
- // FIXME: Enable this code in debug mode *after* we properly go through
- // and "instantiate" the template parameter lists of template template
- // parameters. It's only after this instantiation that (1) any dependent
- // types within the template parameter list of the template template
- // parameter can be checked, and (2) the template type parameter depths
- // will match up.
- QualType OldParmType
- = Context.getTypeDeclType(cast<TemplateTypeParmDecl>(*OldParm));
- QualType NewParmType
- = Context.getTypeDeclType(cast<TemplateTypeParmDecl>(*NewParm));
- assert(Context.getCanonicalType(OldParmType) ==
- Context.getCanonicalType(NewParmType) &&
- "type parameter mismatch?");
-#endif
} else if (NonTypeTemplateParmDecl *OldNTTP
= dyn_cast<NonTypeTemplateParmDecl>(*OldParm)) {
// The types of non-type template parameters must agree.
}
return false;
}
+ assert(OldNTTP->getDepth() == NewNTTP->getDepth() &&
+ "Non-type template parameter depth mismatch");
+ assert(OldNTTP->getPosition() == NewNTTP->getPosition() &&
+ "Non-type template parameter position mismatch");
} else {
// The template parameter lists of template template
// parameters must agree.
- // FIXME: Could we perform a faster "type" comparison here?
assert(isa<TemplateTemplateParmDecl>(*OldParm) &&
"Only template template parameters handled here");
TemplateTemplateParmDecl *OldTTP
/*IsTemplateTemplateParm=*/true,
TemplateArgLoc))
return false;
+
+ assert(OldTTP->getDepth() == NewTTP->getDepth() &&
+ "Template template parameter depth mismatch");
+ assert(OldTTP->getPosition() == NewTTP->getPosition() &&
+ "Template template parameter position mismatch");
}
}
std::string
Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params,
const TemplateArgumentList &Args) {
+ // FIXME: For variadic templates, we'll need to get the structured list.
+ return getTemplateArgumentBindingsText(Params, Args.getFlatArgumentList(),
+ Args.flat_size());
+}
+
+std::string
+Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params,
+ const TemplateArgument *Args,
+ unsigned NumArgs) {
std::string Result;
- if (!Params || Params->size() == 0)
+ if (!Params || Params->size() == 0 || NumArgs == 0)
return Result;
for (unsigned I = 0, N = Params->size(); I != N; ++I) {
+ if (I >= NumArgs)
+ break;
+
if (I == 0)
Result += "[with ";
else
}
Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
- SourceLocation PointOfInstantation,
+ SourceLocation PointOfInstantiation,
ParmVarDecl *Param,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs,
SourceRange InstantiationRange)
: SemaRef(SemaRef) {
- Invalid = CheckInstantiationDepth(PointOfInstantation, InstantiationRange);
+ Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange);
if (!Invalid) {
ActiveTemplateInstantiation Inst;
Inst.Kind
= ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation;
- Inst.PointOfInstantiation = PointOfInstantation;
+ Inst.PointOfInstantiation = PointOfInstantiation;
+ Inst.Entity = reinterpret_cast<uintptr_t>(Param);
+ Inst.TemplateArgs = TemplateArgs;
+ Inst.NumTemplateArgs = NumTemplateArgs;
+ Inst.InstantiationRange = InstantiationRange;
+ SemaRef.ActiveTemplateInstantiations.push_back(Inst);
+ }
+}
+
+Sema::InstantiatingTemplate::
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ TemplateDecl *Template,
+ NonTypeTemplateParmDecl *Param,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceRange InstantiationRange) : SemaRef(SemaRef) {
+ Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange);
+
+ if (!Invalid) {
+ ActiveTemplateInstantiation Inst;
+ Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution;
+ Inst.PointOfInstantiation = PointOfInstantiation;
+ Inst.Template = Template;
+ Inst.Entity = reinterpret_cast<uintptr_t>(Param);
+ Inst.TemplateArgs = TemplateArgs;
+ Inst.NumTemplateArgs = NumTemplateArgs;
+ Inst.InstantiationRange = InstantiationRange;
+ SemaRef.ActiveTemplateInstantiations.push_back(Inst);
+ }
+}
+
+Sema::InstantiatingTemplate::
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ TemplateDecl *Template,
+ TemplateTemplateParmDecl *Param,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceRange InstantiationRange) : SemaRef(SemaRef) {
+ Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange);
+
+ if (!Invalid) {
+ ActiveTemplateInstantiation Inst;
+ Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution;
+ Inst.PointOfInstantiation = PointOfInstantiation;
+ Inst.Template = Template;
Inst.Entity = reinterpret_cast<uintptr_t>(Param);
Inst.TemplateArgs = TemplateArgs;
Inst.NumTemplateArgs = NumTemplateArgs;
Inst.InstantiationRange = InstantiationRange;
SemaRef.ActiveTemplateInstantiations.push_back(Inst);
- Invalid = false;
}
}
break;
}
+ case ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution: {
+ NamedDecl *Parm = cast<NamedDecl>((Decl *)Active->Entity);
+ std::string Name;
+ if (!Parm->getName().empty())
+ Name = std::string(" '") + Parm->getName().str() + "'";
+
+ Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
+ diag::note_prior_template_arg_substitution)
+ << isa<TemplateTemplateParmDecl>(Parm)
+ << Name
+ << getTemplateArgumentBindingsText(
+ Active->Template->getTemplateParameters(),
+ Active->TemplateArgs,
+ Active->NumTemplateArgs)
+ << Active->InstantiationRange;
+ break;
+ }
}
}
}
return false;
case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation:
- // A default template argument instantiation may or may not be a
- // SFINAE context; look further up the stack.
+ case ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution:
+ // A default template argument instantiation and substitution into
+ // template parameters with arguments for prior parameters may or may
+ // not be a SFINAE context; look further up the stack.
break;
case ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution:
Member != MemberEnd; ++Member) {
Decl *NewMember = SubstDecl(*Member, Instantiation, TemplateArgs);
if (NewMember) {
- if (NewMember->isInvalidDecl())
+ if (NewMember->isInvalidDecl()) {
Invalid = true;
- else if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember))
+ } else if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember))
Fields.push_back(DeclPtrTy::make(Field));
else if (UsingDecl *UD = dyn_cast<UsingDecl>(NewMember))
Instantiation->addDecl(UD);
PI != PE; ++PI) {
NamedDecl *D = cast_or_null<NamedDecl>(Visit(*PI));
Params.push_back(D);
- Invalid = Invalid || !D;
+ Invalid = Invalid || !D || D->isInvalidDecl();
}
// Clean up if we had an error.
// Check validity of default arguments
template<template<class, int> class // expected-note{{previous template template parameter is here}}
= Y1> // expected-error{{template template argument has different template parameters than its corresponding template template parameter}}
- class C1;
+ class C1 {};
+
+C1<> c1;
struct X4;
int array4[is_same<X4<add_pointer>,
X4<add_pointer, add_pointer::apply> >::value? 1 : -1];
+
+template<int> struct X5 {}; // expected-note{{has a different type 'int'}}
+template<long> struct X5b {};
+template<typename T,
+ template<T> class B = X5> // expected-error{{template template argument has different}} \
+ // expected-note{{previous non-type template parameter}}
+ struct X6 {};
+
+X6<int> x6a;
+X6<long> x6b;
+X6<long, X5b> x6c;
apply<add_pointer, int>::type ip = &i;
apply<add_reference, int>::type ir = i;
apply<add_reference, float>::type fr = i; // expected-error{{non-const lvalue reference to type 'float' cannot be initialized with a value of type 'int'}}
+
+// Template template parameters
+template<int> struct B; // expected-note{{has a different type 'int'}}
+
+template<typename T,
+ template<T Value> class X> // expected-error{{cannot have type 'float'}} \
+ // expected-note{{with type 'long'}}
+struct X0 { };
+
+X0<int, B> x0b1;
+X0<float, B> x0b2; // expected-note{{while substituting}}
+X0<long, B> x0b3; // expected-error{{template template argument has different template parameters}}
Constant<float (*)(int, int), f> *c6; // expected-error{{non-type template argument of type 'float (*)(int, double)' cannot be converted to a value of type 'float (*)(int, int)'}}
-Constant<float, 0> *c7; // expected-note{{in instantiation of default argument for 'Constant<float>' required here}}
+Constant<float, 0> *c7; // expected-note{{while substituting}}
struct X2_arg;
X2<int>::Inner<X2_arg> x2i1;
-X2<float>::Inner<X2_arg> x2i2; // expected-note{{instantiation}}
+X2<float> x2a; // expected-note{{instantiation}}
X2<long>::Inner<X2_arg> x2i3; // expected-error{{template template argument has different}}