]> granicus.if.org Git - clang/commitdiff
PR10147: When substituting a template template argument, substitute in the most
authorRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 29 Aug 2017 22:14:43 +0000 (22:14 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 29 Aug 2017 22:14:43 +0000 (22:14 +0000)
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

include/clang/AST/TemplateName.h
lib/AST/TemplateName.cpp
lib/Sema/SemaTemplateInstantiate.cpp
test/SemaTemplate/temp_arg_template.cpp

index 30ee834fd3c057e13695df5262bf69c245830df7..45a610e638be0a9f60f66408a4a63ac27c04828a 100644 (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;
 
index 47a7d47e7a489875e388992a776a16836f322caf..9dbe827df580b09ab7e206d1397ffabbbef7e98f 100644 (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))
index f4f0c804aee1ab307eb6b8390318eef79b1ec3f3..1a06f9a2f85a387dece04fb7e1de4ecf001e58be 100644 (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,
index 8f59dd724cc212e58637edae460722f8dc0b56fe..59deae701801e9892c1aeaaf53b5fd9e13f5474b 100644 (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); }
+}