]> granicus.if.org Git - clang/commitdiff
Initial infrastructure for class template partial specialization. Here
authorDouglas Gregor <dgregor@apple.com>
Sun, 31 May 2009 09:31:02 +0000 (09:31 +0000)
committerDouglas Gregor <dgregor@apple.com>
Sun, 31 May 2009 09:31:02 +0000 (09:31 +0000)
we have the basics of declaring and storing class template partial
specializations, matching class template partial specializations at
instantiation time via (limited) template argument deduction, and
using the class template partial specialization's pattern for
instantiation.

This patch is enough to make a simple is_pointer type trait work, but
not much else.

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

12 files changed:
include/clang/AST/DeclCXX.h
include/clang/AST/DeclNodes.def
include/clang/AST/DeclTemplate.h
include/clang/Basic/DiagnosticSemaKinds.td
lib/AST/DeclBase.cpp
lib/AST/DeclTemplate.cpp
lib/Sema/Sema.h
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateInstantiate.cpp
test/SemaTemplate/class-template-spec.cpp
test/SemaTemplate/instantiation-default-1.cpp
test/SemaTemplate/temp_class_spec.cpp [new file with mode: 0644]

index 36c461bf52e6fb0ad31be077ebbe50a11ee8f01d..4a74a2c2cbc4df9dc41394c1275aee02801f991b 100644 (file)
@@ -449,7 +449,8 @@ public:
 
   static bool classof(const Decl *D) { 
     return D->getKind() == CXXRecord || 
-           D->getKind() == ClassTemplateSpecialization; 
+           D->getKind() == ClassTemplateSpecialization ||
+           D->getKind() == ClassTemplatePartialSpecialization; 
   }
   static bool classof(const CXXRecordDecl *D) { return true; }
   static bool classof(const ClassTemplateSpecializationDecl *D) { 
index a82d26a20c05fb54c23ab2e67e1a076495c946a9..d1b921a4cb65508ff1201ace46e7f55985cc52ad 100644 (file)
@@ -86,6 +86,8 @@ ABSTRACT_DECL(Named,  Decl)
       DECL(Record, TagDecl)
         DECL(CXXRecord, RecordDecl)
           DECL(ClassTemplateSpecialization, CXXRecordDecl)
+            DECL(ClassTemplatePartialSpecialization, 
+                 ClassTemplateSpecializationDecl)
     DECL(TemplateTypeParm, TypeDecl)
   ABSTRACT_DECL(Value, NamedDecl)
     DECL(EnumConstant, ValueDecl)
@@ -141,8 +143,8 @@ DECL_RANGE(Named, OverloadedFunction, ObjCImplementation)
 DECL_RANGE(ObjCContainer, ObjCContainer, ObjCInterface)
 DECL_RANGE(Field, Field, ObjCAtDefsField)
 DECL_RANGE(Type, Typedef, TemplateTypeParm)
-DECL_RANGE(Tag, Enum, ClassTemplateSpecialization)
-DECL_RANGE(Record, Record, ClassTemplateSpecialization)
+DECL_RANGE(Tag, Enum, ClassTemplatePartialSpecialization)
+DECL_RANGE(Record, Record, ClassTemplatePartialSpecialization)
 DECL_RANGE(Value, EnumConstant, NonTypeTemplateParm)
 DECL_RANGE(Function, Function, CXXConversion)
 DECL_RANGE(Template, Template, TemplateTemplateParm)
index b68b46f56d0db62f13b077f62341303aa0983389..226af3411d5512a0288c1c7cdca66a939e7b97df 100644 (file)
@@ -24,6 +24,7 @@ class TemplateParameterList;
 class TemplateDecl;
 class FunctionTemplateDecl;
 class ClassTemplateDecl;
+class ClassTemplatePartialSpecializationDecl;
 class TemplateTypeParmDecl;
 class NonTypeTemplateParmDecl;
 class TemplateTemplateParmDecl;
@@ -619,7 +620,8 @@ enum TemplateSpecializationKind {
   /// has not yet been declared, defined, or instantiated.
   TSK_Undeclared = 0,
   /// This template specialization was declared or defined by an
-  /// explicit specialization (C++ [temp.expl.spec]).
+  /// explicit specialization (C++ [temp.expl.spec]) or partial
+  /// specialization (C++ [temp.class.spec]).
   TSK_ExplicitSpecialization,
   /// This template specialization was implicitly instantiated from a
   /// template. (C++ [temp.inst]).
@@ -654,7 +656,8 @@ class ClassTemplateSpecializationDecl
   /// Really a value of type TemplateSpecializationKind.
   unsigned SpecializationKind : 2;
 
-  ClassTemplateSpecializationDecl(ASTContext &Context,
+protected:
+  ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK,
                                   DeclContext *DC, SourceLocation L,
                                   ClassTemplateDecl *SpecializedTemplate,
                                   TemplateArgument *TemplateArgs,
@@ -686,16 +689,16 @@ public:
     SpecializationKind = TSK;
   }
 
-  void Profile(llvm::FoldingSetNodeID &ID) const {
-    Profile(ID, TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size());
-  }
-
   /// \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) {
     TypeForDecl = T.getTypePtr();
   }
 
+  void Profile(llvm::FoldingSetNodeID &ID) const {
+    Profile(ID, TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size());
+  }
+
   static void 
   Profile(llvm::FoldingSetNodeID &ID, const TemplateArgument *TemplateArgs, 
           unsigned NumTemplateArgs) {
@@ -704,12 +707,58 @@ public:
   }
 
   static bool classof(const Decl *D) { 
-    return D->getKind() == ClassTemplateSpecialization;
+    return D->getKind() == ClassTemplateSpecialization ||
+           D->getKind() == ClassTemplatePartialSpecialization;
   }
 
   static bool classof(const ClassTemplateSpecializationDecl *) {
     return true;
   }
+
+  static bool classof(const ClassTemplatePartialSpecializationDecl *) {
+    return true;
+  }
+};
+
+class ClassTemplatePartialSpecializationDecl 
+  : public ClassTemplateSpecializationDecl 
+{
+  /// \brief The list of template parameters 
+  TemplateParameterList* TemplateParams;
+
+  ClassTemplatePartialSpecializationDecl(ASTContext &Context,
+                                         DeclContext *DC, SourceLocation L,
+                                         TemplateParameterList *Params,
+                                         ClassTemplateDecl *SpecializedTemplate,
+                                         TemplateArgument *TemplateArgs,
+                                         unsigned NumTemplateArgs)
+    : ClassTemplateSpecializationDecl(Context, ClassTemplatePartialSpecialization,
+                                      DC, L, SpecializedTemplate, TemplateArgs,
+                                      NumTemplateArgs),
+      TemplateParams(Params) { }
+
+public:
+  static ClassTemplatePartialSpecializationDecl *
+  Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
+         TemplateParameterList *Params,
+         ClassTemplateDecl *SpecializedTemplate,
+         TemplateArgument *TemplateArgs, unsigned NumTemplateArgs,
+         ClassTemplatePartialSpecializationDecl *PrevDecl);
+
+  /// Get the list of template parameters
+  TemplateParameterList *getTemplateParameters() const {
+    return TemplateParams;
+  }
+
+  // FIXME: Add Profile support!
+
+  static bool classof(const Decl *D) { 
+    return D->getKind() == ClassTemplatePartialSpecialization;
+  }
+
+  static bool classof(const ClassTemplatePartialSpecializationDecl *) {
+    return true;
+  }
 };
 
 /// Declaration of a class template.
