[cfe-commits] r85447 - in /cfe/trunk: include/clang/AST/DeclTemplate.h include/clang/Basic/DiagnosticSemaKinds.td lib/AST/DeclTemplate.cpp lib/Sema/Sema.h lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateDeduction.cpp lib/Sema/SemaTemplateInstantiate.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/CXX/temp/temp.decls/temp.class.spec/p6.cpp

Douglas Gregor dgregor at apple.com
Wed Oct 28 17:04:12 PDT 2009


Author: dgregor
Date: Wed Oct 28 19:04:11 2009
New Revision: 85447

URL: http://llvm.org/viewvc/llvm-project?rev=85447&view=rev
Log:
Implement support for semantic checking and template instantiation of
class template partial specializations of member templates. Also,
fixes a silly little bug in the marking of "used" template parameters
in member templates. Fixes PR5236.

Modified:
    cfe/trunk/include/clang/AST/DeclTemplate.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/AST/DeclTemplate.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp

Modified: cfe/trunk/include/clang/AST/DeclTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=85447&r1=85446&r2=85447&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Wed Oct 28 19:04:11 2009
@@ -91,6 +91,13 @@
   /// arguments or if there is a parameter pack.
   unsigned getMinRequiredArguments() const;
 
+  /// \brief Get the depth of this template parameter list in the set of
+  /// template parameter lists.
+  ///
+  /// The first template parameter list in a declaration will have depth 0,
+  /// the second template parameter list will have depth 1, etc.
+  unsigned getDepth() const;
+  
   SourceLocation getTemplateLoc() const { return TemplateLoc; }
   SourceLocation getLAngleLoc() const { return LAngleLoc; }
   SourceLocation getRAngleLoc() const { return RAngleLoc; }
@@ -859,6 +866,12 @@
     InheritedDefault = Inherited;
   }
 
+  /// \brief Retrieve the depth of the template parameter.
+  unsigned getDepth() const;
+  
+  /// \brief Retrieve the index of the template parameter.
+  unsigned getIndex() const;
+
   /// \brief Returns whether this is a parameter pack.
   bool isParameterPack() const { return ParameterPack; }
 
@@ -1150,6 +1163,14 @@
   /// \brief The list of template parameters
   TemplateParameterList* TemplateParams;
 
+  /// \brief The class template partial specialization from which this 
+  /// class template partial specialization was instantiated.
+  ///
+  /// The boolean value will be true to indicate that this class template
+  /// partial specialization was specialized at this level.
+  llvm::PointerIntPair<ClassTemplatePartialSpecializationDecl *, 1, bool>
+      InstantiatedFromMember;
+    
   ClassTemplatePartialSpecializationDecl(ASTContext &Context,
                                          DeclContext *DC, SourceLocation L,
                                          TemplateParameterList *Params,
@@ -1160,7 +1181,7 @@
                                       ClassTemplatePartialSpecialization,
                                       DC, L, SpecializedTemplate, Builder,
                                       PrevDecl),
-      TemplateParams(Params) { }
+      TemplateParams(Params), InstantiatedFromMember(0, false) { }
 
 public:
   static ClassTemplatePartialSpecializationDecl *
@@ -1175,6 +1196,70 @@
     return TemplateParams;
   }
 
