r188969 - Improve support for static data member templates. This revision still has at least one bug, as it does not respect the variable template specialization hierarchy well.

Larisse Voufo lvoufo at google.com
Wed Aug 21 17:28:27 PDT 2013


Author: lvoufo
Date: Wed Aug 21 19:28:27 2013
New Revision: 188969

URL: http://llvm.org/viewvc/llvm-project?rev=188969&view=rev
Log:
Improve support for static data member templates. This revision still has at least one bug, as it does not respect the variable template specialization hierarchy well.

Modified:
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=188969&r1=188968&r2=188969&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Aug 21 19:28:27 2013
@@ -5333,18 +5333,13 @@ Sema::ActOnVariableDeclarator(Scope *S,
   // 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 (PrevVarTemplate)
-    mergeDeclAttributes(NewVD, PrevVarTemplate->getTemplatedDecl());
-
-  AddPushedVisibilityAttribute(NewVD);
-
   PushOnScopeChains(NewTemplate, S);
   AddToScope = false;
 

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=188969&r1=188968&r2=188969&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Aug 21 19:28:27 2013
@@ -2391,7 +2391,7 @@ DeclResult Sema::ActOnVarTemplateSpecial
     // 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 @@ DeclResult Sema::ActOnVarTemplateSpecial
                           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

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=188969&r1=188968&r2=188969&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Wed Aug 21 19:28:27 2013
@@ -952,7 +952,6 @@ TemplateDeclInstantiator::VisitClassTemp
 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.
@@ -971,28 +970,11 @@ Decl *TemplateDeclInstantiator::VisitVar
       PrevVarTemplate = dyn_cast<VarTemplateDecl>(Found.front());
   }
 
-  // FIXME: This, and ForVarTemplate, is a hack that is probably unnecessary.
-  // We should use a simplified version of VisitVarDecl.
   VarDecl *VarInst =
       cast_or_null<VarDecl>(VisitVarDecl(Pattern, /*ForVarTemplate=*/ true));
 
   DeclContext *DC = Owner;
 
-  /* FIXME: This should be handled in VisitVarDecl, as used to produce
-     VarInst above.
-  // Instantiate the qualifier.
-  NestedNameSpecifierLoc QualifierLoc = Pattern->getQualifierLoc();
-  if (QualifierLoc) {
-    QualifierLoc =
-        SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc, TemplateArgs);
-    if (!QualifierLoc)
-      return 0;
-  }
-
-  if (QualifierLoc)
-    VarInst->setQualifierInfo(QualifierLoc);
-  */
-
   VarTemplateDecl *Inst = VarTemplateDecl::Create(
       SemaRef.Context, DC, D->getLocation(), D->getIdentifier(), InstParams,
       VarInst, PrevVarTemplate);
@@ -1028,7 +1010,6 @@ Decl *TemplateDeclInstantiator::VisitVar
     VarTemplatePartialSpecializationDecl *D) {
   assert(D->isStaticDataMember() &&
          "Only static data member templates are allowed.");
-  // FIXME: Also only when instantiating a class?
 
   VarTemplateDecl *VarTemplate = D->getSpecializedTemplate();
 
@@ -2669,11 +2650,18 @@ TemplateDeclInstantiator::InstantiateVar
   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,8 +3291,10 @@ VarTemplateSpecializationDecl *Sema::Com
     const MultiLevelTemplateArgumentList &TemplateArgs) {
 
   // Do substitution on the type of the declaration
+  MultiLevelTemplateArgumentList Innermost;
+  Innermost.addOuterTemplateArguments(TemplateArgs.getInnermost());
   TypeSourceInfo *DI =
-      SubstType(PatternDecl->getTypeSourceInfo(), TemplateArgs,
+      SubstType(PatternDecl->getTypeSourceInfo(), Innermost,
                 PatternDecl->getTypeSpecStartLoc(), PatternDecl->getDeclName());
   if (!DI)
     return 0;
@@ -3386,6 +3376,11 @@ void Sema::BuildVariableInstantiation(
 
   if (isa<VarTemplateSpecializationDecl>(NewVar)) {
     // Do not instantiate the variable just yet.
+  } else if (ForVarTemplate) {
+    assert(!NewVar->getInit() &&
+           "A variable should not have an initializer if it is templated"
+           " and we are instantiating its template");
+    NewVar->setInit(OldVar->getInit());
   } else
     InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs);
 

Modified: cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp?rev=188969&r1=188968&r2=188969&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp Wed Aug 21 19:28:27 2013
@@ -127,13 +127,13 @@ struct matrix_constants {
 };
 
 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,63 @@ namespace in_class_template {
   };
   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<typename T>
+  struct D3 {
+    template<typename U> static const U Data = U(100);
+  };
+  template const int D3<float>::Data<int>;
+#ifndef PRECXX11
+  static_assert(D3<float>::Data<int> == 100, "");
+#endif
+
+  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<>
-    //template<typename U> U* D1<float>::Data<U*> = (U*)(0) + 1;
-    //template const int D0<float>::Data<int*>;
-    //template int* D1<float>::Data<int*>;
+    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'}}
+  }
+  
+  namespace other_bugs {
+    // FIXME: This fails to properly initilize the variable 'k'.
+    
+    template<typename A> struct S { 
+      template<typename B> static int V;
+      template<typename B> static int V0;
+    };
+    template struct S<int>;
+    template<typename A> template<typename B> int S<A>::V0 = 123;
+    template<typename A> template<typename B> int S<A>::V<B> = 123;
+    int k = S<int>::V<void>;
   }
 }
 





More information about the cfe-commits mailing list