@@ -722,6 +771,11 @@ protected:
     /// template, including explicit specializations and instantiations.
     llvm::FoldingSet<ClassTemplateSpecializationDecl> Specializations;
 
+    /// \brief The class template partial specializations for this class
+    /// template.
+    llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> 
+      PartialSpecializations;
+
     /// \brief The injected-class-name type for this class template.
     QualType InjectedClassNameType;
   };
@@ -768,6 +822,13 @@ public:
     return CommonPtr->Specializations;
   }
 
+  /// \brief Retrieve the set of partial specializations of this class
+  /// template.
+  llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> &
+  getPartialSpecializations() {
+    return CommonPtr->PartialSpecializations;
+  }
+
   /// \brief Retrieve the type of the injected-class-name for this
   /// class template.
   ///
index 946b8003bea3d98502f8148e4378de910587fe35..1f72c24963523e8bfd28159c402e1db487e0ee16 100644 (file)
@@ -733,8 +733,9 @@ def err_template_spec_needs_header : Error<
   "template specialization requires 'template<>'">;
 def err_template_spec_extra_headers : Error<
   "template specialization must have a single 'template<>' header">;
-def unsup_template_partial_spec : Error<
-  "class template partial specialization is not yet supported">;
+def unsup_template_partial_spec_ordering : Error<
+  "partial ordering of class template partial specializations is not yet "
+  "supported">;
 def err_template_spec_decl_out_of_scope_global : Error<
   "class template specialization of %0 must occur in the global scope">;
 def err_template_spec_decl_out_of_scope : Error<
