TemplateName getUnderlying() const;
+ /// Get the template name to substitute when this template name is used as a
+ /// template template argument. This refers to the most recent declaration of
+ /// the template, including any default template arguments.
+ TemplateName getNameToSubstitute() const;
+
/// \brief Determines whether this is a dependent template name.
bool isDependent() const;
return Storage.dyn_cast<DependentTemplateName *>();
}
+TemplateName TemplateName::getNameToSubstitute() const {
+ TemplateDecl *Decl = getAsTemplateDecl();
+
+ // Substituting a dependent template name: preserve it as written.
+ if (!Decl)
+ return *this;
+
+ // If we have a template declaration, use the most recent non-friend
+ // declaration of that template.
+ Decl = cast<TemplateDecl>(Decl->getMostRecentDecl());
+ while (Decl->getFriendObjectKind()) {
+ Decl = cast<TemplateDecl>(Decl->getPreviousDecl());
+ assert(Decl && "all declarations of template are friends");
+ }
+ return TemplateName(Decl);
+}
+
bool TemplateName::isDependent() const {
if (TemplateDecl *Template = getAsTemplateDecl()) {
if (isa<TemplateTemplateParmDecl>(Template))
Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
}
- TemplateName Template = Arg.getAsTemplate();
+ TemplateName Template = Arg.getAsTemplate().getNameToSubstitute();
assert(!Template.isNull() && Template.getAsTemplateDecl() &&
"Wrong kind of template template argument");
return Template.getAsTemplateDecl();
Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
}
- TemplateName Template = Arg.getAsTemplate();
+ TemplateName Template = Arg.getAsTemplate().getNameToSubstitute();
assert(!Template.isNull() && "Null template template argument");
-
- // We don't ever want to substitute for a qualified template name, since
- // the qualifier is handled separately. So, look through the qualified
- // template name to its underlying declaration.
- if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
- Template = TemplateName(QTN->getTemplateDecl());
+ assert(!Template.getAsQualifiedTemplateName() &&
+ "template decl to substitute is qualified?");
Template = getSema().Context.getSubstTemplateTemplateParm(TTP, Template);
return Template;
TemplateArgument Arg = SubstPack->getArgumentPack();
Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
- return Arg.getAsTemplate();
+ return Arg.getAsTemplate().getNameToSubstitute();
}
return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType,
template<template<typename T, T> class U> struct A {};
template<template<typename T, T> class U> struct B : A<U> {};
}
+
+namespace PR10147 {
+ template<typename T> struct A {};
+ template<typename T = int> struct A;
+ template<template<typename...> class A> void f(A<int>*) { A<> a; } // expected-warning 0-1{{extension}}
+ void g() { f((A<>*)0); }
+}