Hi rsmith,

1. The basic test cases on static data member templates of class templates are 
now working.
More test cases are underway...

2. A bit of FIXME clean-up...

http://llvm-reviews.chandlerc.com/D1448

Files:
  include/clang/Sema/Sema.h
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaTemplate.cpp
  lib/Sema/SemaTemplateInstantiate.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/SemaCXX/cxx1y-variable-templates_in_class.cpp
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -1472,8 +1472,7 @@
                                      MultiTemplateParamsArg TemplateParamLists,
                                      bool &AddToScope);
   // Returns true if the variable declaration is a redeclaration
-  bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous,
-                                bool IsVariableTemplate = false);
+  bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous);
   void CheckVariableDeclarationType(VarDecl *NewVD);
   void CheckCompleteVariableDeclaration(VarDecl *var);
   void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D);
@@ -1869,7 +1868,7 @@
                                     Scope *S, bool MergeTypeWithOld);
   void mergeObjCMethodDecls(ObjCMethodDecl *New, ObjCMethodDecl *Old);
   void MergeVarDecl(VarDecl *New, LookupResult &Previous,
-                    bool IsVariableTemplate, bool MergeTypeWithPrevious);
+                    bool MergeTypeWithPrevious);
   void MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool MergeTypeWithOld);
   void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old);
   bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Scope *S);
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -2887,7 +2887,7 @@
 /// definitions here, since the initializer hasn't been attached.
 ///
 void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous,
