]> granicus.if.org Git - clang/commitdiff
Keep track of the template arguments deduced when matching a class
authorDouglas Gregor <dgregor@apple.com>
Sun, 2 Aug 2009 23:24:31 +0000 (23:24 +0000)
committerDouglas Gregor <dgregor@apple.com>
Sun, 2 Aug 2009 23:24:31 +0000 (23:24 +0000)
template partial specialization. Then, use those template arguments
when instantiating members of that class template partial
specialization. Fixes PR4607.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@77925 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/DeclTemplate.h
lib/AST/DeclTemplate.cpp
lib/Sema/SemaTemplateInstantiate.cpp
test/SemaTemplate/partial-spec-instantiate.cpp [new file with mode: 0644]

index 501f82d6ba82e08b54384d99febf3c37928c109e..fdd4d150f679dd52c5e4ade1daf01c86806ba7c2 100644 (file)
@@ -869,8 +869,23 @@ enum TemplateSpecializationKind {
 /// \endcode
 class ClassTemplateSpecializationDecl 
   : public CXXRecordDecl, public llvm::FoldingSetNode {
+    
+  /// \brief Structure that stores information about a class template 
+  /// specialization that was instantiated from a class template partial
+  /// specialization.
+  struct SpecializedPartialSpecialization {
+    /// \brief The class template partial specialization from which this
+    /// class template specialization was instantiated.
+    ClassTemplatePartialSpecializationDecl *PartialSpecialization;
+    
+    /// \brief The template argument list deduced for the class template
+    /// partial specialization itself.
+    TemplateArgumentList *TemplateArgs;
+  };
+    
   /// \brief The template that this specialization specializes
-  ClassTemplateDecl *SpecializedTemplate;
+  llvm::PointerUnion<ClassTemplateDecl *, SpecializedPartialSpecialization *>
+    SpecializedTemplate;
 
   /// \brief The template arguments used to describe this specialization.
   TemplateArgumentList TemplateArgs;
@@ -893,11 +908,13 @@ public:
          TemplateArgumentListBuilder &Builder,
          ClassTemplateSpecializationDecl *PrevDecl);
 
+  virtual void Destroy(ASTContext& C);
+
   /// \brief Retrieve the template that this specialization specializes.
-  ClassTemplateDecl *getSpecializedTemplate() const { 
-    return SpecializedTemplate; 
-  }
+  ClassTemplateDecl *getSpecializedTemplate() const;
 
+  /// \brief Retrieve the template arguments of the class template 
+  /// specialization.
   const TemplateArgumentList &getTemplateArgs() const { 
     return TemplateArgs;
   }
@@ -912,6 +929,56 @@ public:
     SpecializationKind = TSK;
   }
 
+  /// \brief If this class template specialization is an instantiation of
+  /// a template (rather than an explicit specialization), return the
+  /// class template or class template partial specialization from which it
+  /// was instantiated.
+  llvm::PointerUnion<ClassTemplateDecl *, 
+                     ClassTemplatePartialSpecializationDecl *>
+  getInstantiatedFrom() const {
+    if (getSpecializationKind() != TSK_ImplicitInstantiation &&
+        getSpecializationKind() != TSK_ExplicitInstantiation)
+      return (ClassTemplateDecl*)0;
+    
+    if (SpecializedPartialSpecialization *PartialSpec 
+          = SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>())
+      return PartialSpec->PartialSpecialization;
+    
+    return const_cast<ClassTemplateDecl*>(
+                             SpecializedTemplate.get<ClassTemplateDecl*>());
+  }
+    
+  /// \brief Retrieve the set of template arguments that should be used
+  /// to instantiate members of the class template or class template partial
+  /// specialization from which this class template specialization was
+  /// instantiated.
+  ///
+  /// \returns For a class template specialization instantiated from the primary
+  /// template, this function will return the same template arguments as
+  /// getTemplateArgs(). For a class template specialization instantiated from
+  /// a class template partial specialization, this function will return the
+  /// deduced template arguments for the class template partial specialization
+  /// itself.
+  const TemplateArgumentList &getTemplateInstantiationArgs() const {
+    if (SpecializedPartialSpecialization *PartialSpec 
+        = SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>())
+      return *PartialSpec->TemplateArgs;
+    
+    return getTemplateArgs();
+  }
+    
+  /// \brief Note that this class template specialization is actually an
+  /// instantiation of the given class template partial specialization whose
+  /// template arguments have been deduced.
+  void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec,
+                          TemplateArgumentList *TemplateArgs) {
+    SpecializedPartialSpecialization *PS 
+      = new (getASTContext()) SpecializedPartialSpecialization();
+    PS->PartialSpecialization = PartialSpec;
+    PS->TemplateArgs = TemplateArgs;
+    SpecializedTemplate = PS;
+  }
+    
   /// \brief Sets the type of this specialization as it was written by
   /// the user. This will be a class template specialization type.
   void setTypeAsWritten(QualType T) {
index 6b3ea437ab694a22ca8440976013c8d1fc9d9f20..f5f7bfec5fa99875260a2e56265c4ae90e91c7ca 100644 (file)
@@ -415,6 +415,22 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context,
   return Result;
 }
 