+  /// \brief Retrieve the member class template partial specialization from
+  /// which this particular class template partial specialization was
+  /// instantiated.
+  ///
+  /// \code
+  /// template<typename T>
+  /// struct Outer {
+  ///   template<typename U> struct Inner;
+  ///   template<typename U> struct Inner<U*> { }; // #1
+  /// };
+  ///
+  /// Outer<float>::Inner<int*> ii;
+  /// \endcode
+  ///
+  /// In this example, the instantiation of \c Outer<float>::Inner<int*> will
+  /// end up instantiating the partial specialization 
+  /// \c Outer<float>::Inner<U*>, which itself was instantiated from the class 
+  /// template partial specialization \c Outer<T>::Inner<U*>. Given 
+  /// \c Outer<float>::Inner<U*>, this function would return
+  /// \c Outer<T>::Inner<U*>.
+  ClassTemplatePartialSpecializationDecl *getInstantiatedFromMember() {
+    ClassTemplatePartialSpecializationDecl *First
+      = cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration());
+    return First->InstantiatedFromMember.getPointer();
+  }
+  
+  void setInstantiatedFromMember(
+                          ClassTemplatePartialSpecializationDecl *PartialSpec) {
+    ClassTemplatePartialSpecializationDecl *First
+      = cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration());
+    First->InstantiatedFromMember.setPointer(PartialSpec);
+  }
+    
+  /// \brief Determines whether this class template partial specialization 
+  /// template was a specialization of a member partial specialization.
+  ///
+  /// In the following example, the member template partial specialization
+  /// \c X<int>::Inner<T*> is a member specialization.
+  ///
+  /// \code
+  /// template<typename T>
+  /// struct X {
+  ///   template<typename U> struct Inner;
+  ///   template<typename U> struct Inner<U*>;
+  /// };
+  ///
+  /// template<> template<typename T>
+  /// struct X<int>::Inner<T*> { /* ... */ };
+  /// \endcode
+  bool isMemberSpecialization() {
+    ClassTemplatePartialSpecializationDecl *First
+      = cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration());
+    return First->InstantiatedFromMember.getInt();
+  }
+  
+  /// \brief Note that this member template is a specialization.
+  void setMemberSpecialization() {
+    ClassTemplatePartialSpecializationDecl *First
+      = cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration());
+    assert(First->InstantiatedFromMember.getPointer() &&
+           "Only member templates can be member template specializations");
+    return First->InstantiatedFromMember.setInt(true);
+  }
+    
   // FIXME: Add Profile support!
 
   static bool classof(const Decl *D) {

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=85447&r1=85446&r2=85447&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Oct 28 19:04:11 2009
@@ -1014,7 +1014,11 @@
 def err_partial_spec_ordering_ambiguous : Error<
     "ambiguous partial specializations of %0">;
 def note_partial_spec_match : Note<"partial specialization matches %0">;
-
+def err_partial_spec_redeclared : Error<
+  "class template partial specialization %0 cannot be redeclared">;
+def note_prev_partial_spec_here : Note<
+  "previous declaration of class template partial specialization %0 is here">;
+  
 // C++ Function template specializations
 def err_function_template_spec_no_match : Error<
     "no function template matches function template specialization %0">;

Modified: cfe/trunk/lib/AST/DeclTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclTemplate.cpp?rev=85447&r1=85446&r2=85447&view=diff

==============================================================================
--- cfe/trunk/lib/AST/DeclTemplate.cpp (original)
+++ cfe/trunk/lib/AST/DeclTemplate.cpp Wed Oct 28 19:04:11 2009
@@ -67,6 +67,21 @@
   return NumRequiredArgs;
 }
 
+unsigned TemplateParameterList::getDepth() const {
+  if (size() == 0)
+    return 0;
+  
+  const NamedDecl *FirstParm = getParam(0);
+  if (const TemplateTypeParmDecl *TTP
+        = dyn_cast<TemplateTypeParmDecl>(FirstParm))
+    return TTP->getDepth();
+  else if (const NonTypeTemplateParmDecl *NTTP 
+             = dyn_cast<NonTypeTemplateParmDecl>(FirstParm))
+    return NTTP->getDepth();
+  else
+    return cast<TemplateTemplateParmDecl>(FirstParm)->getDepth();
+}
+
 //===----------------------------------------------------------------------===//
 // TemplateDecl Implementation
 //===----------------------------------------------------------------------===//
@@ -229,6 +244,14 @@
   return new (C) TemplateTypeParmDecl(DC, L, Id, Typename, Type, ParameterPack);
 }
 
+unsigned TemplateTypeParmDecl::getDepth() const {
+  return TypeForDecl->getAs<TemplateTypeParmType>()->getDepth();
+}
+
+unsigned TemplateTypeParmDecl::getIndex() const {
+  return TypeForDecl->getAs<TemplateTypeParmType>()->getIndex();
+}
+
 //===----------------------------------------------------------------------===//
 // NonTypeTemplateParmDecl Method Implementations
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=85447&r1=85446&r2=85447&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Oct 28 19:04:11 2009
@@ -2869,6 +2869,7 @@
   
   void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
                                   bool OnlyDeduced,
+                                  unsigned Depth,
                                   llvm::SmallVectorImpl<bool> &Used);
   void MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
                                      llvm::SmallVectorImpl<bool> &Deduced);

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=85447&r1=85446&r2=85447&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Oct 28 19:04:11 2009
@@ -2880,8 +2880,6 @@
                                                   Converted.flatSize());
 
     // 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
@@ -2901,6 +2899,11 @@
     }
     Specialization = Partial;
 
+    // If we are providing an explicit specialization of a member class 
+    // template specialization, make a note of that.
+    if (PrevPartial && PrevPartial->getInstantiatedFromMember())
+      PrevPartial->setMemberSpecialization();
+    
     // Check that all of the template parameters of the class template
     // partial specialization are deducible from the template
     // arguments. If not, this class template partial specialization
@@ -2908,6 +2911,7 @@
     llvm::SmallVector<bool, 8> DeducibleParams;
     DeducibleParams.resize(TemplateParams->size());
     MarkUsedTemplateParameters(Partial->getTemplateArgs(), true, 
+                               TemplateParams->getDepth(),
                                DeducibleParams);
     unsigned NumNonDeducible = 0;
     for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I)

Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=85447&r1=85446&r2=85447&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Wed Oct 28 19:04:11 2009
@@ -1690,6 +1690,7 @@
 static void
 MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
                            bool OnlyDeduced,
