Bug fix: disallow a variable template to be redeclared as a non-templated variable

llvm-svn: 188350
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index bc46aae..c583674 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2920,15 +2920,21 @@
 /// definitions here, since the initializer hasn't been attached.
 ///
 void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous,
-                        bool MergeTypeWithPrevious) {
+                        bool IsVariableTemplate, bool MergeTypeWithPrevious) {
   // If the new decl is already invalid, don't do any other checking.
   if (New->isInvalidDecl())
     return;
 
-  // Verify the old decl was also a variable.
+  // Verify the old decl was also a variable or variable template.
   VarDecl *Old = 0;
-  if (!Previous.isSingleResult() ||
-      !(Old = dyn_cast<VarDecl>(Previous.getFoundDecl()))) {
+  if (Previous.isSingleResult() &&
+      (Old = dyn_cast<VarDecl>(Previous.getFoundDecl()))) {
+    if (IsVariableTemplate)
+      Old = Old->getDescribedVarTemplate() ? Old : 0;
+    else
+      Old = Old->getDescribedVarTemplate() ? 0 : Old;
+  }
+  if (!Old) {
     Diag(New->getLocation(), diag::err_redefinition_different_kind)
       << New->getDeclName();
     Diag(Previous.getRepresentativeDecl()->getLocation(),
@@ -4919,6 +4925,7 @@
   bool IsExplicitSpecialization = false;
   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;
@@ -5019,6 +5026,7 @@
 
         } else { // if (TemplateParams->size() > 0)
           // This is a template declaration.
+          IsVariableTemplate = true;
 
           // Check that we can declare a template here.
           if (CheckTemplateDeclScope(S, TemplateParams))
@@ -5310,9 +5318,11 @@
         LookupResult PrevDecl(*this, GetNameForDeclarator(D),
                               LookupOrdinaryName, ForRedeclaration);
         PrevDecl.addDecl(PrevVarTemplate->getTemplatedDecl());
-        D.setRedeclaration(CheckVariableDeclaration(NewVD, PrevDecl));
+        D.setRedeclaration(
+            CheckVariableDeclaration(NewVD, PrevDecl, IsVariableTemplate));
       } else
-        D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
+        D.setRedeclaration(
+            CheckVariableDeclaration(NewVD, Previous, IsVariableTemplate));
     }
 
     // This is an explicit specialization of a static data member. Check it.
@@ -5340,8 +5350,8 @@
     }
   }
 
-  // If this is not a variable template, return it now
-  if (!TemplateParams || IsVariableTemplateSpecialization)
+  // 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.
@@ -5745,7 +5755,8 @@
 ///
 /// Returns true if the variable declaration is a redeclaration.
 bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
-                                    LookupResult &Previous) {
+                                    LookupResult &Previous,
+                                    bool IsVariableTemplate) {
   CheckVariableDeclarationType(NewVD);
 
   // If the decl is already known invalid, don't check it.
@@ -5795,7 +5806,7 @@
   filterNonConflictingPreviousDecls(Context, NewVD, Previous);
 
   if (!Previous.empty()) {
-    MergeVarDecl(NewVD, Previous, MergeTypeWithPrevious);
+    MergeVarDecl(NewVD, Previous, IsVariableTemplate, MergeTypeWithPrevious);
     return true;
   }
   return false;
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index bd2936b..c8298a9 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2280,32 +2280,6 @@
                                              bool IsPartialSpecialization);
 
 static TemplateSpecializationKind getTemplateSpecializationKind(Decl *D);