+void ClassTemplateSpecializationDecl::Destroy(ASTContext &C) {
+  if (SpecializedPartialSpecialization *PartialSpec 
+        = SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>())
+    C.Deallocate(PartialSpec);
+  
+  CXXRecordDecl::Destroy(C);
+}
+
+ClassTemplateDecl *
+ClassTemplateSpecializationDecl::getSpecializedTemplate() const { 
+  if (SpecializedPartialSpecialization *PartialSpec 
+      = SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>())
+    return PartialSpec->PartialSpecialization->getSpecializedTemplate();
+  return SpecializedTemplate.get<ClassTemplateDecl*>();
+}
+
 //===----------------------------------------------------------------------===//
 // ClassTemplatePartialSpecializationDecl Implementation
 //===----------------------------------------------------------------------===//
index cb43f1c6a0d856fa9643dcee63a56a9b3efa7e6b..ae16c7124c683d2637cf344585a3f30e801cfd1a 100644 (file)
@@ -32,7 +32,7 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D) {
   // Template arguments for a class template specialization.
   if (ClassTemplateSpecializationDecl *Spec 
         = dyn_cast<ClassTemplateSpecializationDecl>(D))
-    return Spec->getTemplateArgs();
+    return Spec->getTemplateInstantiationArgs();
 
   // Template arguments for a function template specialization.
   if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D))
@@ -50,7 +50,7 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D) {
 
   ClassTemplateSpecializationDecl *EnclosingTemplate 
     = cast<ClassTemplateSpecializationDecl>(EnclosingTemplateCtx);
-  return EnclosingTemplate->getTemplateArgs();
+  return EnclosingTemplate->getTemplateInstantiationArgs();
 }
 
 Sema::InstantiatingTemplate::
@@ -1011,6 +1011,7 @@ Sema::InstantiateClassTemplateSpecialization(
     //      instantiation is generated from that specialization.
     Pattern = Matched[0].first;
     TemplateArgs = Matched[0].second;
+    ClassTemplateSpec->setInstantiationOf(Matched[0].first, Matched[0].second);
   } else if (Matched.size() > 1) {
     //   -- If more than one matching specialization is found, the
     //      partial order rules (14.5.4.2) are used to determine
diff --git a/test/SemaTemplate/partial-spec-instantiate.cpp b/test/SemaTemplate/partial-spec-instantiate.cpp
new file mode 100644 (file)
index 0000000..8d1ae23
--- /dev/null
@@ -0,0 +1,20 @@
+// RUN: clang-cc -fsyntax-only %s
+
+// PR4607
+template <class T> struct X {};
+
+template <> struct X<char>
+{
+  static char* g();
+};
+
+template <class T> struct X2 {};
+
+template <class U>
+struct X2<U*> {
+  static void f() {
+    X<U>::g();
+  }
+};
+
+void a(char *a, char *b) {X2<char*>::f();}