[cfe-commits] r83533 - in /cfe/trunk: include/clang/AST/ASTContext.h include/clang/AST/Decl.h include/clang/Basic/DiagnosticSemaKinds.td lib/AST/ASTContext.cpp lib/AST/Decl.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateInstantiate.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp

Douglas Gregor dgregor at apple.com
Thu Oct 8 00:24:58 PDT 2009


Author: dgregor
Date: Thu Oct  8 02:24:58 2009
New Revision: 83533

URL: http://llvm.org/viewvc/llvm-project?rev=83533&view=rev
Log:
For instantiations of static data members of class templates, keep
track of the kind of specialization or instantiation. Also, check the
scope of the specialization and ensure that a specialization
declaration without an initializer is not a definition.

Modified:
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp

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

==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Thu Oct  8 02:24:58 2009
@@ -154,7 +154,8 @@
   ///
   /// This data structure stores the mapping from instantiations of static
   /// data members to the static data member representations within the
-  /// class template from which they were instantiated.
+  /// class template from which they were instantiated along with the kind
+  /// of instantiation or specialization (a TemplateSpecializationKind - 1).
   ///
   /// Given the following example:
   ///
@@ -172,8 +173,9 @@
   ///
   /// This mapping will contain an entry that maps from the VarDecl for
   /// X<int>::value to the corresponding VarDecl for X<T>::value (within the
-  /// class template X).
-  llvm::DenseMap<VarDecl *, VarDecl *> InstantiatedFromStaticDataMember;
+  /// class template X) and will be marked TSK_ImplicitInstantiation.
+  llvm::DenseMap<VarDecl *, MemberSpecializationInfo *> 
+    InstantiatedFromStaticDataMember;
 
   /// \brief Keeps track of the UnresolvedUsingDecls from which UsingDecls
   /// where created during instantiation.
@@ -265,11 +267,12 @@
   /// \brief If this variable is an instantiated static data member of a
   /// class template specialization, returns the templated static data member
   /// from which it was instantiated.
-  VarDecl *getInstantiatedFromStaticDataMember(VarDecl *Var);
+  MemberSpecializationInfo *getInstantiatedFromStaticDataMember(VarDecl *Var);
 
   /// \brief Note that the static data member \p Inst is an instantiation of
   /// the static data member template \p Tmpl of a class template.
-  void setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl);
+  void setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
+                                           TemplateSpecializationKind TSK);
 
   /// \brief If this using decl is instantiated from an unresolved using decl,
   /// return it.

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

==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Thu Oct  8 02:24:58 2009
@@ -300,6 +300,29 @@
   APValue Evaluated;
 };
 
+// \brief Describes the kind of template specialization that a
+// particular template specialization declaration represents.
+enum TemplateSpecializationKind {
+  /// This template specialization was formed from a template-id but
+  /// has not yet been declared, defined, or instantiated.
+  TSK_Undeclared = 0,
+  /// This template specialization was implicitly instantiated from a
+  /// template. (C++ [temp.inst]).
+  TSK_ImplicitInstantiation,
+  /// This template specialization was declared or defined by an
+  /// explicit specialization (C++ [temp.expl.spec]) or partial
+  /// specialization (C++ [temp.class.spec]).
+  TSK_ExplicitSpecialization,
+  /// This template specialization was instantiated from a template
+  /// due to an explicit instantiation declaration request
+  /// (C++0x [temp.explicit]).
+  TSK_ExplicitInstantiationDeclaration,
+  /// This template specialization was instantiated from a template
+  /// due to an explicit instantiation definition request
+  /// (C++ [temp.explicit]).
+  TSK_ExplicitInstantiationDefinition
+};
+  
 /// VarDecl - An instance of this class is created to represent a variable
 /// declaration or definition.
 class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
@@ -566,6 +589,14 @@
   /// from which it was instantiated.
   VarDecl *getInstantiatedFromStaticDataMember();
 
+  /// \brief If this variable is a static data member, determine what kind of 
+  /// template specialization or instantiation this is.
+  TemplateSpecializationKind getTemplateSpecializationKind();
+  
+  /// \brief For a static data member that was instantiated from a static
+  /// data member of a class template, set the template specialiation kind.
+  void setTemplateSpecializationKind(TemplateSpecializationKind TSK);
+  
   /// isFileVarDecl - Returns true for file scoped variable declaration.
   bool isFileVarDecl() const {
     if (getKind() != Decl::Var)
@@ -754,29 +785,6 @@
   static bool classof(const OriginalParmVarDecl *D) { return true; }
 };
 
