PR10147: When substituting a template template argument, substitute in the most

recent (non-friend) declaration to pick up the right set of default template
arguments.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@312049 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Richard Smith 2017-08-29 22:14:43 +00:00
parent d1cb214fe8
commit bfd88732fe
4 changed files with 34 additions and 9 deletions

View File

@ -262,6 +262,11 @@ public:
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;

View File

@ -131,6 +131,23 @@ DependentTemplateName *TemplateName::getAsDependentTemplateName() 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))

View File

@ -975,7 +975,7 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
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();
@ -1122,14 +1122,10 @@ TemplateName TemplateInstantiator::TransformTemplateName(
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;
@ -1143,7 +1139,7 @@ TemplateName TemplateInstantiator::TransformTemplateName(
TemplateArgument Arg = SubstPack->getArgumentPack();
Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
return Arg.getAsTemplate();
return Arg.getAsTemplate().getNameToSubstitute();
}
return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType,

View File

@ -141,3 +141,10 @@ namespace PR32185 {
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); }
}