index 80b422e75388413fcebfeb3584355120da80367c..fd7de715db7ff99002cbeb92c60d495f0814acdd 100644 (file)
@@ -212,6 +212,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
     // Aren't looked up?
     case UsingDirective:
     case ClassTemplateSpecialization:
+    case ClassTemplatePartialSpecialization:
       return 0;
   }
 }
@@ -399,6 +400,9 @@ bool DeclContext::isDependentContext() const {
   if (isFileContext())
     return false;
 
+  if (isa<ClassTemplatePartialSpecializationDecl>(this))
+    return true;
+
   if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(this))
     if (Record->getDescribedClassTemplate())
       return true;
index f1979c4bed6af8e53f20fbbbdb5a56bf709b3155..f38ee825106e2d7e76c76292849bdedc8bb45c97 100644 (file)
@@ -268,12 +268,12 @@ TemplateArgumentList::~TemplateArgumentList() {
 // ClassTemplateSpecializationDecl Implementation
 //===----------------------------------------------------------------------===//
 ClassTemplateSpecializationDecl::
-ClassTemplateSpecializationDecl(ASTContext &Context,
+ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK,
                                 DeclContext *DC, SourceLocation L,
                                 ClassTemplateDecl *SpecializedTemplate,
                                 TemplateArgument *TemplateArgs,
                                 unsigned NumTemplateArgs)
-  : CXXRecordDecl(ClassTemplateSpecialization
+  : CXXRecordDecl(DK
                   SpecializedTemplate->getTemplatedDecl()->getTagKind(), 
                   DC, L,
                   // FIXME: Should we use DeclarationName for the name of
@@ -292,10 +292,33 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context,
                                         unsigned NumTemplateArgs,
                                    ClassTemplateSpecializationDecl *PrevDecl) {
   ClassTemplateSpecializationDecl *Result
-    = new (Context)ClassTemplateSpecializationDecl(Context, DC, L, 
+    = new (Context)ClassTemplateSpecializationDecl(Context, 
+                                                   ClassTemplateSpecialization,
+                                                   DC, L, 
                                                    SpecializedTemplate,
                                                    TemplateArgs, 
                                                    NumTemplateArgs);
   Context.getTypeDeclType(Result, PrevDecl);
   return Result;
 }
+
+//===----------------------------------------------------------------------===//
+// ClassTemplatePartialSpecializationDecl Implementation
+//===----------------------------------------------------------------------===//
+ClassTemplatePartialSpecializationDecl *
+ClassTemplatePartialSpecializationDecl::
+Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
+       TemplateParameterList *Params,
+       ClassTemplateDecl *SpecializedTemplate,
+       TemplateArgument *TemplateArgs, unsigned NumTemplateArgs,
+       ClassTemplatePartialSpecializationDecl *PrevDecl) {
+  ClassTemplatePartialSpecializationDecl *Result
+    = new (Context)ClassTemplatePartialSpecializationDecl(Context, 
+                                                          DC, L, Params,
+                                                          SpecializedTemplate,
+                                                          TemplateArgs, 
+                                                          NumTemplateArgs);
+  Result->setSpecializationKind(TSK_ExplicitSpecialization);
+  Context.getTypeDeclType(Result, PrevDecl);
+  return Result;
+}
index d926fa9c4bd792f472545c6c0dab1fa5ae177d09..c428d29367defa6b39b5cf8d1bf313501ade3035 100644 (file)
@@ -68,6 +68,7 @@ namespace clang {
   class TemplateArgumentList;
   class TemplateParameterList;
   class TemplateTemplateParmDecl;
+  class ClassTemplatePartialSpecializationDecl;
   class ClassTemplateDecl;
   class ObjCInterfaceDecl;
   class ObjCCompatibleAliasDecl;
@@ -2017,6 +2018,17 @@ public:
   QualType CheckTypenameType(NestedNameSpecifier *NNS,
                              const IdentifierInfo &II,
                              SourceRange Range);
+
+  bool DeduceTemplateArguments(QualType Param, QualType Arg,
+                               llvm::SmallVectorImpl<TemplateArgument> &Deduced);
+  bool DeduceTemplateArguments(const TemplateArgument &Param,
+                               const TemplateArgument &Arg,
+                               llvm::SmallVectorImpl<TemplateArgument> &Deduced);
+  bool DeduceTemplateArguments(const TemplateArgumentList &ParamList,
+                               const TemplateArgumentList &ArgList,
+                               llvm::SmallVectorImpl<TemplateArgument> &Deduced);
+  bool DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
+                               const TemplateArgumentList &TemplateArgs);
                              
   //===--------------------------------------------------------------------===//
   // C++ Template Instantiation
index 179e27d8b7a63b3268bce51744e242c71c176f64..782a0d87d8971264363bcd3e0b418be01a0c5d6f 100644 (file)
@@ -2000,6 +2000,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
   ClassTemplateDecl *ClassTemplate 
     = cast<ClassTemplateDecl>(Name.getAsTemplateDecl());
 
+  bool isPartialSpecialization = false;
+
   // Check the validity of the template headers that introduce this
   // template.
   // FIXME: Once we have member templates, we'll need to check
@@ -2017,11 +2019,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
       return true;
     }
 
-    if (TemplateParams->size() > 0) {
-      // FIXME: No support for class template partial specialization.
-      Diag(TemplateParams->getTemplateLoc(), diag::unsup_template_partial_spec);
-      return true;
-    }
+    // FIXME: We'll need more checks, here!
+    if (TemplateParams->size() > 0)
+      isPartialSpecialization = true;
   }
 
   // Check that the specialization uses the same tag kind as the