-// \brief Describes the kind of template specialization that a
-// particular template specialization declaration represents.
-enum TemplateSpecializationKind {
-  /// This template specialization was formed from a template-id but
-  /// has not yet been declared, defined, or instantiated.
-  TSK_Undeclared = 0,
-  /// This template specialization was implicitly instantiated from a
-  /// template. (C++ [temp.inst]).
-  TSK_ImplicitInstantiation,
-  /// This template specialization was declared or defined by an
-  /// explicit specialization (C++ [temp.expl.spec]) or partial
-  /// specialization (C++ [temp.class.spec]).
-  TSK_ExplicitSpecialization,
-  /// This template specialization was instantiated from a template
-  /// due to an explicit instantiation declaration request
-  /// (C++0x [temp.explicit]).
-  TSK_ExplicitInstantiationDeclaration,
-  /// This template specialization was instantiated from a template
-  /// due to an explicit instantiation definition request
-  /// (C++ [temp.explicit]).
-  TSK_ExplicitInstantiationDefinition
-};
-
 /// FunctionDecl - An instance of this class is created to represent a
 /// function declaration or definition.
 ///

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

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Oct  8 02:24:58 2009
@@ -948,9 +948,8 @@
   "%select{class template|class template partial|function template|member "
   "function|static data member|member class}0 specialization of %1 must occur "
   "at global scope">;
-def err_function_spec_not_instantiated : Error<
-  "specialization of member function %q0 does not specialize an instantiated "
-  "member function">;
+def err_spec_member_not_instantiated : Error<
+  "specialization of member %q0 does not specialize an instantiated member">;
 def note_specialized_decl : Note<"attempt to specialize declaration here">;
 
 // C++ class template specializations and out-of-line definitions

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

==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Thu Oct  8 02:24:58 2009
@@ -232,9 +232,10 @@
   InitBuiltinType(NullPtrTy,           BuiltinType::NullPtr);
 }
 
-VarDecl *ASTContext::getInstantiatedFromStaticDataMember(VarDecl *Var) {
+MemberSpecializationInfo *
+ASTContext::getInstantiatedFromStaticDataMember(VarDecl *Var) {
   assert(Var->isStaticDataMember() && "Not a static data member");
-  llvm::DenseMap<VarDecl *, VarDecl *>::iterator Pos
+  llvm::DenseMap<VarDecl *, MemberSpecializationInfo *>::iterator Pos
     = InstantiatedFromStaticDataMember.find(Var);
   if (Pos == InstantiatedFromStaticDataMember.end())
     return 0;
@@ -243,12 +244,14 @@
 }
 
 void
-ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl) {
+ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
+                                                TemplateSpecializationKind TSK) {
   assert(Inst->isStaticDataMember() && "Not a static data member");
   assert(Tmpl->isStaticDataMember() && "Not a static data member");
   assert(!InstantiatedFromStaticDataMember[Inst] &&
          "Already noted what static data member was instantiated from");
-  InstantiatedFromStaticDataMember[Inst] = Tmpl;
+  InstantiatedFromStaticDataMember[Inst] 
+    = new (*this) MemberSpecializationInfo(Tmpl, TSK);
 }
 
 UnresolvedUsingDecl *

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

==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Thu Oct  8 02:24:58 2009
@@ -371,7 +371,26 @@
 }
 
 VarDecl *VarDecl::getInstantiatedFromStaticDataMember() {
-  return getASTContext().getInstantiatedFromStaticDataMember(this);
+  if (MemberSpecializationInfo *MSI
+        = getASTContext().getInstantiatedFromStaticDataMember(this))
+    return cast<VarDecl>(MSI->getInstantiatedFrom());
+  
+  return 0;
+}
+
+TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() {
+  if (MemberSpecializationInfo *MSI
+        = getASTContext().getInstantiatedFromStaticDataMember(this))
+    return MSI->getTemplateSpecializationKind();
+  
+  return TSK_Undeclared;
+}
+
+void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
+  MemberSpecializationInfo *MSI
+    = getASTContext().getInstantiatedFromStaticDataMember(this);
+  assert(MSI && "Not an instantiated static data member?");
+  MSI->setTemplateSpecializationKind(TSK);
 }
 
 bool VarDecl::isTentativeDefinition(ASTContext &Context) const {

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu Oct  8 02:24:58 2009
@@ -2519,8 +2519,7 @@
                                            unsigned NumExplicitTemplateArgs,
                                            SourceLocation RAngleLoc,
                                            NamedDecl *&PrevDecl);