+                           unsigned Level,
                            llvm::SmallVectorImpl<bool> &Deduced);
   
 /// \brief Determine whether the function template \p FT1 is at least as
@@ -1782,18 +1783,22 @@
   case TPOC_Call: {
     unsigned NumParams = std::min(Proto1->getNumArgs(), Proto2->getNumArgs());
     for (unsigned I = 0; I != NumParams; ++I)
-      ::MarkUsedTemplateParameters(S, Proto2->getArgType(I), false,
+      ::MarkUsedTemplateParameters(S, Proto2->getArgType(I), false, 
+                                   TemplateParams->getDepth(),
                                    UsedParameters);
     break;
   }
     
   case TPOC_Conversion:
-    ::MarkUsedTemplateParameters(S, Proto2->getResultType(), false,
+    ::MarkUsedTemplateParameters(S, Proto2->getResultType(), false, 
+                                 TemplateParams->getDepth(),
                                  UsedParameters);
     break;
     
   case TPOC_Other:
-    ::MarkUsedTemplateParameters(S, FD2->getType(), false, UsedParameters);
+    ::MarkUsedTemplateParameters(S, FD2->getType(), false, 
+                                 TemplateParams->getDepth(),
+                                 UsedParameters);
     break;
   }
   
@@ -2065,6 +2070,7 @@
 MarkUsedTemplateParameters(Sema &SemaRef,
                            const TemplateArgument &TemplateArg,
                            bool OnlyDeduced,
+                           unsigned Depth,
                            llvm::SmallVectorImpl<bool> &Used);
 
 /// \brief Mark the template parameters that are used by the given
@@ -2073,6 +2079,7 @@
 MarkUsedTemplateParameters(Sema &SemaRef,
                            const Expr *E,
                            bool OnlyDeduced,
+                           unsigned Depth,
                            llvm::SmallVectorImpl<bool> &Used) {
   // FIXME: if !OnlyDeduced, we have to walk the whole subexpression to 
   // find other occurrences of template parameters.
@@ -2085,7 +2092,8 @@
   if (!NTTP)
     return;
 
-  Used[NTTP->getIndex()] = true;
+  if (NTTP->getDepth() == Depth)
+    Used[NTTP->getIndex()] = true;
 }
 
 /// \brief Mark the template parameters that are used by the given
@@ -2094,13 +2102,15 @@
 MarkUsedTemplateParameters(Sema &SemaRef,
                            NestedNameSpecifier *NNS,
                            bool OnlyDeduced,
+                           unsigned Depth,
                            llvm::SmallVectorImpl<bool> &Used) {
   if (!NNS)
     return;
   
-  MarkUsedTemplateParameters(SemaRef, NNS->getPrefix(), OnlyDeduced, Used);
+  MarkUsedTemplateParameters(SemaRef, NNS->getPrefix(), OnlyDeduced, Depth,
+                             Used);
   MarkUsedTemplateParameters(SemaRef, QualType(NNS->getAsType(), 0), 
-                             OnlyDeduced, Used);
+                             OnlyDeduced, Depth, Used);
 }
   
 /// \brief Mark the template parameters that are used by the given
@@ -2109,16 +2119,20 @@
 MarkUsedTemplateParameters(Sema &SemaRef,
                            TemplateName Name,
                            bool OnlyDeduced,
+                           unsigned Depth,
                            llvm::SmallVectorImpl<bool> &Used) {
   if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
     if (TemplateTemplateParmDecl *TTP
-        = dyn_cast<TemplateTemplateParmDecl>(Template))
-      Used[TTP->getIndex()] = true;
+          = dyn_cast<TemplateTemplateParmDecl>(Template)) {
+      if (TTP->getDepth() == Depth)
+        Used[TTP->getIndex()] = true;
+    }
     return;
   }
   
   if (DependentTemplateName *DTN = Name.getAsDependentTemplateName())
-    MarkUsedTemplateParameters(SemaRef, DTN->getQualifier(), OnlyDeduced, Used);
+    MarkUsedTemplateParameters(SemaRef, DTN->getQualifier(), OnlyDeduced, 
+                               Depth, Used);
 }
 
 /// \brief Mark the template parameters that are used by the given
@@ -2126,6 +2140,7 @@
 static void
 MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
                            bool OnlyDeduced,
