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

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Tue Aug 29 15:14:43 PDT 2017


Author: rsmith
Date: Tue Aug 29 15:14:43 2017
New Revision: 312049

URL: http://llvm.org/viewvc/llvm-project?rev=312049&view=rev
Log:
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.

Modified:
    cfe/trunk/include/clang/AST/TemplateName.h
    cfe/trunk/lib/AST/TemplateName.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/test/SemaTemplate/temp_arg_template.cpp

Modified: cfe/trunk/include/clang/AST/TemplateName.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/TemplateName.h?rev=312049&r1=312048&r2=312049&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/TemplateName.h (original)
+++ cfe/trunk/include/clang/AST/TemplateName.h Tue Aug 29 15:14:43 2017
@@ -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;
 

Modified: cfe/trunk/lib/AST/TemplateName.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TemplateName.cpp?rev=312049&r1=312048&r2=312049&view=diff
==============================================================================
--- cfe/trunk/lib/AST/TemplateName.cpp (original)
+++ cfe/trunk/lib/AST/TemplateName.cpp Tue Aug 29 15:14:43 2017
@@ -131,6 +131,23 @@ DependentTemplateName *TemplateName::get
   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))

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=312049&r1=312048&r2=312049&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Tue Aug 29 15:14:43 2017
@@ -975,7 +975,7 @@ Decl *TemplateInstantiator::TransformDec
         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::Trans
         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::Trans
     
     TemplateArgument Arg = SubstPack->getArgumentPack();
     Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
-    return Arg.getAsTemplate();
+    return Arg.getAsTemplate().getNameToSubstitute();
   }
 
   return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType,

Modified: cfe/trunk/test/SemaTemplate/temp_arg_template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg_template.cpp?rev=312049&r1=312048&r2=312049&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_arg_template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_arg_template.cpp Tue Aug 29 15:14:43 2017
@@ -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); }
+}




More information about the cfe-commits mailing list