r191548 - Variable templates: handle instantiation of static data member templates

Richard Smith richard-llvm at metafoo.co.uk
Fri Sep 27 13:14:13 PDT 2013


Author: rsmith
Date: Fri Sep 27 15:14:12 2013
New Revision: 191548

URL: http://llvm.org/viewvc/llvm-project?rev=191548&view=rev
Log:
Variable templates: handle instantiation of static data member templates
appropriately, especially when they appear within class templates.

Added:
    cfe/trunk/test/CodeGenCXX/cxx1y-variable-template.cpp
Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/AST/DeclTemplate.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Template.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/Decl.cpp
    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/SemaCXX/cxx1y-variable-templates_in_class.cpp
    cfe/trunk/test/SemaTemplate/explicit-instantiation.cpp

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=191548&r1=191547&r2=191548&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Fri Sep 27 15:14:12 2013
@@ -1146,10 +1146,16 @@ public:
   /// from which it was instantiated.
   VarDecl *getInstantiatedFromStaticDataMember() const;
 
-  /// \brief If this variable is a static data member, determine what kind of
+  /// \brief If this variable is an instantiation of a variable template or a
+  /// static data member of a class template, determine what kind of
   /// template specialization or instantiation this is.
   TemplateSpecializationKind getTemplateSpecializationKind() const;
 
+  /// \brief If this variable is an instantiation of a variable template or a
+  /// static data member of a class template, determine its point of
+  /// instantiation.
+  SourceLocation getPointOfInstantiation() const;
+
   /// \brief If this variable is an instantiation of a static data member of a
   /// class template specialization, retrieves the member specialization
   /// information.

Modified: cfe/trunk/include/clang/AST/DeclTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=191548&r1=191547&r2=191548&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Fri Sep 27 15:14:12 2013
@@ -1387,7 +1387,7 @@ class ClassTemplateSpecializationDecl
 
     /// \brief The template argument list deduced for the class template
     /// partial specialization itself.
-    TemplateArgumentList *TemplateArgs;
+    const TemplateArgumentList *TemplateArgs;
   };
 
   /// \brief The template that this specialization specializes
@@ -1412,7 +1412,7 @@ class ClassTemplateSpecializationDecl
   ExplicitSpecializationInfo *ExplicitInfo;
 
   /// \brief The template arguments used to describe this specialization.
-  TemplateArgumentList *TemplateArgs;
+  const TemplateArgumentList *TemplateArgs;
 
   /// \brief The point where this template was instantiated (if any)
   SourceLocation PointOfInstantiation;
@@ -1563,7 +1563,7 @@ public:
   /// instantiation of the given class template partial specialization whose
   /// template arguments have been deduced.
   void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec,
-                          TemplateArgumentList *TemplateArgs) {
+                          const TemplateArgumentList *TemplateArgs) {
     assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() &&
            "Already set to a class template partial specialization!");
     SpecializedPartialSpecialization *PS
@@ -2250,7 +2250,7 @@ class VarTemplateSpecializationDecl : pu
 
     /// \brief The template argument list deduced for the variable template
     /// partial specialization itself.
-    TemplateArgumentList *TemplateArgs;
+    const TemplateArgumentList *TemplateArgs;
   };
 
   /// \brief The template that this specialization specializes.
@@ -2275,7 +2275,7 @@ class VarTemplateSpecializationDecl : pu
   ExplicitSpecializationInfo *ExplicitInfo;
 
   /// \brief The template arguments used to describe this specialization.
-  TemplateArgumentList *TemplateArgs;
+  const TemplateArgumentList *TemplateArgs;
   TemplateArgumentListInfo TemplateArgsInfo;
 
   /// \brief The point where this template was instantiated (if any).
@@ -2421,7 +2421,7 @@ public:
   /// instantiation of the given variable template partial specialization whose
   /// template arguments have been deduced.
   void setInstantiationOf(VarTemplatePartialSpecializationDecl *PartialSpec,
-                          TemplateArgumentList *TemplateArgs) {
+                          const TemplateArgumentList *TemplateArgs) {
     assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() &&
            "Already set to a variable template partial specialization!");
     SpecializedPartialSpecialization *PS =

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=191548&r1=191547&r2=191548&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Sep 27 15:14:12 2013
@@ -3302,11 +3302,11 @@ def warn_explicit_instantiation_unqualif
   InGroup<CXX11Compat>, DefaultIgnore;
 def err_explicit_instantiation_undefined_member : Error<
   "explicit instantiation of undefined %select{member class|member function|"
-  "static data member|static data member template}0 %1 of class template %2">;
+  "static data member}0 %1 of class template %2">;
 def err_explicit_instantiation_undefined_func_template : Error<
   "explicit instantiation of undefined function template %0">;
 def err_explicit_instantiation_undefined_var_template : Error<
-  "explicit instantiation of undefined variable template %0">;
+  "explicit instantiation of undefined variable template %q0">;
 def err_explicit_instantiation_declaration_after_definition : Error<
   "explicit instantiation declaration (with 'extern') follows explicit "
   "instantiation definition (without 'extern')">;

Modified: cfe/trunk/include/clang/Sema/Template.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Template.h?rev=191548&r1=191547&r2=191548&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Template.h (original)
+++ cfe/trunk/include/clang/Sema/Template.h Fri Sep 27 15:14:12 2013
@@ -493,7 +493,7 @@ namespace clang {
     Decl *VisitVarTemplateSpecializationDecl(
         VarTemplateDecl *VarTemplate, VarDecl *FromVar, void *InsertPos,
         const TemplateArgumentListInfo &TemplateArgsInfo,
-        SmallVectorImpl<TemplateArgument> &Converted);
+        llvm::ArrayRef<TemplateArgument> Converted);
 
     Decl *InstantiateTypedefNameDecl(TypedefNameDecl *D, bool IsTypeAlias);
     ClassTemplatePartialSpecializationDecl *

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=191548&r1=191547&r2=191548&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Fri Sep 27 15:14:12 2013
@@ -7864,14 +7864,7 @@ GVALinkage ASTContext::GetGVALinkageForV
   if (!VD->isExternallyVisible())
     return GVA_Internal;
 