+                           unsigned Depth,
                            llvm::SmallVectorImpl<bool> &Used) {
   if (T.isNull())
     return;
@@ -2140,6 +2155,7 @@
     MarkUsedTemplateParameters(SemaRef,
                                cast<PointerType>(T)->getPointeeType(),
                                OnlyDeduced,
+                               Depth,
                                Used);
     break;
 
@@ -2147,6 +2163,7 @@
     MarkUsedTemplateParameters(SemaRef,
                                cast<BlockPointerType>(T)->getPointeeType(),
                                OnlyDeduced,
+                               Depth,
                                Used);
     break;
 
@@ -2155,69 +2172,74 @@
     MarkUsedTemplateParameters(SemaRef,
                                cast<ReferenceType>(T)->getPointeeType(),
                                OnlyDeduced,
+                               Depth,
                                Used);
     break;
 
   case Type::MemberPointer: {
     const MemberPointerType *MemPtr = cast<MemberPointerType>(T.getTypePtr());
     MarkUsedTemplateParameters(SemaRef, MemPtr->getPointeeType(), OnlyDeduced,
-                               Used);
+                               Depth, Used);
     MarkUsedTemplateParameters(SemaRef, QualType(MemPtr->getClass(), 0),
-                               OnlyDeduced, Used);
+                               OnlyDeduced, Depth, Used);
     break;
   }
 
   case Type::DependentSizedArray:
     MarkUsedTemplateParameters(SemaRef,
                                cast<DependentSizedArrayType>(T)->getSizeExpr(),
-                               OnlyDeduced, Used);
+                               OnlyDeduced, Depth, Used);
     // Fall through to check the element type
 
   case Type::ConstantArray:
   case Type::IncompleteArray:
     MarkUsedTemplateParameters(SemaRef,
                                cast<ArrayType>(T)->getElementType(),
-                               OnlyDeduced, Used);
+                               OnlyDeduced, Depth, Used);
     break;
 
   case Type::Vector:
   case Type::ExtVector:
     MarkUsedTemplateParameters(SemaRef,
                                cast<VectorType>(T)->getElementType(),
-                               OnlyDeduced, Used);
+                               OnlyDeduced, Depth, Used);
     break;
 
   case Type::DependentSizedExtVector: {
     const DependentSizedExtVectorType *VecType
       = cast<DependentSizedExtVectorType>(T);
     MarkUsedTemplateParameters(SemaRef, VecType->getElementType(), OnlyDeduced,
-                               Used);
+                               Depth, Used);
     MarkUsedTemplateParameters(SemaRef, VecType->getSizeExpr(), OnlyDeduced, 
-                               Used);
+                               Depth, Used);
     break;
   }
 
   case Type::FunctionProto: {
     const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
     MarkUsedTemplateParameters(SemaRef, Proto->getResultType(), OnlyDeduced,
-                               Used);
+                               Depth, Used);
     for (unsigned I = 0, N = Proto->getNumArgs(); I != N; ++I)
       MarkUsedTemplateParameters(SemaRef, Proto->getArgType(I), OnlyDeduced,
-                                 Used);
+                                 Depth, Used);
     break;
   }
 
-  case Type::TemplateTypeParm:
-    Used[cast<TemplateTypeParmType>(T)->getIndex()] = true;
+  case Type::TemplateTypeParm: {
+    const TemplateTypeParmType *TTP = cast<TemplateTypeParmType>(T);
+    if (TTP->getDepth() == Depth)
+      Used[TTP->getIndex()] = true;
     break;
+  }
 
   case Type::TemplateSpecialization: {
     const TemplateSpecializationType *Spec
       = cast<TemplateSpecializationType>(T);
     MarkUsedTemplateParameters(SemaRef, Spec->getTemplateName(), OnlyDeduced,
-                               Used);
+                               Depth, Used);
     for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
-      MarkUsedTemplateParameters(SemaRef, Spec->getArg(I), OnlyDeduced, Used);
+      MarkUsedTemplateParameters(SemaRef, Spec->getArg(I), OnlyDeduced, Depth,
+                                 Used);
     break;
   }
 
@@ -2225,14 +2247,14 @@
     if (!OnlyDeduced)
       MarkUsedTemplateParameters(SemaRef, 
                                  cast<ComplexType>(T)->getElementType(),
-                                 OnlyDeduced, Used);
+                                 OnlyDeduced, Depth, Used);
     break;
 
   case Type::Typename:
     if (!OnlyDeduced)
       MarkUsedTemplateParameters(SemaRef,
                                  cast<TypenameType>(T)->getQualifier(),
-                                 OnlyDeduced, Used);
+                                 OnlyDeduced, Depth, Used);
     break;
 
   // None of these types have any template parameters in them.