-/*
-// Check the new variable specialization against the parsed input.
-//
-// FIXME: Model this against function specializations where
-// a new function declaration is checked against the specialization
-// as candidate for redefinition... (?)
-static bool CheckVariableTemplateSpecializationType() {
-
-  if (ExpectedType is undeduced &&  ParsedType is not undeduced)
-    ExpectedType = dedudeType();
-
-  if (both types are undeduced)
-    ???;
-
-  bool CheckType = !ExpectedType()->
-
-  if (!Context.hasSameType(DI->getType(), ExpectedDI->getType())) {
-    unsigned ErrStr = IsPartialSpecialization ? 2 : 1;
-    Diag(D.getIdentifierLoc(), diag::err_invalid_var_template_spec_type)
-        << ErrStr << VarTemplate << DI->getType() << ExpectedDI->getType();
-    Diag(VarTemplate->getLocation(), diag::note_template_declared_here)
-        << 2 << VarTemplate->getDeclName();
-    return true;
-  }
-}
-*/
 
 DeclResult Sema::ActOnVarTemplateSpecialization(
     Scope *S, VarTemplateDecl *VarTemplate, Declarator &D, TypeSourceInfo *DI,
@@ -2359,13 +2333,6 @@
   if (!ExpectedDI)
     return true;
 
-  /*
-  // Check the new variable specialization against the parsed input.
-  // (Attributes are merged later below.)
-  if (CheckVariableTemplateSpecializationType())
-    return true;
-  */
-
   // Find the variable template (partial) specialization declaration that
   // corresponds to these arguments.
   if (IsPartialSpecialization) {
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index c7242aa..3379ebc 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3365,7 +3365,7 @@
              OldVar->hasLinkage())
     LookupQualifiedName(Previous, NewVar->getDeclContext(), false);
 
-  CheckVariableDeclaration(NewVar, Previous);
+  CheckVariableDeclaration(NewVar, Previous, ForVarTemplate);
 
   if (OldVar->isOutOfLine()) {
     OldVar->getLexicalDeclContext()->addDecl(NewVar);
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 1eef54b..7099d32 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -943,7 +943,7 @@
   VD->setCachedLinkage(Linkage(Record[Idx++]));
 
   // Only true variables (not parameters or implicit parameters) can be merged.
-  if (VD->getKind() == Decl::Var)
+  if (VD->getKind() != Decl::ParmVar && VD->getKind() != Decl::ImplicitParam)
     mergeRedeclarable(VD, Redecl);
   
   if (uint64_t Val = Record[Idx++]) {
@@ -955,11 +955,22 @@
     }
   }
 
-  if (Record[Idx++]) { // HasMemberSpecializationInfo.
+  enum VarKind {
+    VarNotTemplate = 0, VarTemplate, StaticDataMemberSpecialization
+  };
+  switch ((VarKind)Record[Idx++]) {
+  case VarNotTemplate:
+    break;
+  case VarTemplate:
+    VD->setDescribedVarTemplate(ReadDeclAs<VarTemplateDecl>(Record, Idx));
+    break;
+  case StaticDataMemberSpecialization: { // HasMemberSpecializationInfo.
     VarDecl *Tmpl = ReadDeclAs<VarDecl>(Record, Idx);
     TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
     SourceLocation POI = ReadSourceLocation(Record, Idx);
     Reader.getContext().setInstantiatedFromStaticDataMember(VD, Tmpl, TSK,POI);
+    break;
+  }
   }
 
   return Redecl;
@@ -1433,7 +1444,7 @@
   RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D);
 
   if (ThisDeclID == Redecl.getFirstID()) {
-    // This ClassTemplateDecl owns a CommonPtr; read it to keep track of all of
+    // This VarTemplateDecl owns a CommonPtr; read it to keep track of all of
     // the specializations.
     SmallVector<serialization::DeclID, 2> SpecIDs;
     SpecIDs.push_back(0);
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index c9f3a65..8072630 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -712,14 +712,21 @@
   } else {
     Record.push_back(0);
   }
-
-  MemberSpecializationInfo *SpecInfo
-    = D->isStaticDataMember() ? D->getMemberSpecializationInfo() : 0;
-  Record.push_back(SpecInfo != 0);
-  if (SpecInfo) {
+  
+  enum {
+    VarNotTemplate = 0, VarTemplate, StaticDataMemberSpecialization
+  };
+  if (VarTemplateDecl *TemplD = D->getDescribedVarTemplate()) {
+    Record.push_back(VarTemplate);
+    Writer.AddDeclRef(TemplD, Record);
+  } else if (MemberSpecializationInfo *SpecInfo
+               = D->getMemberSpecializationInfo()) {
+    Record.push_back(StaticDataMemberSpecialization);
     Writer.AddDeclRef(SpecInfo->getInstantiatedFrom(), Record);
     Record.push_back(SpecInfo->getTemplateSpecializationKind());
     Writer.AddSourceLocation(SpecInfo->getPointOfInstantiation(), Record);
+  } else {
+    Record.push_back(VarNotTemplate);
   }
 
   if (!D->hasAttrs() &&
@@ -739,7 +746,7 @@
       !isa<VarTemplateSpecializationDecl>(D) &&
       !D->isConstexpr() &&
       !D->isPreviousDeclInSameBlockScope() &&
-      !SpecInfo)
+      !D->getMemberSpecializationInfo())
     AbbrevToUse = Writer.getDeclVarAbbrev();
 
   Code = serialization::DECL_VAR;