@@ -2061,14 +2061,26 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
             ClassTemplate->getTemplateParameters()->size()) &&
          "Converted template argument list is too short!");
   
-  // Find the class template specialization declaration that
+  // Find the class template (partial) specialization declaration that
   // corresponds to these arguments.
   llvm::FoldingSetNodeID ID;
-  ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0],
-                                           ConvertedTemplateArgs.size());
+  if (isPartialSpecialization)
+    // FIXME: Template parameter list matters, too
+    ClassTemplatePartialSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0],
+                                                    ConvertedTemplateArgs.size());
+  else
+    ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0],
+                                             ConvertedTemplateArgs.size());
   void *InsertPos = 0;
-  ClassTemplateSpecializationDecl *PrevDecl
-    = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
+  ClassTemplateSpecializationDecl *PrevDecl = 0;
+
+  if (isPartialSpecialization)
+    PrevDecl
+      = ClassTemplate->getPartialSpecializations().FindNodeOrInsertPos(ID, 
+                                                                    InsertPos);
+  else
+    PrevDecl
+      = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
 
   ClassTemplateSpecializationDecl *Specialization = 0;
 
@@ -2088,6 +2100,31 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
     Specialization = PrevDecl;
     Specialization->setLocation(TemplateNameLoc);
     PrevDecl = 0;