@@ -2259,6 +2281,7 @@
 MarkUsedTemplateParameters(Sema &SemaRef,
                            const TemplateArgument &TemplateArg,
                            bool OnlyDeduced,
+                           unsigned Depth,
                            llvm::SmallVectorImpl<bool> &Used) {
   switch (TemplateArg.getKind()) {
   case TemplateArgument::Null:
@@ -2267,25 +2290,27 @@
 
   case TemplateArgument::Type:
     MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsType(), OnlyDeduced,
-                               Used);
+                               Depth, Used);
     break;
 
   case TemplateArgument::Declaration:
     if (TemplateTemplateParmDecl *TTP
-        = dyn_cast<TemplateTemplateParmDecl>(TemplateArg.getAsDecl()))
-      Used[TTP->getIndex()] = true;
+          = dyn_cast<TemplateTemplateParmDecl>(TemplateArg.getAsDecl())) {
+      if (TTP->getDepth() == Depth)
+        Used[TTP->getIndex()] = true;
+    }
     break;
 
   case TemplateArgument::Expression:
     MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsExpr(), OnlyDeduced, 
-                               Used);
+                               Depth, Used);
     break;
       
   case TemplateArgument::Pack:
     for (TemplateArgument::pack_iterator P = TemplateArg.pack_begin(),
                                       PEnd = TemplateArg.pack_end();
          P != PEnd; ++P)
-      MarkUsedTemplateParameters(SemaRef, *P, OnlyDeduced, Used);
+      MarkUsedTemplateParameters(SemaRef, *P, OnlyDeduced, Depth, Used);
     break;
   }
 }
@@ -2301,10 +2326,11 @@
 /// deduced.
 void
 Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
-                                 bool OnlyDeduced,
+                                 bool OnlyDeduced, unsigned Depth,
                                  llvm::SmallVectorImpl<bool> &Used) {
   for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
-    ::MarkUsedTemplateParameters(*this, TemplateArgs[I], OnlyDeduced, Used);
+    ::MarkUsedTemplateParameters(*this, TemplateArgs[I], OnlyDeduced, 
+                                 Depth, Used);
 }
 
 /// \brief Marks all of the template parameters that will be deduced by a
@@ -2319,5 +2345,5 @@
   FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
   for (unsigned I = 0, N = Function->getNumParams(); I != N; ++I)
     ::MarkUsedTemplateParameters(*this, Function->getParamDecl(I)->getType(),
-                                 true, Deduced);
+                                 true, TemplateParams->getDepth(), Deduced);
 }

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=85447&r1=85446&r2=85447&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Wed Oct 28 19:04:11 2009
@@ -981,61 +981,72 @@
     }
   }
 
-  if (Matched.size() == 1) {
-    //   -- If exactly one matching specialization is found, the
-    //      instantiation is generated from that specialization.
-    Pattern = Matched[0].first;
-    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
-    //      whether one of the specializations is more specialized
-    //      than the others. If none of the specializations is more
-    //      specialized than all of the other matching
-    //      specializations, then the use of the class template is
-    //      ambiguous and the program is ill-formed.
+  if (Matched.size() >= 1) {
     llvm::SmallVector<MatchResult, 4>::iterator Best = Matched.begin();
-    for (llvm::SmallVector<MatchResult, 4>::iterator P = Best + 1,
-                                                  PEnd = Matched.end();
-         P != PEnd; ++P) {
-      if (getMoreSpecializedPartialSpecialization(P->first, Best->first) 
-            == P->first)
-        Best = P;
-    }
-    
-    // Determine if the best partial specialization is more specialized than
-    // the others.
-    bool Ambiguous = false;
-    for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
-                                                  PEnd = Matched.end();
-         P != PEnd; ++P) {
-      if (P != Best &&
-          getMoreSpecializedPartialSpecialization(P->first, Best->first)
-            != Best->first) {
-        Ambiguous = true;
-        break;
+    if (Matched.size() == 1) {
+      //   -- If exactly one matching specialization is found, the
+      //      instantiation is generated from that specialization.
+      // We don't need to do anything for this.
+    } else {
+      //   -- If more than one matching specialization is found, the
+      //      partial order rules (14.5.4.2) are used to determine
+      //      whether one of the specializations is more specialized
+      //      than the others. If none of the specializations is more
+      //      specialized than all of the other matching
+      //      specializations, then the use of the class template is
+      //      ambiguous and the program is ill-formed.
+      for (llvm::SmallVector<MatchResult, 4>::iterator P = Best + 1,
+                                                    PEnd = Matched.end();
+           P != PEnd; ++P) {
+        if (getMoreSpecializedPartialSpecialization(P->first, Best->first) 
+              == P->first)
+          Best = P;
       }
-    }
-     
-    if (Ambiguous) {
-      // Partial ordering did not produce a clear winner. Complain.
-      ClassTemplateSpec->setInvalidDecl();
-      Diag(PointOfInstantiation, diag::err_partial_spec_ordering_ambiguous)
-        << ClassTemplateSpec;
       
-      // Print the matching partial specializations.
+      // Determine if the best partial specialization is more specialized than
+      // the others.
+      bool Ambiguous = false;
       for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
                                                     PEnd = Matched.end();
-           P != PEnd; ++P)
-        Diag(P->first->getLocation(), diag::note_partial_spec_match)
-          << getTemplateArgumentBindingsText(P->first->getTemplateParameters(),
-                                             *P->second);
+           P != PEnd; ++P) {
+        if (P != Best &&
+            getMoreSpecializedPartialSpecialization(P->first, Best->first)
+              != Best->first) {
+          Ambiguous = true;
+          break;
+        }
+      }
+       
+      if (Ambiguous) {
+        // Partial ordering did not produce a clear winner. Complain.
+        ClassTemplateSpec->setInvalidDecl();
+        Diag(PointOfInstantiation, diag::err_partial_spec_ordering_ambiguous)
+          << ClassTemplateSpec;
+        
+        // Print the matching partial specializations.
+        for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
+                                                      PEnd = Matched.end();
+             P != PEnd; ++P)
+          Diag(P->first->getLocation(), diag::note_partial_spec_match)
+            << getTemplateArgumentBindingsText(P->first->getTemplateParameters(),
+                                               *P->second);
 
-      return true;
+        return true;
+      }
     }
     
     // Instantiate using the best class template partial specialization.