-  bool CheckMemberFunctionSpecialization(CXXMethodDecl *FD, 
-                                         NamedDecl *&PrevDecl);
+  bool CheckMemberSpecialization(NamedDecl *Member, NamedDecl *&PrevDecl);
     
   virtual DeclResult
   ActOnExplicitInstantiation(Scope *S,

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Oct  8 02:24:58 2009
@@ -2193,7 +2193,6 @@
 
   // Match up the template parameter lists with the scope specifier, then
   // determine whether we have a template or a template specialization.
-  // FIXME: Actually record when this is an explicit specialization!
   bool isExplicitSpecialization = false;
   if (TemplateParameterList *TemplateParams
         = MatchTemplateParametersToScopeSpecifier(
@@ -2259,7 +2258,7 @@
       !(NewVD->hasLinkage() &&
         isOutOfScopePreviousDeclaration(PrevDecl, DC, Context)))
     PrevDecl = 0;
-
+  
   // Merge the decl with the existing one if appropriate.
   if (PrevDecl) {
     if (isa<FieldDecl>(PrevDecl) && D.getCXXScopeSpec().isSet()) {
@@ -2281,6 +2280,11 @@
 
   CheckVariableDeclaration(NewVD, PrevDecl, Redeclaration);
 
+  // This is an explicit specialization of a static data member. Check it.
+  if (isExplicitSpecialization && !NewVD->isInvalidDecl() &&
+      CheckMemberSpecialization(NewVD, PrevDecl))
+    NewVD->setInvalidDecl();
+  
   // attributes declared post-definition are currently ignored
   if (PrevDecl) {
     const VarDecl *Def = 0, *PrevVD = dyn_cast<VarDecl>(PrevDecl);
@@ -2837,8 +2841,7 @@
                                               PrevDecl))
         NewFD->setInvalidDecl();
   } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD) &&
-             CheckMemberFunctionSpecialization(cast<CXXMethodDecl>(NewFD),
-                                               PrevDecl))
+             CheckMemberSpecialization(NewFD, PrevDecl))
     NewFD->setInvalidDecl();
            
   // Perform semantic checking on the function declaration.
@@ -3400,6 +3403,15 @@
       return;
     }
 
+    // C++ [temp.expl.spec]p15:
+    //   An explicit specialization of a static data member of a template is a
+    //   definition if the declaration includes an initializer; otherwise, it 
+    //   is a declaration.
+    if (Var->isStaticDataMember() &&
+        Var->getInstantiatedFromStaticDataMember() &&
+        Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+      return;
+    
     // C++ [dcl.init]p9:
     //   If no initializer is specified for an object, and the object
     //   is of (possibly cv-qualified) non-POD class type (or array

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Oct  8 02:24:58 2009
@@ -6209,11 +6209,9 @@
 
   if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
     // Implicit instantiation of static data members of class templates.
-    // FIXME: distinguish between implicit instantiations (which we need to
-    // actually instantiate) and explicit specializations.
-    // FIXME: extern templates
     if (Var->isStaticDataMember() &&
-        Var->getInstantiatedFromStaticDataMember())
+        Var->getInstantiatedFromStaticDataMember() &&
+        Var->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
       PendingImplicitInstantiations.push_back(std::make_pair(Var, Loc));
 
     // FIXME: keep track of references to static data?

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Oct  8 02:24:58 2009
@@ -2365,8 +2365,9 @@
     return CTS->getSpecializationKind();
   if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D))
     return Function->getTemplateSpecializationKind();
-
-  // FIXME: static data members!
+  if (VarDecl *Var = dyn_cast<VarDecl>(D))
+    return Var->getTemplateSpecializationKind();
+  
   // FIXME: member classes of class templates!
   return TSK_Undeclared;
 }
@@ -3118,7 +3119,7 @@
   return false;
 }
 
-/// \brief Perform semantic analysis for the given member function
+/// \brief Perform semantic analysis for the given non-template member
 /// specialization.
 ///
 /// This routine performs all of the semantic analysis required for an 
@@ -3126,27 +3127,45 @@
 /// the function declaration \p FD will become a member function
 /// specialization.
 ///
-/// \param FD the function declaration, which will be updated to become a
-/// function template specialization.
+/// \param Member the member declaration, which will be updated to become a
+/// specialization.
 ///
 /// \param PrevDecl the set of declarations, one of which may be specialized
 /// by this function specialization.
 bool 