-                        bool IsVariableTemplate, bool MergeTypeWithPrevious) {
+                        bool MergeTypeWithPrevious) {
   // If the new decl is already invalid, don't do any other checking.
   if (New->isInvalidDecl())
     return;
@@ -2896,7 +2896,7 @@
   VarDecl *Old = 0;
   if (Previous.isSingleResult() &&
       (Old = dyn_cast<VarDecl>(Previous.getFoundDecl()))) {
-    if (IsVariableTemplate)
+    if (New->getDescribedVarTemplate())
       Old = Old->getDescribedVarTemplate() ? Old : 0;
     else
       Old = Old->getDescribedVarTemplate() ? 0 : Old;
@@ -4893,10 +4893,9 @@
   bool IsVariableTemplateSpecialization = false;
   bool IsPartialSpecialization = false;
   bool IsVariableTemplate = false;
-  bool Invalid = false; // TODO: Can we remove this (error-prone)?
-  TemplateParameterList *TemplateParams = 0;
   VarTemplateDecl *PrevVarTemplate = 0;
-  VarDecl *NewVD;
+  VarDecl *NewVD = 0;
+  VarTemplateDecl *NewTemplate = 0;
   if (!getLangOpts().CPlusPlus) {
     NewVD = VarDecl::Create(Context, DC, D.getLocStart(),
                             D.getIdentifierLoc(), II,
@@ -4905,6 +4904,8 @@
     if (D.isInvalidType())
       NewVD->setInvalidDecl();
   } else {
+    bool Invalid = false;
+
     if (DC->isRecord() && !CurContext->isRecord()) {
       // This is an out-of-line definition of a static data member.
       switch (SC) {
@@ -4963,10 +4964,11 @@
 
     // Match up the template parameter lists with the scope specifier, then
     // determine whether we have a template or a template specialization.
-    TemplateParams = MatchTemplateParametersToScopeSpecifier(
-        D.getDeclSpec().getLocStart(), D.getIdentifierLoc(),
-        D.getCXXScopeSpec(), TemplateParamLists,
-        /*never a friend*/ false, IsExplicitSpecialization, Invalid);
+    TemplateParameterList *TemplateParams =
+        MatchTemplateParametersToScopeSpecifier(
+            D.getDeclSpec().getLocStart(), D.getIdentifierLoc(),
+            D.getCXXScopeSpec(), TemplateParamLists,
+            /*never a friend*/ false, IsExplicitSpecialization, Invalid);
     if (TemplateParams) {
       if (!TemplateParams->size() &&
           D.getName().getKind() != UnqualifiedId::IK_TemplateId) {
@@ -5090,13 +5092,24 @@
       NewVD = VarDecl::Create(Context, DC, D.getLocStart(),
                               D.getIdentifierLoc(), II, R, TInfo, SC);
 
+    // If this is supposed to be a variable template, create it as such.
+    if (IsVariableTemplate) {
+      NewTemplate =
+          VarTemplateDecl::Create(Context, DC, D.getIdentifierLoc(), Name,
+                                  TemplateParams, NewVD, PrevVarTemplate);
+      NewVD->setDescribedVarTemplate(NewTemplate);
+    }
+
     // If this decl has an auto type in need of deduction, make a note of the
     // Decl so we can diagnose uses of it in its own initializer.
     if (D.getDeclSpec().containsPlaceholderType() && R->getContainedAutoType())
       ParsingInitForAutoVars.insert(NewVD);
 
-    if (D.isInvalidType() || Invalid)
+    if (D.isInvalidType() || Invalid) {
       NewVD->setInvalidDecl();
+      if (NewTemplate)
+        NewTemplate->setInvalidDecl();
+    }
 
     SetNestedNameSpecifier(NewVD, D);
 
@@ -5120,6 +5133,8 @@
   // Set the lexical context. If the declarator has a C++ scope specifier, the
   // lexical context will be different from the semantic context.
   NewVD->setLexicalDeclContext(CurContext);
+  if (NewTemplate)
+    NewTemplate->setLexicalDeclContext(CurContext);
 
   if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) {
     if (NewVD->hasLocalStorage()) {
@@ -5178,8 +5193,11 @@
         << 0 << NewVD->getDeclName()
         << SourceRange(D.getDeclSpec().getModulePrivateSpecLoc())
         << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc());
-    else
+    else {
       NewVD->setModulePrivate();
+      if (NewTemplate)
+        NewTemplate->setModulePrivate();
+    }
   }
 
   // Handle attributes prior to checking for duplicates in MergeVarDecl
@@ -5188,6 +5206,13 @@
   if (NewVD->hasAttrs())
     CheckAlignasUnderalignment(NewVD);
 
+  if (IsVariableTemplate) {
+    if (PrevVarTemplate)
+      mergeDeclAttributes(NewVD, PrevVarTemplate->getTemplatedDecl());
+
+    AddPushedVisibilityAttribute(NewVD);
+  }
+
   if (getLangOpts().CUDA) {
     // CUDA B.2.5: "__shared__ and __constant__ variables have implied static
     // storage [duration]."
@@ -5285,11 +5310,9 @@
         LookupResult PrevDecl(*this, GetNameForDeclarator(D),
                               LookupOrdinaryName, ForRedeclaration);
         PrevDecl.addDecl(PrevVarTemplate->getTemplatedDecl());
-        D.setRedeclaration(
-            CheckVariableDeclaration(NewVD, PrevDecl, IsVariableTemplate));
+        D.setRedeclaration(CheckVariableDeclaration(NewVD, PrevDecl));
       } else
-        D.setRedeclaration(
-            CheckVariableDeclaration(NewVD, Previous, IsVariableTemplate));
+        D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
     }
 
     // This is an explicit specialization of a static data member. Check it.
@@ -5317,45 +5340,21 @@
     }
   }
 
-  // If this is not a variable template, return it now.
-  if (!IsVariableTemplate)
-    return NewVD;
-
-  // If this is supposed to be a variable template, create it as such.
-  VarTemplateDecl *NewTemplate =
-      VarTemplateDecl::Create(Context, DC, D.getIdentifierLoc(), Name,
-                              TemplateParams, NewVD, PrevVarTemplate);
-  NewVD->setDescribedVarTemplate(NewTemplate);
-
-  if (D.getDeclSpec().isModulePrivateSpecified())
-    NewTemplate->setModulePrivate();
-
   // If we are providing an explicit specialization of a static variable
   // template, make a note of that.
   if (PrevVarTemplate && PrevVarTemplate->getInstantiatedFromMemberTemplate())
-    NewTemplate->setMemberSpecialization();
+    PrevVarTemplate->setMemberSpecialization();
 
-  // Set the lexical context of this template
-  NewTemplate->setLexicalDeclContext(CurContext);
-  if (NewVD->isStaticDataMember() && NewVD->isOutOfLine())
-    NewTemplate->setAccess(NewVD->getAccess());
+  if (NewTemplate) {
+    ActOnDocumentableDecl(NewTemplate);
 
-  if (PrevVarTemplate)
-    mergeDeclAttributes(NewVD, PrevVarTemplate->getTemplatedDecl());
+    if (NewVD->isStaticDataMember() && NewVD->isOutOfLine())
+      NewTemplate->setAccess(NewVD->getAccess());
 
-  AddPushedVisibilityAttribute(NewVD);
-
-  PushOnScopeChains(NewTemplate, S);
-  AddToScope = false;
-
-  if (Invalid) {
-    NewTemplate->setInvalidDecl();
-    NewVD->setInvalidDecl();
+    return NewTemplate;
   }
 
-  ActOnDocumentableDecl(NewTemplate);
-
-  return NewTemplate;
+  return NewVD;
 }
 
 /// \brief Diagnose variable or built-in function shadowing.  Implements
@@ -5721,9 +5720,7 @@
 /// Sets NewVD->isInvalidDecl() if an error was encountered.
 ///
 /// Returns true if the variable declaration is a redeclaration.
-bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
-                                    LookupResult &Previous,
-                                    bool IsVariableTemplate) {
+bool Sema::CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous) {
   CheckVariableDeclarationType(NewVD);
 
   // If the decl is already known invalid, don't check it.
@@ -5773,7 +5770,7 @@
   filterNonConflictingPreviousDecls(Context, NewVD, Previous);
 
   if (!Previous.empty()) {
-    MergeVarDecl(NewVD, Previous, IsVariableTemplate, MergeTypeWithPrevious);
+    MergeVarDecl(NewVD, Previous, MergeTypeWithPrevious);
     return true;
   }
   return false;
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -2391,7 +2391,7 @@
     // If we are providing an explicit specialization of a member variable
     // template specialization, make a note of that.
     if (PrevPartial && PrevPartial->getInstantiatedFromMember())
-      Partial->setMemberSpecialization();
+      PrevPartial->setMemberSpecialization();
 
     // Check that all of the template parameters of the variable template
     // partial specialization are deducible from the template
@@ -2477,6 +2477,9 @@
                           ForRedeclaration);
     PrevSpec.addDecl(PrevDecl);
     D.setRedeclaration(CheckVariableDeclaration(Specialization, PrevSpec));
+  } else if (Specialization->isStaticDataMember() &&
+             Specialization->isOutOfLine()) {
+    Specialization->setAccess(VarTemplate->getAccess());
   }
 
   // Link instantiations of static data members back to the template from
Index: lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiate.cpp
+++ lib/Sema/SemaTemplateInstantiate.cpp
@@ -2254,12 +2254,10 @@
   };
 }
 
