diff options
| -rw-r--r-- | clang/include/clang/AST/TemplateName.h | 5 | ||||
| -rw-r--r-- | clang/lib/AST/TemplateName.cpp | 17 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 14 | ||||
| -rw-r--r-- | clang/test/SemaTemplate/temp_arg_template.cpp | 7 |
4 files changed, 34 insertions, 9 deletions
diff --git a/clang/include/clang/AST/TemplateName.h b/clang/include/clang/AST/TemplateName.h index 30ee834fd3c..45a610e638b 100644 --- a/clang/include/clang/AST/TemplateName.h +++ b/clang/include/clang/AST/TemplateName.h @@ -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; diff --git a/clang/lib/AST/TemplateName.cpp b/clang/lib/AST/TemplateName.cpp index 47a7d47e7a4..9dbe827df58 100644 --- a/clang/lib/AST/TemplateName.cpp +++ b/clang/lib/AST/TemplateName.cpp @@ -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)) diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index f4f0c804aee..1a06f9a2f85 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -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, diff --git a/clang/test/SemaTemplate/temp_arg_template.cpp b/clang/test/SemaTemplate/temp_arg_template.cpp index 8f59dd724cc..59deae70180 100644 --- a/clang/test/SemaTemplate/temp_arg_template.cpp +++ b/clang/test/SemaTemplate/temp_arg_template.cpp @@ -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); } +} |