-Sema::CheckMemberFunctionSpecialization(CXXMethodDecl *FD,
-                                        NamedDecl *&PrevDecl) {
-  // Try to find the member function we are instantiating.
-  CXXMethodDecl *Instantiation = 0;
-  for (OverloadIterator Ovl(PrevDecl), OvlEnd; Ovl != OvlEnd; ++Ovl) {
-    if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Ovl)) {
-      if (Context.hasSameType(FD->getType(), Method->getType())) {
-        Instantiation = Method;
-        break;
+Sema::CheckMemberSpecialization(NamedDecl *Member, NamedDecl *&PrevDecl) {
+  assert(!isa<TemplateDecl>(Member) && "Only for non-template members");
+         
+  // Try to find the member we are instantiating.
+  NamedDecl *Instantiation = 0;
+  NamedDecl *InstantiatedFrom = 0;
+  if (!PrevDecl) {
+    // Nowhere to look anyway.
+  } else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Member)) {
+    for (OverloadIterator Ovl(PrevDecl), OvlEnd; Ovl != OvlEnd; ++Ovl) {
+      if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Ovl)) {
+        if (Context.hasSameType(Function->getType(), Method->getType())) {
+          Instantiation = Method;
+          InstantiatedFrom = Method->getInstantiatedFromMemberFunction();
+          break;
+        }
+      }
+    }
+  } else if (isa<VarDecl>(Member)) {
+    if (VarDecl *PrevVar = dyn_cast<VarDecl>(PrevDecl))
+      if (PrevVar->isStaticDataMember()) {
+        Instantiation = PrevDecl;
+        InstantiatedFrom = PrevVar->getInstantiatedFromStaticDataMember();
       }
+  } else if (isa<RecordDecl>(Member)) {
+    if (CXXRecordDecl *PrevRecord = dyn_cast<CXXRecordDecl>(PrevDecl)) {
+      Instantiation = PrevDecl;
+      InstantiatedFrom = PrevRecord->getInstantiatedFromMemberClass();
     }
   }
   
   if (!Instantiation) {
-    // There is no previous declaration that matches. Since member function
+    // There is no previous declaration that matches. Since member
     // specializations are always out-of-line, the caller will complain about
     // this mismatch later.
     return false;
@@ -3155,30 +3174,43 @@
   // FIXME: Check if the prior declaration has a point of instantiation.
   // If so, we have run afoul of C++ [temp.expl.spec]p6.
   
-  // Make sure that this is a specialization of a member function.
-  FunctionDecl *FunctionInTemplate
-    = Instantiation->getInstantiatedFromMemberFunction();
-  if (!FunctionInTemplate) {
-    Diag(FD->getLocation(), diag::err_function_spec_not_instantiated)
-      << FD;
+  // Make sure that this is a specialization of a member.
+  if (!InstantiatedFrom) {
+    Diag(Member->getLocation(), diag::err_spec_member_not_instantiated)
+      << Member;
     Diag(Instantiation->getLocation(), diag::note_specialized_decl);
     return true;
   }
   
   // Check the scope of this explicit specialization.
   if (CheckTemplateSpecializationScope(*this, 
-                                       FunctionInTemplate,
-                                       Instantiation, FD->getLocation(), 
+                                       InstantiatedFrom,
+                                       Instantiation, Member->getLocation(), 
                                        false, TSK_ExplicitSpecialization))
     return true;
 
   // FIXME: Check for specialization-after-instantiation errors and such.
   
-  // Note that this function is an explicit instantiation of a member function.
-  Instantiation->setTemplateSpecializationKind(TSK_ExplicitSpecialization);
-  FD->setInstantiationOfMemberFunction(FunctionInTemplate, 
-                                       TSK_ExplicitSpecialization);
-  
+  // Note that this is an explicit instantiation of a member.
+  if (isa<FunctionDecl>(Member)) {
+    // FIXME: We're also setting the original instantiation we found to be
+    // an explicit specialization, although I'd rather not have to do this.
+    cast<FunctionDecl>(Instantiation)->setTemplateSpecializationKind(
+                                                    TSK_ExplicitSpecialization);
+    cast<FunctionDecl>(Member)->setInstantiationOfMemberFunction(
+                                        cast<CXXMethodDecl>(InstantiatedFrom),
+                                                  TSK_ExplicitSpecialization);
+  } else if (isa<VarDecl>(Member)) {
+    Context.setInstantiatedFromStaticDataMember(cast<VarDecl>(Member),
+                                                cast<VarDecl>(InstantiatedFrom),
+                                                TSK_ExplicitSpecialization);
+  } else {
+    assert(isa<CXXRecordDecl>(Member) && "Only member classes remain");
+    // FIXME: Record TSK_ExplicitSpecialization.
+    cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass(
+                                        cast<CXXRecordDecl>(InstantiatedFrom));
+  }
+             
   // Save the caller the trouble of having to figure out which declaration
   // this specialization matches.
   PrevDecl = Instantiation;
@@ -3547,7 +3579,8 @@
     }
     
     // Instantiate static data member.
-    // FIXME: Note that this is an explicit instantiation.
+    // FIXME: Check for prior specializations and such.
+    Prev->setTemplateSpecializationKind(TSK);
     if (TSK == TSK_ExplicitInstantiationDefinition)
       InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev, false);
     

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Thu Oct  8 02:24:58 2009
@@ -982,9 +982,12 @@
       if (!Function->getBody() && TSK != TSK_ExplicitInstantiationDeclaration)
         InstantiateFunctionDefinition(PointOfInstantiation, Function);
     } else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) {
-      if (Var->isStaticDataMember() && 
-          TSK != TSK_ExplicitInstantiationDeclaration)
-        InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var);
+      if (Var->isStaticDataMember()) {
+        Var->setTemplateSpecializationKind(TSK);
+        
+        if (TSK != TSK_ExplicitInstantiationDeclaration)
+          InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var);
+      }        
     } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(*D)) {
       if (Record->isInjectedClassName())
         continue;

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Thu Oct  8 02:24:58 2009
@@ -155,6 +155,12 @@
     Owner->addDecl(Var);
   }
 