+  } else if (isPartialSpecialization) {
+    // FIXME: extra checking for partial specializations
+
+    // Create a new class template partial specialization declaration node.
+    TemplateParameterList *TemplateParams 
+      = static_cast<TemplateParameterList*>(*TemplateParameterLists.get());
+    ClassTemplatePartialSpecializationDecl *PrevPartial
+      = cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl);
+    ClassTemplatePartialSpecializationDecl *Partial 
+      = ClassTemplatePartialSpecializationDecl::Create(Context, 
+                                             ClassTemplate->getDeclContext(),
+                                                TemplateNameLoc,
+                                                TemplateParams,
+                                                ClassTemplate,
+                                                &ConvertedTemplateArgs[0],
+                                                ConvertedTemplateArgs.size(),
+                                                PrevPartial);
+
+    if (PrevPartial) {
+      ClassTemplate->getPartialSpecializations().RemoveNode(PrevPartial);
+      ClassTemplate->getPartialSpecializations().GetOrInsertNode(Partial);
+    } else {
+      ClassTemplate->getPartialSpecializations().InsertNode(Partial, InsertPos);
+    }
+    Specialization = Partial;
   } else {
     // Create a new class template specialization declaration node for
     // this explicit specialization.
@@ -2119,7 +2156,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
       // instantiation with a special diagnostic.
       SourceRange Range(TemplateNameLoc, RAngleLoc);
       Diag(TemplateNameLoc, diag::err_redefinition) 
-        << Specialization << Range;
+        << Context.getTypeDeclType(Specialization) << Range;
       Diag(Def->getLocation(), diag::note_previous_definition);
       Specialization->setInvalidDecl();
       return true;
@@ -2526,3 +2563,89 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
       << Name;
   return QualType();
 }
+
+// FIXME: Move to SemaTemplateDeduction.cpp
+bool 
+Sema::DeduceTemplateArguments(QualType Param, QualType Arg,
+                             llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+  // We only want to look at the canonical types, since typedefs and
+  // sugar are not part of template argument deduction.
+  Param = Context.getCanonicalType(Param);
+  Arg = Context.getCanonicalType(Arg);
+
+  // If the parameter type is not dependent, just compare the types
+  // directly.
+  if (!Param->isDependentType())
+    return Param == Arg;
+
+  // FIXME: Use a visitor or switch to handle all of the kinds of
+  // types that the parameter may be.
+  if (const TemplateTypeParmType *TemplateTypeParm 
+        = Param->getAsTemplateTypeParmType()) {
+    (void)TemplateTypeParm; // FIXME: use this
+    // The argument type can not be less qualified than the parameter
+    // type.
+    if (Param.isMoreQualifiedThan(Arg))
+      return false;
+
+    unsigned Quals = Arg.getCVRQualifiers() & ~Param.getCVRQualifiers();
+    QualType DeducedType = Arg.getQualifiedType(Quals);
+    // FIXME: actually save the deduced type, and check that this
+    // deduction is consistent.
+    return true;
+  }
+
+  if (Param.getCVRQualifiers() != Arg.getCVRQualifiers())
+    return false;
+
+  if (const PointerType *PointerParam = Param->getAsPointerType()) {
+    const PointerType *PointerArg = Arg->getAsPointerType();
+    if (!PointerArg)
+      return false;
+
+    return DeduceTemplateArguments(PointerParam->getPointeeType(),
+                                   PointerArg->getPointeeType(),
+                                   Deduced);
+  }
+
+  // FIXME: Many more cases to go (to go).
+  return false;
+}
+
+bool
+Sema::DeduceTemplateArguments(const TemplateArgument &Param,
+                              const TemplateArgument &Arg,
+                             llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+  assert(Param.getKind() == Arg.getKind() &&
+         "Template argument kind mismatch during deduction");
+  switch (Param.getKind()) {
+  case TemplateArgument::Type: 
+    return DeduceTemplateArguments(Param.getAsType(), Arg.getAsType(),
+                                   Deduced);
+
+  default:
+    return false;
+  }
+}
+
+bool 
+Sema::DeduceTemplateArguments(const TemplateArgumentList &ParamList,
+                              const TemplateArgumentList &ArgList,
+                              llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+  assert(ParamList.size() == ArgList.size());
+  for (unsigned I = 0, N = ParamList.size(); I != N; ++I) {
+    if (!DeduceTemplateArguments(ParamList[I], ArgList[I], Deduced))
+      return false;
+  }
+  return true;
+}
+
+
+bool 
+Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
+                              const TemplateArgumentList &TemplateArgs) {
+  llvm::SmallVector<TemplateArgument, 4> Deduced;
+  Deduced.resize(Partial->getTemplateParameters()->size());
+  return DeduceTemplateArguments(Partial->getTemplateArgs(), TemplateArgs, 
+                                 Deduced);
+}
index 3cac739818190a1ac54b12470d163bff0c607c1c..d3d771b0ebb65759c83abfc875db632c73a74163 100644 (file)
@@ -822,14 +822,34 @@ Sema::InstantiateClassTemplateSpecialization(
   if (ClassTemplateSpec->getSpecializationKind() != TSK_Undeclared)
     return true;
 
-  // FIXME: Push this class template instantiation onto the instantiation stack,
-  // checking for recursion that exceeds a certain depth.
-
-  // FIXME: Perform class template partial specialization to select the best
-  // template.
   ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate();
-
   CXXRecordDecl *Pattern = Template->getTemplatedDecl();
+  const TemplateArgumentList *TemplateArgs 
+    = &ClassTemplateSpec->getTemplateArgs();
+
+  // Determine whether any class template partial specializations
+  // match the given template arguments.
+  llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> Matched;
+  for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator 
+         Partial = Template->getPartialSpecializations().begin(),
+         PartialEnd = Template->getPartialSpecializations().end();
+       Partial != PartialEnd;
+       ++Partial) {
+    if (DeduceTemplateArguments(&*Partial, ClassTemplateSpec->getTemplateArgs()))
+      Matched.push_back(&*Partial);
+  }
+
+  if (Matched.size() == 1) {
+    Pattern = Matched[0];
+    // FIXME: set TemplateArgs to the template arguments of the
+    // partial specialization, instantiated with the deduced template
+    // arguments.
+  } else if (Matched.size() > 1) {
+    // FIXME: Implement partial ordering of class template partial
+    // specializations.
+    Diag(ClassTemplateSpec->getLocation(), 
+         diag::unsup_template_partial_spec_ordering);
+  }
 
   // Note that this is an instantiation.  
   ClassTemplateSpec->setSpecializationKind(
@@ -837,8 +857,7 @@ Sema::InstantiateClassTemplateSpecialization(
                                              : TSK_ImplicitInstantiation);
 
   return InstantiateClass(ClassTemplateSpec->getLocation(),
-                          ClassTemplateSpec, Pattern,
-                          ClassTemplateSpec->getTemplateArgs(),
+                          ClassTemplateSpec, Pattern, *TemplateArgs,
                           ExplicitInstantiation);
 }
 
