Improve support for static data member templates. This revision still has at least...
authorLarisse Voufo <lvoufo@google.com>
Thu, 22 Aug 2013 00:28:27 +0000 (00:28 +0000)
committerLarisse Voufo <lvoufo@google.com>
Thu, 22 Aug 2013 00:28:27 +0000 (00:28 +0000)
llvm-svn: 188969

clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaTemplate.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp

index 9dad47f..9f2e757 100644 (file)
@@ -5333,18 +5333,13 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
   // 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;
 
index 5d01691..f4f43ab 100644 (file)
@@ -2391,7 +2391,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
     // 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::ActOnVarTemplateSpecialization(
                           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 b53c197..8d066a0 100644 (file)
@@ -952,7 +952,6 @@ TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl(
 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::VisitVarTemplateDecl(VarTemplateDecl *D) {
       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::VisitVarTemplatePartialSpecializationDecl(
     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::InstantiateVarTemplatePartialSpecialization(
   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::CompleteVarTemplateSpecializationDecl(
     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);
 
index 7f2823c..077394f 100644 (file)
@@ -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
 
-    //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'}}
+  }
+  
+  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>;
   }
 }