+  // Link instantiations of static data members back to the template from
+  // which they were instantiated.
+  if (Var->isStaticDataMember())
+    SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D, 
+                                                        TSK_ImplicitInstantiation);
+  
   if (D->getInit()) {
     OwningExprResult Init
       = SemaRef.SubstExpr(D->getInit(), TemplateArgs);
@@ -191,11 +197,6 @@
   } else if (!Var->isStaticDataMember() || Var->isOutOfLine())
     SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false);
 
-  // Link instantiations of static data members back to the template from
-  // which they were instantiated.
-  if (Var->isStaticDataMember())
-    SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D);
-
   return Var;
 }
 
@@ -977,6 +978,10 @@
 
   assert(!Function->getBody() && "Already instantiated!");
 
+  // Never instantiate an explicit specialization.
+  if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+    return;
+  
   // Find the function body that we'll be substituting.
   const FunctionDecl *PatternDecl = 0;
   if (FunctionTemplateDecl *Primary = Function->getPrimaryTemplate()) {
@@ -1084,7 +1089,6 @@
     return;
 
   // Find the out-of-line definition of this static data member.
-  // FIXME: Do we have to look for specializations separately?
   VarDecl *Def = Var->getInstantiatedFromStaticDataMember();
   bool FoundOutOfLineDef = false;
   assert(Def && "This data member was not instantiated from a template?");
@@ -1106,7 +1110,17 @@
     return;
   }
 
-  // FIXME: extern templates
+  // Never instantiate an explicit specialization.
+  if (Def->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+    return;
+  
+  // C++0x [temp.explicit]p9:
+  //   Except for inline functions, other explicit instantiation declarations
+  //   have the effect of suppressing the implicit instantiation of the entity
+  //   to which they refer.
+  if (Def->getTemplateSpecializationKind() 
+        == TSK_ExplicitInstantiationDeclaration)
+    return;
 
   InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
   if (Inst)

Modified: cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp?rev=83533&r1=83532&r2=83533&view=diff

==============================================================================
--- cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp Thu Oct  8 02:24:58 2009
@@ -49,7 +49,7 @@
   
 template<typename T>
 struct X0 { // expected-note 2{{here}}
-  static T member;
+  static T member; // expected-note{{here}}
   
   void f1(T t) { // expected-note{{explicitly specialized declaration is here}}
     t = 17;
@@ -106,16 +106,27 @@
   x0.f1(cvp); // okay: we've explicitly specialized
 }
 
-#if 0
-// FIXME: update the remainder of this test to check for scopes properly.
 //     -- static data member of a class template
-template<> 
-NonDefaultConstructible X0<NonDefaultConstructible>::member = 17;
+namespace N0 {
+  // This actually tests p15; the following is a declaration, not a definition.
+  template<> 
+  NonDefaultConstructible X0<NonDefaultConstructible>::member;
+  
+  template<> long X0<long>::member = 17;
+
+  template<> float X0<float>::member;
+}
 
 NonDefaultConstructible &get_static_member() {
-  return X0<NonDefaultConstructible>::member;
+  return N0::X0<NonDefaultConstructible>::member;
 }
 
+template<> int N0::X0<int>::member;  // expected-error{{originally}}
+
+template<> float N0::X0<float>::member = 3.14f;
+
+#if 0
+// FIXME: update the remainder of this test to check for scopes properly.
 //    -- member class of a class template
 template<>
 struct X0<void*>::Inner { };





More information about the cfe-commits mailing list