-  // If this is a static data member, compute the kind of template
-  // specialization. Otherwise, this variable is not part of a
-  // template.
-  TemplateSpecializationKind TSK = TSK_Undeclared;
-  if (VD->isStaticDataMember())
-    TSK = VD->getTemplateSpecializationKind();
-
-  switch (TSK) {
+  switch (VD->getTemplateSpecializationKind()) {
   case TSK_Undeclared:
   case TSK_ExplicitSpecialization:
     return GVA_StrongExternal;

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=191548&r1=191547&r2=191548&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Fri Sep 27 15:14:12 2013
@@ -1689,13 +1689,24 @@ VarDecl::DefinitionKind VarDecl::isThisD
   //   A declaration is a definition unless [...] it contains the 'extern'
   //   specifier or a linkage-specification and neither an initializer [...],
   //   it declares a static data member in a class declaration [...].
-  // 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.
+  // C++1y [temp.expl.spec]p15:
+  //   An explicit specialization of a static data member or an explicit
+  //   specialization of a static data member template is a definition if the
+  //   declaration includes an initializer; otherwise, it is a declaration.
+  //
+  // FIXME: How do you declare (but not define) a partial specialization of
+  // a static data member template outside the containing class?
   if (isStaticDataMember()) {
-    if (isOutOfLine() && (hasInit() ||
-          getTemplateSpecializationKind() != TSK_ExplicitSpecialization))
+    if (isOutOfLine() &&
+        (hasInit() ||
+         // If the first declaration is out-of-line, this may be an
+         // instantiation of an out-of-line partial specialization of a variable
+         // template for which we have not yet instantiated the initializer.
+         (getFirstDeclaration()->isOutOfLine()
+              ? getTemplateSpecializationKind() == TSK_Undeclared
+              : getTemplateSpecializationKind() !=
+                    TSK_ExplicitSpecialization) ||
+         isa<VarTemplatePartialSpecializationDecl>(this)))
       return Definition;
     else
       return DeclarationOnly;
@@ -1710,6 +1721,13 @@ VarDecl::DefinitionKind VarDecl::isThisD
   if (hasInit())
     return Definition;
 
+  // A variable template specialization (other than a static data member
+  // template or an explicit specialization) is a declaration until we
+  // instantiate its initializer.
+  if (isa<VarTemplateSpecializationDecl>(this) &&
+      getTemplateSpecializationKind() != TSK_ExplicitSpecialization)
+    return DeclarationOnly;
+
   if (hasExternalStorage())
     return DeclarationOnly;
 
@@ -1978,10 +1996,21 @@ TemplateSpecializationKind VarDecl::getT
 
   if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
     return MSI->getTemplateSpecializationKind();
-  
+
   return TSK_Undeclared;
 }
 
+SourceLocation VarDecl::getPointOfInstantiation() const {
+  if (const VarTemplateSpecializationDecl *Spec =
+          dyn_cast<VarTemplateSpecializationDecl>(this))
+    return Spec->getPointOfInstantiation();
+
+  if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
+    return MSI->getPointOfInstantiation();
+
+  return SourceLocation();
+}
+
 VarTemplateDecl *VarDecl::getDescribedVarTemplate() const {
   return getASTContext().getTemplateOrSpecializationInfo(this)
       .dyn_cast<VarTemplateDecl *>();
@@ -2002,13 +2031,16 @@ MemberSpecializationInfo *VarDecl::getMe
 
 void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK,
                                          SourceLocation PointOfInstantiation) {
+  assert((isa<VarTemplateSpecializationDecl>(this) ||
+          getMemberSpecializationInfo()) &&
+         "not a variable or static data member template specialization");
+
   if (VarTemplateSpecializationDecl *Spec =
           dyn_cast<VarTemplateSpecializationDecl>(this)) {
     Spec->setSpecializationKind(TSK);
     if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() &&
         Spec->getPointOfInstantiation().isInvalid())
       Spec->setPointOfInstantiation(PointOfInstantiation);
-    return;
   }
 
   if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) {
@@ -2016,11 +2048,7 @@ void VarDecl::setTemplateSpecializationK
     if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() &&
         MSI->getPointOfInstantiation().isInvalid())
       MSI->setPointOfInstantiation(PointOfInstantiation);
-    return;
   }