-    Pattern = Best->first;
+    ClassTemplatePartialSpecializationDecl *OrigPartialSpec = Best->first;
+    while (OrigPartialSpec->getInstantiatedFromMember()) {
+      // If we've found an explicit specialization of this class template,
+      // stop here and use that as the pattern.
+      if (OrigPartialSpec->isMemberSpecialization())
+        break;
+      
+      OrigPartialSpec = OrigPartialSpec->getInstantiatedFromMember();
+    }
+    
+    Pattern = OrigPartialSpec;
     ClassTemplateSpec->setInstantiationOf(Best->first, Best->second);
   } else {
     //   -- If no matches are found, the instantiation is generated

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=85447&r1=85446&r2=85447&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Wed Oct 28 19:04:11 2009
@@ -82,6 +82,10 @@
 
     TemplateParameterList *
       SubstTemplateParams(TemplateParameterList *List);
+      
+    bool InstantiateClassTemplatePartialSpecialization(
+                                              ClassTemplateDecl *ClassTemplate,
+                           ClassTemplatePartialSpecializationDecl *PartialSpec);
   };
 }
 
@@ -389,6 +393,21 @@
   return 0;
 }
 
+namespace {
+  class SortDeclByLocation {
+    SourceManager &SourceMgr;
+    
+  public:
+    explicit SortDeclByLocation(SourceManager &SourceMgr) 
+      : SourceMgr(SourceMgr) { }
+    
+    bool operator()(const Decl *X, const Decl *Y) const {
+      return SourceMgr.isBeforeInTranslationUnit(X->getLocation(),
+                                                 Y->getLocation());
+    }
+  };
+}
+
 Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
   TemplateParameterList *TempParams = D->getTemplateParameters();
   TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
@@ -413,13 +432,52 @@
   SemaRef.Context.getTypeDeclType(RecordInst);
   
   Owner->addDecl(Inst);
+  
+  // First, we sort the partial specializations by location, so 
+  // that we instantiate them in the order they were declared.
+  llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
+  for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
+         P = D->getPartialSpecializations().begin(), 
+         PEnd = D->getPartialSpecializations().end();
+       P != PEnd; ++P)
+    PartialSpecs.push_back(&*P);
+  std::sort(PartialSpecs.begin(), PartialSpecs.end(),
+            SortDeclByLocation(SemaRef.SourceMgr));
+  
+  // Instantiate all of the partial specializations of this member class 
+  // template.
+  for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I)
+    InstantiateClassTemplatePartialSpecialization(Inst, PartialSpecs[I]);
+  
   return Inst;
 }
 
 Decl *
 TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl(
                                    ClassTemplatePartialSpecializationDecl *D) {
-  assert(false &&"Partial specializations of member templates are unsupported");
+  ClassTemplateDecl *ClassTemplate = D->getSpecializedTemplate();
+  
+  // Lookup the already-instantiated declaration in the instantiation
+  // of the class template and return that.
+  DeclContext::lookup_result Found
+    = Owner->lookup(ClassTemplate->getDeclName());
+  if (Found.first == Found.second)
+    return 0;
+  
+  ClassTemplateDecl *InstClassTemplate
+    = dyn_cast<ClassTemplateDecl>(*Found.first);
+  if (!InstClassTemplate)
+    return 0;
+  
+  Decl *DCanon = D->getCanonicalDecl();
+  for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
+            P = InstClassTemplate->getPartialSpecializations().begin(),
+         PEnd = InstClassTemplate->getPartialSpecializations().end();
+       P != PEnd; ++P) {
+    if (P->getInstantiatedFromMember()->getCanonicalDecl() == DCanon)
+      return &*P;
+  }
+  
   return 0;
 }
 