-bool
-Sema::InstantiateClassTemplateSpecialization(
-                           SourceLocation PointOfInstantiation,
-                           ClassTemplateSpecializationDecl *ClassTemplateSpec,
-                           TemplateSpecializationKind TSK,
-                           bool Complain) {
+bool Sema::InstantiateClassTemplateSpecialization(
+    SourceLocation PointOfInstantiation,
+    ClassTemplateSpecializationDecl *ClassTemplateSpec,
+    TemplateSpecializationKind TSK, bool Complain) {
   // Perform the actual instantiation on the canonical declaration.
   ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>(
                                          ClassTemplateSpec->getCanonicalDecl());
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -952,7 +952,6 @@
 Decl *TemplateDeclInstantiator::VisitVarTemplateDecl(VarTemplateDecl *D) {
   assert(D->getTemplatedDecl()->isStaticDataMember() &&
          "Only static data member templates are allowed.");
-  // FIXME: Also only when instantiating a class?
 
   // Create a local instantiation scope for this variable template, which
   // will contain the instantiations of the template parameters.
@@ -1028,7 +1027,6 @@
     VarTemplatePartialSpecializationDecl *D) {
   assert(D->isStaticDataMember() &&
          "Only static data member templates are allowed.");
-  // FIXME: Also only when instantiating a class?
 
   VarTemplateDecl *VarTemplate = D->getSpecializedTemplate();
 
@@ -2668,12 +2666,17 @@
   InstPartialSpec->setInstantiatedFromMember(PartialSpec);
   InstPartialSpec->setTypeAsWritten(WrittenTy);
 
-  InstPartialSpec->setAccess(PartialSpec->getAccess());
-  // FIXME: How much of BuildVariableInstantiation() should go in here?
-
   // Add this partial specialization to the set of variable template partial
   // specializations. The instantiation of the initializer is not necessary.
   VarTemplate->AddPartialSpecialization(InstPartialSpec, /*InsertPos=*/0);
+
+  // Set the initializer, to use as pattern for initialization.
+  if (VarDecl *Def = PartialSpec->getDefinition(SemaRef.getASTContext()))
+    PartialSpec = cast<VarTemplatePartialSpecializationDecl>(Def);
+  SemaRef.BuildVariableInstantiation(InstPartialSpec, PartialSpec, TemplateArgs,
+                                     LateAttrs, StartingScope);
+  InstPartialSpec->setInit(PartialSpec->getInit());
+
   return InstPartialSpec;
 }
 
@@ -3303,9 +3306,12 @@
     const MultiLevelTemplateArgumentList &TemplateArgs) {
 
   // Do substitution on the type of the declaration
-  TypeSourceInfo *DI =
-      SubstType(PatternDecl->getTypeSourceInfo(), TemplateArgs,
-                PatternDecl->getTypeSpecStartLoc(), PatternDecl->getDeclName());
+  ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
+  TypeSourceInfo *DI = SubstType(
+      PatternDecl->getTypeSourceInfo(),
+      MultiLevelTemplateArgumentList(*TemplateArgumentList::CreateCopy(
+          Context, Innermost.begin(), Innermost.size())),
+      PatternDecl->getTypeSpecStartLoc(), PatternDecl->getDeclName());
   if (!DI)
     return 0;
 
@@ -3364,8 +3370,7 @@
   } else if (!isa<VarTemplateSpecializationDecl>(NewVar) &&
              OldVar->hasLinkage())
     LookupQualifiedName(Previous, NewVar->getDeclContext(), false);
-
-  CheckVariableDeclaration(NewVar, Previous, ForVarTemplate);
+  CheckVariableDeclaration(NewVar, Previous);
 
   if (OldVar->isOutOfLine()) {
     OldVar->getLexicalDeclContext()->addDecl(NewVar);
Index: test/SemaCXX/cxx1y-variable-templates_in_class.cpp
===================================================================
--- test/SemaCXX/cxx1y-variable-templates_in_class.cpp
+++ test/SemaCXX/cxx1y-variable-templates_in_class.cpp
@@ -127,13 +127,13 @@
 };
 
 namespace in_class_template {
-  // FIXME: member data templates of class templates are not well supported yet.
 
   template<typename T>
   class D0 {
     template<typename U> static U Data;
     template<typename U> static const U Data<U*> = U();
   };
+  template const int D0<float>::Data<int*>;
 
   template<typename T>
   class D1 {
@@ -142,14 +142,41 @@
   };
   template<typename T>
   template<typename U> U* D1<T>::Data<U*> = (U*)(0);
-    
-  namespace to_be_fixed {
-    // FIXME: The following generate runtime exceptions!
+  template int* D1<float>::Data<int*>;
+
+  template<typename T>
+  class D2 {
+    template<typename U> static U Data;
+    template<typename U> static U* Data<U*>;
+  };
+  template<>
+  template<typename U> U* D2<float>::Data<U*> = (U*)(0) + 1;
+  template int* D1<float>::Data<int*>;
 
-    //template<>
-    //template<typename U> U* D1<float>::Data<U*> = (U*)(0) + 1;
-    //template const int D0<float>::Data<int*>;
-    //template int* D1<float>::Data<int*>;
+  namespace bug_files {
+    // FIXME: A bug has been filed addressing an issue similar to these. 
+    // No error diagnosis should be produced, because an
+    // explicit specialization of a member templates of class 
+    // template specialization should not inherit the partial 
+    // specializations from the class template specialization.
+
+    template<typename T>
+    class D0 {
+      template<typename U> static U Data;
+      template<typename U> static const U Data<U*> = U(10);  // expected-note {{previous definition is here}}
+    };
+    template<>
+    template<typename U> U D0<float>::Data<U*> = U(100);  // expected-error{{redefinition of 'Data'}}
+
+    template<typename T>
+    class D1 {
+      template<typename U> static U Data;
+      template<typename U> static U* Data<U*>;  // expected-note {{previous definition is here}}
+    };  
+    template<typename T>
+    template<typename U> U* D1<T>::Data<U*> = (U*)(0);
+    template<>
+    template<typename U> U* D1<float>::Data<U*> = (U*)(0) + 1;  // expected-error{{redefinition of 'Data'}}
   }
 }
 
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to