-
-  llvm_unreachable(
-      "Not a variable or static data member template specialization");
 }
 
 void

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=191548&r1=191547&r2=191548&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Sep 27 15:14:12 2013
@@ -8338,7 +8338,8 @@ void Sema::AddInitializerToDecl(Decl *Re
     if (VDecl->getStorageClass() == SC_Extern &&
         (!getLangOpts().CPlusPlus ||
          !(Context.getBaseElementType(VDecl->getType()).isConstQualified() ||
-           VDecl->isExternC())))
+           VDecl->isExternC())) &&
+        !isTemplateInstantiation(VDecl->getTemplateSpecializationKind()))
       Diag(VDecl->getLocation(), diag::warn_extern_init);
 
     // C99 6.7.8p4. All file scoped initializers need to be constant.

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=191548&r1=191547&r2=191548&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Sep 27 15:14:12 2013
@@ -11767,45 +11767,33 @@ static void DoMarkVarDeclReferenced(Sema
 
   VarTemplateSpecializationDecl *VarSpec =
       dyn_cast<VarTemplateSpecializationDecl>(Var);
+  assert(!isa<VarTemplatePartialSpecializationDecl>(Var) &&
+         "Can't instantiate a partial template specialization.");
 
   // Implicit instantiation of static data members, static data member
   // templates of class templates, and variable template specializations.
   // Delay instantiations of variable templates, except for those
   // that could be used in a constant expression.
-  if (VarSpec || (Var->isStaticDataMember() &&
-                  Var->getInstantiatedFromStaticDataMember())) {
-    MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
-    if (VarSpec)
-      assert(!isa<VarTemplatePartialSpecializationDecl>(Var) &&
-             "Can't instantiate a partial template specialization.");
-    if (Var->isStaticDataMember())
-      assert(MSInfo && "Missing member specialization information?");
+  TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind();
+  if (isTemplateInstantiation(TSK)) {
+    bool TryInstantiating = TSK == TSK_ImplicitInstantiation;
 
-    SourceLocation PointOfInstantiation;
-    bool InstantiationIsOkay = true;
-    if (MSInfo) {
-      bool AlreadyInstantiated = !MSInfo->getPointOfInstantiation().isInvalid();
-      TemplateSpecializationKind TSK = MSInfo->getTemplateSpecializationKind();
-
-      if (TSK == TSK_ImplicitInstantiation &&
-          (!AlreadyInstantiated ||
-           Var->isUsableInConstantExpressions(SemaRef.Context))) {
-        if (!AlreadyInstantiated) {
-          // This is a modification of an existing AST node. Notify listeners.
-          if (ASTMutationListener *L = SemaRef.getASTMutationListener())
-            L->StaticDataMemberInstantiated(Var);
-          MSInfo->setPointOfInstantiation(Loc);
-        }
-        PointOfInstantiation = MSInfo->getPointOfInstantiation();
-      } else
-        InstantiationIsOkay = false;
-    } else {
-      if (VarSpec->getPointOfInstantiation().isInvalid())
-        VarSpec->setPointOfInstantiation(Loc);
-      PointOfInstantiation = VarSpec->getPointOfInstantiation();
+    if (TryInstantiating && !isa<VarTemplateSpecializationDecl>(Var)) {
+      if (Var->getPointOfInstantiation().isInvalid()) {
+        // This is a modification of an existing AST node. Notify listeners.
+        if (ASTMutationListener *L = SemaRef.getASTMutationListener())
+          L->StaticDataMemberInstantiated(Var);
+      } else if (!Var->isUsableInConstantExpressions(SemaRef.Context))
+        // Don't bother trying to instantiate it again, unless we might need
+        // its initializer before we get to the end of the TU.
+        TryInstantiating = false;
     }
 
-    if (InstantiationIsOkay) {
+    if (Var->getPointOfInstantiation().isInvalid())
+      Var->setTemplateSpecializationKind(TSK, Loc);
+
+    if (TryInstantiating) {
+      SourceLocation PointOfInstantiation = Var->getPointOfInstantiation();
       bool InstantiationDependent = false;
       bool IsNonDependent =
           VarSpec ? !TemplateSpecializationType::anyDependentTemplateArguments(

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=191548&r1=191547&r2=191548&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Fri Sep 27 15:14:12 2013
@@ -7372,13 +7372,8 @@ DeclResult Sema::ActOnExplicitInstantiat
     CheckExplicitInstantiationScope(*this, Prev, D.getIdentifierLoc(), true);
 
     // Verify that it is okay to explicitly instantiate here.
-    MemberSpecializationInfo *MSInfo = Prev->getMemberSpecializationInfo();
-    TemplateSpecializationKind PrevTSK =
-        MSInfo ? MSInfo->getTemplateSpecializationKind()
-               : Prev->getTemplateSpecializationKind();
-    SourceLocation POI = MSInfo ? MSInfo->getPointOfInstantiation()
-                                : cast<VarTemplateSpecializationDecl>(Prev)
-                                      ->getPointOfInstantiation();
+    TemplateSpecializationKind PrevTSK = Prev->getTemplateSpecializationKind();
+    SourceLocation POI = Prev->getPointOfInstantiation();
     bool HasNoEffect = false;
     if (CheckSpecializationInstantiationRedecl(D.getIdentifierLoc(), TSK, Prev,
                                                PrevTSK, POI, HasNoEffect))

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=191548&r1=191547&r2=191548&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Fri Sep 27 15:14:12 2013
@@ -2471,6 +2471,9 @@ Sema::InstantiateClassMembers(SourceLoca
         }
       }
     } else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) {
+      if (isa<VarTemplateSpecializationDecl>(Var))
+        continue;
+
       if (Var->isStaticDataMember()) {
         MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
         assert(MSInfo && "No member specialization information?");

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=191548&r1=191547&r2=191548&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Fri Sep 27 15:14:12 2013
@@ -318,7 +318,6 @@ TemplateDeclInstantiator::VisitTypeAlias
   return Inst;
 }
 
-// FIXME: Revise for static member templates.
 Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
   return VisitVarDecl(D, /*InstantiatingVarTemplate=*/false);
 }
@@ -2338,7 +2337,7 @@ Decl *TemplateDeclInstantiator::VisitVar
 Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
     VarTemplateDecl *VarTemplate, VarDecl *D, void *InsertPos,
     const TemplateArgumentListInfo &TemplateArgsInfo,
-    SmallVectorImpl<TemplateArgument> &Converted) {
+    llvm::ArrayRef<TemplateArgument> Converted) {
 
   // If this is the variable for an anonymous struct or union,
   // instantiate the anonymous struct/union type first.
@@ -2366,7 +2365,8 @@ Decl *TemplateDeclInstantiator::VisitVar
       VarTemplate, DI->getType(), DI, D->getStorageClass(), Converted.data(),
       Converted.size());
   Var->setTemplateArgsInfo(TemplateArgsInfo);
-  VarTemplate->AddSpecialization(Var, InsertPos);
+  if (InsertPos)
+    VarTemplate->AddSpecialization(Var, InsertPos);
 
   // Substitute the nested name specifier, if any.
   if (SubstQualifier(D, Var))
@@ -2691,12 +2691,8 @@ TemplateDeclInstantiator::InstantiateVar
   // 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, Owner, StartingScope);
-  InstPartialSpec->setInit(PartialSpec->getInit());
 
   return InstPartialSpec;
 }
@@ -3309,8 +3305,15 @@ VarTemplateSpecializationDecl *Sema::Bui
   MultiLevelTemplateArgumentList TemplateArgLists;
   TemplateArgLists.addOuterTemplateArguments(&TemplateArgList);
 
+  // Instantiate the first declaration of the variable template: for a partial
+  // specialization of a static data member template, the first declaration may
+  // or may not be the declaration in the class; if it's in the class, we want
+  // to instantiate a member in the class (a declaration), and if it's outside,
+  // we want to instantiate a definition.
+  FromVar = FromVar->getFirstDeclaration();
+
   TemplateDeclInstantiator Instantiator(
-      *this, VarTemplate->getDeclContext(),
+      *this, FromVar->getDeclContext(),
       MultiLevelTemplateArgumentList(TemplateArgList));
 
   // TODO: Set LateAttrs and StartingScope ...
@@ -3327,10 +3330,8 @@ 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(), Innermost,
+      SubstType(PatternDecl->getTypeSourceInfo(), TemplateArgs,
                 PatternDecl->getTypeSpecStartLoc(), PatternDecl->getDeclName());
   if (!DI)
     return 0;
@@ -3429,14 +3430,9 @@ void Sema::BuildVariableInstantiation(
     NewVar->setInstantiationOfStaticDataMember(OldVar,
                                                TSK_ImplicitInstantiation);
 
-  if (isa<VarTemplateSpecializationDecl>(NewVar)) {
-    // Do not instantiate the variable just yet.
-  } else if (InstantiatingVarTemplate) {
-    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
+  // Delay instantiation of the initializer for variable templates until a
+  // definition of the variable is needed.
+  if (!isa<VarTemplateSpecializationDecl>(NewVar) && !InstantiatingVarTemplate)
     InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs);
 
   // Diagnose unused local variables with dependent types, where the diagnostic
@@ -3513,19 +3509,18 @@ void Sema::InstantiateStaticDataMemberDe
 void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
                                          VarDecl *Var, bool Recursive,
                                          bool DefinitionRequired) {
-
   if (Var->isInvalidDecl())
     return;
 
   VarTemplateSpecializationDecl *VarSpec =
       dyn_cast<VarTemplateSpecializationDecl>(Var);
-  assert((VarSpec || Var->isStaticDataMember()) &&
-         "Not a static data member, nor a variable template specialization?");
-  VarDecl *PatternDecl = 0;
+  VarDecl *PatternDecl = 0, *Def = 0;
+  MultiLevelTemplateArgumentList TemplateArgs =
+      getTemplateInstantiationArgs(Var);
 
-  // If this is a variable template specialization, make sure that it is
-  // non-dependent, then find its instantiation pattern.
   if (VarSpec) {
+    // If this is a variable template specialization, make sure that it is
+    // non-dependent, then find its instantiation pattern.
     bool InstantiationDependent = false;
     assert(!TemplateSpecializationType::anyDependentTemplateArguments(
                VarSpec->getTemplateArgsInfo(), InstantiationDependent) &&
@@ -3533,59 +3528,123 @@ void Sema::InstantiateVariableDefinition
            "not type-dependent");
     (void)InstantiationDependent;
 
-    // Find the variable initialization that we'll be substituting.
+    // Find the variable initialization that we'll be substituting. If the
+    // pattern was instantiated from a member template, look back further to
+    // find the real pattern.
     assert(VarSpec->getSpecializedTemplate() &&
            "Specialization without specialized template?");
     llvm::PointerUnion<VarTemplateDecl *,
                        VarTemplatePartialSpecializationDecl *> PatternPtr =
         VarSpec->getSpecializedTemplateOrPartial();
     if (PatternPtr.is<VarTemplatePartialSpecializationDecl *>()) {
-      PatternDecl = cast<VarDecl>(
-          PatternPtr.get<VarTemplatePartialSpecializationDecl *>());
+      VarTemplatePartialSpecializationDecl *Tmpl =
+          PatternPtr.get<VarTemplatePartialSpecializationDecl *>();
+      while (VarTemplatePartialSpecializationDecl *From =
+                 Tmpl->getInstantiatedFromMember()) {
+        if (Tmpl->isMemberSpecialization())
+          break;
 
-      // Find actual definition
-      if (VarDecl *Def = PatternDecl->getDefinition(getASTContext()))
-        PatternDecl = Def;
+        Tmpl = From;
+      }
+      PatternDecl = Tmpl;
     } else {
-      VarTemplateDecl *PatternTemplate = PatternPtr.get<VarTemplateDecl *>();
+      VarTemplateDecl *Tmpl = PatternPtr.get<VarTemplateDecl *>();
+      while (VarTemplateDecl *From =
+                 Tmpl->getInstantiatedFromMemberTemplate()) {
+        if (Tmpl->isMemberSpecialization())
+          break;
+
+        Tmpl = From;
+      }
+      PatternDecl = Tmpl->getTemplatedDecl();
+    }
+
+    // If this is a static data member template, there might be an
+    // uninstantiated initializer on the declaration. If so, instantiate
+    // it now.
+    if (PatternDecl->isStaticDataMember() &&
+        (PatternDecl = PatternDecl->getFirstDeclaration())->hasInit() &&
+        !Var->hasInit()) {
+      // FIXME: Factor out the duplicated instantiation context setup/tear down
+      // code here.
+      InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
+      if (Inst)
+        return;
+
+      // If we're performing recursive template instantiation, create our own
+      // queue of pending implicit instantiations that we will instantiate
+      // later, while we're still within our own instantiation context.
+      SmallVector<VTableUse, 16> SavedVTableUses;
+      std::deque<PendingImplicitInstantiation> SavedPendingInstantiations;
+      if (Recursive) {
+        VTableUses.swap(SavedVTableUses);
+        PendingInstantiations.swap(SavedPendingInstantiations);
+      }
 
-      // Find actual definition
-      if (VarTemplateDecl *Def = PatternTemplate->getDefinition())
-        PatternTemplate = Def;
+      LocalInstantiationScope Local(*this);
 
-      PatternDecl = PatternTemplate->getTemplatedDecl();
+      // Enter the scope of this instantiation. We don't use
+      // PushDeclContext because we don't have a scope.
+      ContextRAII PreviousContext(*this, Var->getDeclContext());
+      InstantiateVariableInitializer(Var, PatternDecl, TemplateArgs);
+      PreviousContext.pop();
+
+      // FIXME: Need to inform the ASTConsumer that we instantiated the
+      // initializer?
+
+      // This variable may have local implicit instantiations that need to be
+      // instantiated within this scope.
+      PerformPendingInstantiations(/*LocalOnly=*/true);
+
+      Local.Exit();
+
+      if (Recursive) {
+        // Define any newly required vtables.
+        DefineUsedVTables();
+
+        // Instantiate any pending implicit instantiations found during the
+        // instantiation of this template.
+        PerformPendingInstantiations();
+
+        // Restore the set of pending vtables.
+        assert(VTableUses.empty() &&
+               "VTableUses should be empty before it is discarded.");
+        VTableUses.swap(SavedVTableUses);
+
+        // Restore the set of pending implicit instantiations.
+        assert(PendingInstantiations.empty() &&
+               "PendingInstantiations should be empty before it is discarded.");
+        PendingInstantiations.swap(SavedPendingInstantiations);
+      }
     }
-    assert(PatternDecl && "instantiating a non-template");
-  }
 
-  // If this is a static data member, find its out-of-line definition.
-  VarDecl *Def = Var->getInstantiatedFromStaticDataMember();
-  if (Var->isStaticDataMember()) {
-    assert(Def && "This data member was not instantiated from a template?");
-    assert(Def->isStaticDataMember() && "Not a static data member?");
-    Def = Def->getOutOfLineDefinition();
+    // Find actual definition
+    Def = PatternDecl->getDefinition(getASTContext());
+  } else {
+    // If this is a static data member, find its out-of-line definition.
+    assert(Var->isStaticDataMember() && "not a static data member?");
+    PatternDecl = Var->getInstantiatedFromStaticDataMember();
+
+    assert(PatternDecl && "data member was not instantiated from a template?");
+    assert(PatternDecl->isStaticDataMember() && "not a static data member?");
+    Def = PatternDecl->getOutOfLineDefinition();
   }
 
-  // If the instantiation pattern does not have an initializer, or if an
-  // out-of-line definition is not found, we won't perform any instantiation.
-  // Rather, we rely on the user to instantiate this definition (or provide
-  // a specialization for it) in another translation unit.
-  if ((VarSpec && !PatternDecl->getInit()) ||
-      (!VarSpec && Var->isStaticDataMember() && !Def)) {
+  // If we don't have a definition of the variable template, we won't perform
+  // any instantiation. Rather, we rely on the user to instantiate this
+  // definition (or provide a specialization for it) in another translation
+  // unit.
+  if (!Def) {
     if (DefinitionRequired) {
-      if (!Var->isStaticDataMember()) {
+      if (VarSpec)
         Diag(PointOfInstantiation,
-             diag::err_explicit_instantiation_undefined_var_template)
-            << PatternDecl;
-        Diag(PatternDecl->getLocation(),
-             diag::note_explicit_instantiation_here);
-      } else {
-        Def = Var->getInstantiatedFromStaticDataMember();
+             diag::err_explicit_instantiation_undefined_var_template) << Var;
+      else
         Diag(PointOfInstantiation,
              diag::err_explicit_instantiation_undefined_member)
-            << 3 << Var->getDeclName() << Var->getDeclContext();
-        Diag(Def->getLocation(), diag::note_explicit_instantiation_here);
-      }
+            << 2 << Var->getDeclName() << Var->getDeclContext();
+      Diag(PatternDecl->getLocation(),
+           diag::note_explicit_instantiation_here);
       if (VarSpec)
         Var->setInvalidDecl();
     } else if (Var->getTemplateSpecializationKind()
@@ -3603,11 +3662,6 @@ void Sema::InstantiateVariableDefinition
   if (TSK == 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.
-  //
   // C++11 [temp.explicit]p10:
   //   Except for inline functions, [...] explicit instantiation declarations
   //   have the effect of suppressing the implicit instantiation of the entity
@@ -3624,24 +3678,17 @@ void Sema::InstantiateVariableDefinition
       : Consumer(Consumer), Var(Var) { }
 
     ~PassToConsumerRAII() {
-      if (Var->isStaticDataMember())
-        Consumer.HandleCXXStaticMemberVarInstantiation(Var);
-      else {
-        DeclGroupRef DG(Var);
-        Consumer.HandleTopLevelDecl(DG);
-      }
+      Consumer.HandleCXXStaticMemberVarInstantiation(Var);
     }
   } PassToConsumerRAII(Consumer, Var);
 
-  if (!VarSpec) {
-    // If we already have a definition, we're done.
-    if (VarDecl *Def = Var->getDefinition()) {
-      // We may be explicitly instantiating something we've already implicitly
-      // instantiated.
-      Def->setTemplateSpecializationKind(Var->getTemplateSpecializationKind(),
-                                         PointOfInstantiation);
-      return;
-    }
+  // If we already have a definition, we're done.
+  if (VarDecl *Def = Var->getDefinition()) {
+    // We may be explicitly instantiating something we've already implicitly
+    // instantiated.
+    Def->setTemplateSpecializationKind(Var->getTemplateSpecializationKind(),
+                                       PointOfInstantiation);
+    return;
   }
 
   InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
@@ -3666,29 +3713,46 @@ void Sema::InstantiateVariableDefinition
   VarDecl *OldVar = Var;
   if (!VarSpec)
     Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(),
-                                          getTemplateInstantiationArgs(Var)));
-  else
-    // Construct a VarTemplateSpecializationDecl to avoid name clashing with
-    // the primary template. (Note that unlike function declarations, variable
-    // declarations cannot be overloaded.)
-    // In fact, there is no need to construct a new declaration from scratch.
-    // Thus, simply complete its definition with an appropriately substituted
-    // type and initializer.
-    Var = CompleteVarTemplateSpecializationDecl(
-        VarSpec, PatternDecl, getTemplateInstantiationArgs(Var));
+                                          TemplateArgs));
+  else if (Var->isStaticDataMember() &&
+           Var->getLexicalDeclContext()->isRecord()) {
+    // We need to instantiate the definition of a static data member template,
+    // and all we have is the in-class declaration of it. Instantiate a separate
+    // declaration of the definition.
+    TemplateDeclInstantiator Instantiator(*this, Var->getDeclContext(),
+                                          TemplateArgs);
+    Var = cast_or_null<VarDecl>(Instantiator.VisitVarTemplateSpecializationDecl(
+        VarSpec->getSpecializedTemplate(), Def, 0,
+        VarSpec->getTemplateArgsInfo(), VarSpec->getTemplateArgs().asArray()));
+    if (Var) {
+      llvm::PointerUnion<VarTemplateDecl *,
+                         VarTemplatePartialSpecializationDecl *> PatternPtr =
+          VarSpec->getSpecializedTemplateOrPartial();
+      if (VarTemplatePartialSpecializationDecl *Partial =
+          PatternPtr.dyn_cast<VarTemplatePartialSpecializationDecl *>())
+        cast<VarTemplateSpecializationDecl>(Var)->setInstantiationOf(
+            Partial, &VarSpec->getTemplateInstantiationArgs());
+
+      // Merge the definition with the declaration.
+      LookupResult R(*this, Var->getDeclName(), Var->getLocation(),
+                     LookupOrdinaryName, ForRedeclaration);
+      R.addDecl(OldVar);
+      MergeVarDecl(Var, R);
+
+      // Attach the initializer.
+      InstantiateVariableInitializer(Var, Def, TemplateArgs);
+    }
+  } else
+    // Complete the existing variable's definition with an appropriately
+    // substituted type and initializer.
+    Var = CompleteVarTemplateSpecializationDecl(VarSpec, Def, TemplateArgs);
 
   PreviousContext.pop();
 
   if (Var) {
-    MemberSpecializationInfo *MSInfo = OldVar->getMemberSpecializationInfo();
-    if (!VarSpec)
-      assert(MSInfo && "Missing member specialization information?");
-
     PassToConsumerRAII.Var = Var;
-    if (MSInfo)
-      Var->setTemplateSpecializationKind(
-          MSInfo->getTemplateSpecializationKind(),
-          MSInfo->getPointOfInstantiation());
+    Var->setTemplateSpecializationKind(OldVar->getTemplateSpecializationKind(),
+                                       OldVar->getPointOfInstantiation());
   }
 
   // This variable may have local implicit instantiations that need to be

Added: cfe/trunk/test/CodeGenCXX/cxx1y-variable-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx1y-variable-template.cpp?rev=191548&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/cxx1y-variable-template.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/cxx1y-variable-template.cpp Fri Sep 27 15:14:12 2013
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -std=c++1y -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+// Check that we keep the 'extern' when we instantiate the definition of this
+// variable template specialization.
+template<typename T> extern const int extern_redecl;
+template<typename T> const int extern_redecl = 5;
+template const int extern_redecl<int>;
+
+// CHECK: @_Z13extern_redeclIiE = weak_odr constant
+
+template<typename T> struct Outer {
+  template<typename U> struct Inner {
+    template<typename V> static int arr[];
+  };
+};
+Outer<char[100]> outer_int;
+int init_arr();
+template<typename T> template<typename U> template<typename V> int Outer<T>::Inner<U>::arr[sizeof(T) + sizeof(U) + sizeof(V)] = { init_arr() };
+int *p = Outer<char[100]>::Inner<char[20]>::arr<char[3]>;
+
+// CHECK: @_ZN5OuterIA100_cE5InnerIA20_cE3arrIA3_cEE = weak_odr global [123 x i32] zeroinitializer
+// CHECK: @_ZGVN5OuterIA100_cE5InnerIA20_cE3arrIA3_cEE = weak_odr global
+
+// CHECK: call {{.*}}@_Z8init_arrv

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=191548&r1=191547&r2=191548&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp Fri Sep 27 15:14:12 2013
@@ -53,59 +53,84 @@ namespace out_of_line {
   template<typename T> CONST T B3::right<T,int>;
 
   class B4 {
-    template<typename T, typename T0> static CONST T right;
-    template<typename T> static CONST T right<T,int>;
-    template<typename T, typename T0> static CONST T right_def = T(100);
-    template<typename T> static CONST T right_def<T,int>;   // expected-note {{explicit instantiation refers here}}
-  };
-  template<typename T, typename T0> CONST T B4::right;
-  template<typename T> CONST T B4::right<T,int>; // expected-note {{explicit instantiation refers here}}
-  template CONST int B4::right<int,int>;  // expected-error {{explicit instantiation of undefined static data member template 'right' of class}}
-  template CONST int B4::right_def<int,int>;  // expected-error {{explicit instantiation of undefined static data member template 'right_def' of class}}
+    template<typename T, typename T0> static CONST T a;
+    template<typename T> static CONST T a<T,int> = T(100);
+    template<typename T, typename T0> static CONST T b = T(100);
+    template<typename T> static CONST T b<T,int>;
+  };
+  template<typename T, typename T0> CONST T B4::a; // expected-error {{default initialization of an object of const type 'const int'}}
+  template<typename T> CONST T B4::a<T,int>;
+  template CONST int B4::a<int,char>; // expected-note {{in instantiation of}}
+  template CONST int B4::a<int,int>;
+
+  template<typename T, typename T0> CONST T B4::b;
+  template<typename T> CONST T B4::b<T,int>; // expected-error {{default initialization of an object of const type 'const int'}}
+  template CONST int B4::b<int,char>;
+  template CONST int B4::b<int,int>; // expected-note {{in instantiation of}}
 }
 
 namespace non_const_init {
   class A {
-    template<typename T> static T wrong_inst = T(10); // expected-error {{non-const static data member must be initialized out of line}}
-    template<typename T> static T wrong_inst_fixed;
+    template<typename T> static T wrong_inst_undefined = T(10); // expected-note {{refers here}}
+    template<typename T> static T wrong_inst_defined = T(10); // expected-error {{non-const static data member must be initialized out of line}}
+    template<typename T> static T wrong_inst_out_of_line;
   };
-  template int A::wrong_inst<int>;  // expected-note {{in instantiation of static data member 'non_const_init::A::wrong_inst<int>' requested here}}
-  template<typename T> T A::wrong_inst_fixed = T(10);
-  template int A::wrong_inst_fixed<int>;
-  
+
+  template const int A::wrong_inst_undefined<const int>; // expected-error {{undefined}}
+
+  template<typename T> T A::wrong_inst_defined;
+  template const int A::wrong_inst_defined<const int>;
+  template int A::wrong_inst_defined<int>; // expected-note {{in instantiation of static data member 'non_const_init::A::wrong_inst_defined<int>' requested here}}
+
+  template<typename T> T A::wrong_inst_out_of_line = T(10);
+  template int A::wrong_inst_out_of_line<int>;
+
   class B {
-    template<typename T> static T wrong_inst;
-    template<typename T> static T wrong_inst<T*> = T(100);  // expected-error {{non-const static data member must be initialized out of line}}
-    
+    template<typename T> static T wrong_inst; // expected-note {{refers here}}
+    template<typename T> static T wrong_inst<T*> = T(100); // expected-error {{non-const static data member must be initialized out of line}} expected-note {{refers here}}
+
     template<typename T> static T wrong_inst_fixed;
     template<typename T> static T wrong_inst_fixed<T*>;
   };
-  template int B::wrong_inst<int*>;  // expected-note {{in instantiation of static data member 'non_const_init::B::wrong_inst<int *>' requested here}}
+  template int B::wrong_inst<int>; // expected-error {{undefined}}
+  // FIXME: It'd be better to produce the 'explicit instantiation of undefined
+  // template' diagnostic here, not the 'must be initialized out of line'
+  // diagnostic.
+  template int B::wrong_inst<int*>; // expected-note {{in instantiation of static data member 'non_const_init::B::wrong_inst<int *>' requested here}}
+  template const int B::wrong_inst<const int*>; // expected-error {{undefined}}
   template<typename T> T B::wrong_inst_fixed = T(100);
   template int B::wrong_inst_fixed<int>;
-  
+
   class C {
-    template<typename T> static CONST T right_inst = T(10);
-    template<typename T> static CONST T right_inst<T*> = T(100);
+    template<typename T> static CONST T right_inst = T(10); // expected-note {{here}}
+    template<typename T> static CONST T right_inst<T*> = T(100); // expected-note {{here}}
   };
-  template CONST int C::right_inst<int>;
-  template CONST int C::right_inst<int*>;
-  
+  template CONST int C::right_inst<int>; // expected-error {{undefined variable template}}
+  template CONST int C::right_inst<int*>; // expected-error {{undefined variable template}}
+
   namespace pointers {
-    
+
     struct C0 {
       template<typename U> static U Data;
-      template<typename U> static CONST U Data<U*> = U();   // Okay
+      template<typename U> static CONST U Data<U*> = U(); // expected-note {{here}}
+
+      template<typename U> static U Data2;
+      template<typename U> static CONST U Data2<U*> = U();
     };
-    template CONST int C0::Data<int*>;
-    
+    const int c0_test = C0::Data<int*>;
+    static_assert(c0_test == 0, "");
+    template const int C0::Data<int*>; // expected-error {{undefined}}
+
+    template<typename U> const U C0::Data2<U*>;
+    template const int C0::Data2<int*>;
+
     struct C1a {
       template<typename U> static U Data;
       template<typename U> static U* Data<U*>;   // Okay, with out-of-line definition
     };
     template<typename T> T* C1a::Data<T*> = new T();
     template int* C1a::Data<int*>;
-    
+
     struct C1b {
       template<typename U> static U Data;
       template<typename U> static CONST U* Data<U*>;   // Okay, with out-of-line definition
@@ -118,12 +143,13 @@ namespace non_const_init {
       template<typename U> static U* Data<U*> = new U();   // expected-error {{non-const static data member must be initialized out of line}}
     };
     template int* C2a::Data<int*>; // expected-note {{in instantiation of static data member 'non_const_init::pointers::C2a::Data<int *>' requested here}}
-    
-    struct C2b {  // FIXME: ?!? Should this be an error? pointer-types are automatically non-const?
+
+    struct C2b {
       template<typename U> static int Data;
-      template<typename U> static CONST U* Data<U*> = (U*)(0); // expected-error {{non-const static data member must be initialized out of line}}
+      template<typename U> static U *const Data<U*> = (U*)(0); // expected-error {{static data member of type 'int *const'}}
     };
-    template CONST int* C2b::Data<int*>; // expected-note {{in instantiation of static data member 'non_const_init::pointers::C2b::Data<int *>' requested here}}
+    template<typename U> U *const C2b::Data<U*>;
+    template int *const C2b::Data<int*>; // expected-note {{in instantiation of static data member 'non_const_init::pointers::C2b::Data<int *>' requested here}}
   }
 }
 
@@ -146,18 +172,16 @@ namespace constexpred {
 }
 #endif
 
-struct matrix_constants {
-  // TODO: (?)
-};
-
 namespace in_class_template {
 
   template<typename T>
   class D0 {
-    template<typename U> static U Data;
+    template<typename U> static U Data; // expected-note {{here}}
     template<typename U> static CONST U Data<U*> = U();
   };
   template CONST int D0<float>::Data<int*>;
+  template int D0<float>::Data<int>; // expected-error {{undefined}}
+  template<typename T> template<typename U> const U D0<T>::Data<U*>;
 
   template<typename T>
   class D1 {
@@ -166,7 +190,8 @@ namespace in_class_template {
   };
   template<typename T>
   template<typename U> U* D1<T>::Data<U*> = (U*)(0);
-  template int* D1<float>::Data<int*>;
+  template int* D1<float>::Data<int*>; // expected-note {{previous}}
+  template int* D1<float>::Data<int*>; // expected-error {{duplicate explicit instantiation}}
 
   template<typename T>
   class D2 {
@@ -175,53 +200,69 @@ namespace in_class_template {
   };
   template<>
   template<typename U> U* D2<float>::Data<U*> = (U*)(0) + 1;
-  template int* D1<float>::Data<int*>;
+  template int* D2<float>::Data<int*>; // expected-note {{previous}}
+  template int* D2<float>::Data<int*>; // expected-error {{duplicate explicit instantiation}}
 
   template<typename T>
   struct D3 {
-    template<typename U> static CONST U Data = U(100);
+    template<typename U> static CONST U Data = U(100); // expected-note {{here}}
   };
-  template CONST int D3<float>::Data<int>;
   static_assert(D3<float>::Data<int> == 100, "");
+  template const char D3<float>::Data<char>; // expected-error {{undefined}}
 
   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 {
+    class D0a {
       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 U> U D0a<float>::Data<U*> = U(100);  // expected-error {{redefinition of 'Data'}}
 
+    // FIXME: We should accept this, and the corresponding case for class
+    // templates.
+    //
+    // [temp.class.spec.mfunc]/2: If the primary member template is explicitly
+    // specialized for a given specialization of the enclosing class template,
+    // the partial specializations of the member template are ignored
     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<typename U> static CONST U Data<U*> = U(10);  // expected-note {{previous definition is here}}
+    };
+    template<>
+    template<typename U> U D1<float>::Data = U(10);
     template<>
-    template<typename U> U* D1<float>::Data<U*> = (U*)(0) + 1;  // expected-error{{redefinition of 'Data'}}
+    template<typename U> U D1<float>::Data<U*> = U(100);  // expected-error{{redefinition of 'Data'}}
   }
-  
-  namespace other_bugs {
-    // FIXME: This fails to properly initialize the variables 'k1' and 'k2'.
-
-    template<typename A> struct S { 
-      template<typename B> static int V0;
-      template<typename B> static int V1;
+
+  namespace definition_after_outer_instantiation {
+    template<typename A> struct S {
+      template<typename B> static const int V1;
+      template<typename B> static const int V2;
     };
     template struct S<int>;
-    template<typename A> template<typename B> int S<A>::V0 = 123;
-    template<typename A> template<typename B> int S<A>::V1<B*> = 123;
-    int k1 = S<int>::V0<void>;
-    int k2 = S<int>::V1<void*>;
+    template<typename A> template<typename B> const int S<A>::V1 = 123;
+    template<typename A> template<typename B> const int S<A>::V2<B*> = 456;
+
+    static_assert(S<int>::V1<int> == 123, "");
+
+    // FIXME: The first and third case below possibly should be accepted. We're
+    // not picking up partial specializations added after the primary template
+    // is instantiated. This is kind of implied by [temp.class.spec.mfunc]/2,
+    // and matches our behavior for member class templates, but it's not clear
+    // that this is intentional. See PR17294 and core-24030.
+    static_assert(S<int>::V2<int*> == 456, ""); // FIXME expected-error {{}}
+    static_assert(S<int>::V2<int&> == 789, ""); // expected-error {{}}
+
+    template<typename A> template<typename B> const int S<A>::V2<B&> = 789;
+    static_assert(S<int>::V2<int&> == 789, ""); // FIXME expected-error {{}}
+
+    // All is OK if the partial specialization is declared before the implicit
+    // instantiation of the class template specialization.
+    static_assert(S<char>::V1<int> == 123, "");
+    static_assert(S<char>::V2<int*> == 456, "");
+    static_assert(S<char>::V2<int&> == 789, "");
   }
 
   namespace incomplete_array {
@@ -243,13 +284,12 @@ namespace in_class_template {
       template<typename...U> static T y<tuple<U...> >[];
     };
 
-    // FIXME: These cases should be accepted.
     int *use_before_definition = A<int>::x<char>;
     template<typename T> template<typename U> T A<T>::x[sizeof(U)];
-    static_assert(sizeof(A<int>::x<char>) == 1, ""); // expected-error {{incomplete}}
+    static_assert(sizeof(A<int>::x<char>) == 4, "");
 
     template<typename T> template<typename...U> T A<T>::y<tuple<U...> >[] = { U()... };
-    static_assert(sizeof(A<int>::y<tuple<char, char, char> >) == 12, ""); // expected-error {{incomplete}}
+    static_assert(sizeof(A<int>::y<tuple<char, char, char> >) == 12, "");
   }
 }
 

Modified: cfe/trunk/test/SemaTemplate/explicit-instantiation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/explicit-instantiation.cpp?rev=191548&r1=191547&r2=191548&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/explicit-instantiation.cpp (original)
+++ cfe/trunk/test/SemaTemplate/explicit-instantiation.cpp Fri Sep 27 15:14:12 2013
@@ -119,3 +119,33 @@ namespace PR10086 {
     foobar(5);
   }
 }
+
+namespace undefined_static_data_member {
+  template<typename T> struct A {
+    static int a; // expected-note {{here}}
+    template<typename U> static int b; // expected-note {{here}} expected-warning {{extension}}
+  };
+  struct B {
+    template<typename U> static int c; // expected-note {{here}} expected-warning {{extension}}
+  };
+
+  template int A<int>::a; // expected-error {{explicit instantiation of undefined static data member 'a' of class template 'undefined_static_data_member::A<int>'}}
+  template int A<int>::b<int>; // expected-error {{explicit instantiation of undefined variable template 'undefined_static_data_member::A<int>::b<int>'}}
+  template int B::c<int>; // expected-error {{explicit instantiation of undefined variable template 'undefined_static_data_member::B::c<int>'}}
+
+
+  template<typename T> struct C {
+    static int a;
+    template<typename U> static int b; // expected-warning {{extension}}
+  };
+  struct D {
+    template<typename U> static int c; // expected-warning {{extension}}
+  };
+  template<typename T> int C<T>::a;
+  template<typename T> template<typename U> int C<T>::b; // expected-warning {{extension}}
+  template<typename U> int D::c; // expected-warning {{extension}}
+
+  template int C<int>::a;
+  template int C<int>::b<int>;
+  template int D::c<int>;
+}





More information about the cfe-commits mailing list