@@ -431,7 +489,7 @@
   TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
   if (!InstParams)
     return NULL;
-
+  
   FunctionDecl *Instantiated = 0;
   if (CXXMethodDecl *DMethod = dyn_cast<CXXMethodDecl>(D->getTemplatedDecl()))
     Instantiated = cast_or_null<FunctionDecl>(VisitCXXMethodDecl(DMethod, 
@@ -945,6 +1003,130 @@
   return InstL;
 }
 
+/// \brief Instantiate the declaration of a class template partial 
+/// specialization.
+///
+/// \param ClassTemplate the (instantiated) class template that is partially
+// specialized by the instantiation of \p PartialSpec.
+///
+/// \param PartialSpec the (uninstantiated) class template partial 
+/// specialization that we are instantiating.
+///
+/// \returns true if there was an error, false otherwise.
+bool 
+TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
+                                            ClassTemplateDecl *ClassTemplate,
+                          ClassTemplatePartialSpecializationDecl *PartialSpec) {
+  // Substitute into the template parameters of the class template partial
+  // specialization.
+  TemplateParameterList *TempParams = PartialSpec->getTemplateParameters();
+  TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
+  if (!InstParams)
+    return true;
+  
+  // Substitute into the template arguments of the class template partial
+  // specialization.
+  const TemplateArgumentList &PartialSpecTemplateArgs 
+    = PartialSpec->getTemplateInstantiationArgs();
+  llvm::SmallVector<TemplateArgument, 4> InstTemplateArgs;
+  for (unsigned I = 0, N = PartialSpecTemplateArgs.size(); I != N; ++I) {
+    TemplateArgument Inst = SemaRef.Subst(PartialSpecTemplateArgs[I], 
+                                          TemplateArgs);
+    if (Inst.isNull())
+      return true;
+    
+    InstTemplateArgs.push_back(Inst);
+  }
+  
+
+  // Check that the template argument list is well-formed for this
+  // class template.
+  TemplateArgumentListBuilder Converted(ClassTemplate->getTemplateParameters(), 
+                                        InstTemplateArgs.size());
+  if (SemaRef.CheckTemplateArgumentList(ClassTemplate, 
+                                        PartialSpec->getLocation(),
+                                        /*FIXME:*/PartialSpec->getLocation(),
+                                        InstTemplateArgs.data(), 
+                                        InstTemplateArgs.size(),
+                                        /*FIXME:*/PartialSpec->getLocation(), 
+                                        false,
+                                        Converted))
+    return true;
+
+  // Figure out where to insert this class template partial specialization
+  // in the member template's set of class template partial specializations.
+  llvm::FoldingSetNodeID ID;
+  ClassTemplatePartialSpecializationDecl::Profile(ID,
+                                                  Converted.getFlatArguments(),
+                                                  Converted.flatSize(),
+                                                  SemaRef.Context);
+  void *InsertPos = 0;
+  ClassTemplateSpecializationDecl *PrevDecl
+    = ClassTemplate->getPartialSpecializations().FindNodeOrInsertPos(ID,
+                                                                     InsertPos);
+  
+  // Build the canonical type that describes the converted template
+  // arguments of the class template partial specialization.
+  QualType CanonType 
+    = SemaRef.Context.getTemplateSpecializationType(TemplateName(ClassTemplate),
+                                                  Converted.getFlatArguments(),
+                                                    Converted.flatSize());
+
+  // Build the fully-sugared type for this class template
+  // specialization as the user wrote in the specialization
+  // itself. This means that we'll pretty-print the type retrieved
+  // from the specialization's declaration the way that the user
+  // actually wrote the specialization, rather than formatting the
+  // name based on the "canonical" representation used to store the
+  // template arguments in the specialization.
+  QualType WrittenTy
+    = SemaRef.Context.getTemplateSpecializationType(TemplateName(ClassTemplate),
+                                                    InstTemplateArgs.data(),
+                                                    InstTemplateArgs.size(),
+                                                    CanonType);
+  
+  if (PrevDecl) {
+    // We've already seen a partial specialization with the same template
+    // parameters and template arguments. This can happen, for example, when
+    // substituting the outer template arguments ends up causing two
+    // class template partial specializations of a member class template
+    // to have identical forms, e.g.,
+    //
+    //   template<typename T, typename U>
+    //   struct Outer {
+    //     template<typename X, typename Y> struct Inner;
+    //     template<typename Y> struct Inner<T, Y>;
+    //     template<typename Y> struct Inner<U, Y>;
+    //   };
+    //
+    //   Outer<int, int> outer; // error: the partial specializations of Inner
+    //                          // have the same signature.
+    SemaRef.Diag(PartialSpec->getLocation(), diag::err_partial_spec_redeclared)
+      << WrittenTy;
+    SemaRef.Diag(PrevDecl->getLocation(), diag::note_prev_partial_spec_here)
+      << SemaRef.Context.getTypeDeclType(PrevDecl);
+    return true;
+  }
+  
+  
+  // Create the class template partial specialization declaration.
+  ClassTemplatePartialSpecializationDecl *InstPartialSpec
+    = ClassTemplatePartialSpecializationDecl::Create(SemaRef.Context, Owner, 
+                                                     PartialSpec->getLocation(), 
+                                                     InstParams,
+                                                     ClassTemplate, 
+                                                     Converted,
+                                                     0);
+  InstPartialSpec->setInstantiatedFromMember(PartialSpec);
+  InstPartialSpec->setTypeAsWritten(WrittenTy);
+  
+  // Add this partial specialization to the set of class template partial
+  // specializations.
+  ClassTemplate->getPartialSpecializations().InsertNode(InstPartialSpec,
+                                                        InsertPos);
+  return false;
+}
+
 /// \brief Does substitution on the type of the given function, including
 /// all of the function parameters.
 ///