index b3dc3b2dca26c86e2687781e8169599bb7205c76..71d8ea14be6bb69cc73aa1f762b66697cd80e3b6 100644 (file)
@@ -52,9 +52,6 @@ A<char>::A() { }
 // Diagnose specialization errors
 struct A<double> { }; // expected-error{{template specialization requires 'template<>'}}
 
-template<typename T> // expected-error{{class template partial specialization is not yet supported}}
-struct A<T*> { };
-
 template<> struct ::A<double>;
 
 namespace N {
index ecb1fb73f9018eac0861a6eda39307adaf89d896..f0ce0d3cc669d3e2f47232fa909ef9473b400889 100644 (file)
@@ -36,7 +36,7 @@ typedef int& int_ref_t;
 Def2<int_ref_t> *d2; // expected-note{{in instantiation of default argument for 'Def2<int &>' required here}}
 
 
-template<> struct Def1<const int, const int> { }; // expected-error{{redefinition of 'Def1'}}
+template<> struct Def1<const int, const int> { }; // expected-error{{redefinition of 'Def1<int const>'}}
 
 template<typename T, typename T2 = T&> struct Def3;
 
diff --git a/test/SemaTemplate/temp_class_spec.cpp b/test/SemaTemplate/temp_class_spec.cpp
new file mode 100644 (file)
index 0000000..df652b5
--- /dev/null
@@ -0,0 +1,20 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<typename T>
+struct is_pointer {
+  static const bool value = false;
+};
+
+template<typename T>
+struct is_pointer<T*> {
+  static const bool value = true;
+};
+
+template<typename T>
+struct is_pointer<const T*> {
+  static const bool value = true;
+};
+
+int array0[is_pointer<int>::value? -1 : 1];
+int array1[is_pointer<int*>::value? 1 : -1];
+int array2[is_pointer<const int*>::value? 1 : -1]; // expected-error{{partial ordering}} \
+// expected-error{{negative}}