@@ -1391,6 +1573,22 @@
   return false;
 }
 
+static bool 
+isInstantiationOf(ClassTemplatePartialSpecializationDecl *Pattern,
+                  ClassTemplatePartialSpecializationDecl *Instance) {
+  Pattern 
+    = cast<ClassTemplatePartialSpecializationDecl>(Pattern->getCanonicalDecl());
+  do {
+    Instance = cast<ClassTemplatePartialSpecializationDecl>(
+                                                Instance->getCanonicalDecl());
+    if (Pattern == Instance)
+      return true;
+    Instance = Instance->getInstantiatedFromMember();
+  } while (Instance);
+  
+  return false;
+}
+
 static bool isInstantiationOf(CXXRecordDecl *Pattern,
                               CXXRecordDecl *Instance) {
   Pattern = Pattern->getCanonicalDecl();
@@ -1481,6 +1679,11 @@
   if (FunctionTemplateDecl *Temp = dyn_cast<FunctionTemplateDecl>(Other))
     return isInstantiationOf(cast<FunctionTemplateDecl>(D), Temp);
 
+  if (ClassTemplatePartialSpecializationDecl *PartialSpec
+        = dyn_cast<ClassTemplatePartialSpecializationDecl>(Other))
+    return isInstantiationOf(cast<ClassTemplatePartialSpecializationDecl>(D),
+                             PartialSpec);
+
   if (FieldDecl *Field = dyn_cast<FieldDecl>(Other)) {
     if (!Field->getDeclName()) {
       // This is an unnamed field.

Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp?rev=85447&r1=85446&r2=85447&view=diff

==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp Wed Oct 28 19:04:11 2009
@@ -1,5 +1,6 @@
 // RUN: clang-cc -fsyntax-only -verify %s
 
+// Test class template partial specializations of member templates.
 template<typename T>
 struct X0 {
   template<typename U> struct Inner0 {
@@ -16,5 +17,39 @@
   static const unsigned value = 2;
 };
 
-// FIXME: Test instantiation of these partial specializations (once they are
-// implemented).
+int array0[X0<int>::Inner0<int>::value == 0? 1 : -1];
+int array1[X0<int>::Inner0<int*>::value == 1? 1 : -1];
+int array2[X0<int>::Inner0<const int*>::value == 2? 1 : -1];
+
+// Make sure we can provide out-of-line class template partial specializations
+// for member templates (and instantiate them).
+template<class T> struct A { 
+  struct C {
+    template<class T2> struct B;
+  };
+};
+
+// partial specialization of A<T>::C::B<T2> 
+template<class T> template<class T2> struct A<T>::C::B<T2*> { }; 
+
+A<short>::C::B<int*> absip;
+
+// Check for conflicts during template instantiation. 
+template<typename T, typename U>
+struct Outer {
+  template<typename X, typename Y> struct Inner;
+  template<typename Y> struct Inner<T, Y> {}; // expected-note{{previous}}
+  template<typename Y> struct Inner<U, Y> {}; // expected-error{{cannot be redeclared}}
+};
+
+Outer<int, int> outer; // expected-note{{instantiation}}
+
+// Test specialization of class template partial specialization members.
+template<> template<typename Z>
+struct X0<float>::Inner0<Z*> {
+  static const unsigned value = 3;
+};
+
+int array3[X0<float>::Inner0<int>::value == 0? 1 : -1];
+int array4[X0<float>::Inner0<int*>::value == 3? 1 : -1];
+int array5[X0<float>::Inner0<const int*>::value == 2? 1 : -1];





More information about the cfe-commits mailing list