Bug fix: disallow a variable template to be redeclared as a non-templated variable
authorLarisse Voufo <lvoufo@google.com>
Wed, 14 Aug 2013 03:09:19 +0000 (03:09 +0000)
committerLarisse Voufo <lvoufo@google.com>
Wed, 14 Aug 2013 03:09:19 +0000 (03:09 +0000)
llvm-svn: 188350

clang/include/clang/Sema/Sema.h
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaTemplate.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/lib/Serialization/ASTReaderDecl.cpp
clang/lib/Serialization/ASTWriterDecl.cpp
clang/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp
clang/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp
clang/test/PCH/cxx1y-variable-templates.cpp
clang/test/SemaCXX/cxx1y-variable-templates_top_level.cpp

index f2c78e981e6b54b35235d7d375ea2f29e7d1af50..e66c388b6bb4d885e956ac248a141d699ef66950 100644 (file)
@@ -1472,7 +1472,8 @@ public:
                                      MultiTemplateParamsArg TemplateParamLists,
                                      bool &AddToScope);
   // Returns true if the variable declaration is a redeclaration
-  bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous);
+  bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous,
+                                bool IsVariableTemplate = false);
   void CheckVariableDeclarationType(VarDecl *NewVD);
   void CheckCompleteVariableDeclaration(VarDecl *var);
   void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D);
@@ -1868,9 +1869,8 @@ public:
                                     Scope *S, bool MergeTypeWithOld);
   void mergeObjCMethodDecls(ObjCMethodDecl *New, ObjCMethodDecl *Old);
   void MergeVarDecl(VarDecl *New, LookupResult &Previous,
-                    bool MergeTypeWithPrevious);
-  void MergeVarDeclTypes(VarDecl *New, VarDecl *Old,
-                         bool MergeTypeWithOld);
+                    bool IsVariableTemplate, 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 bc46aae0a6b3e6410089a5451bab2d6b31b906d6..c58367462214b2b76374e217786d12bb4fd5f2df 100644 (file)
@@ -2920,15 +2920,21 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old,
 /// 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 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
   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 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
 
         } 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 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
         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 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
     }
   }
 
-  // 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 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
 ///
 /// 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 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
   filterNonConflictingPreviousDecls(Context, NewVD, Previous);
 
   if (!Previous.empty()) {
-    MergeVarDecl(NewVD, Previous, MergeTypeWithPrevious);
+    MergeVarDecl(NewVD, Previous, IsVariableTemplate, MergeTypeWithPrevious);
     return true;
   }
   return false;
index bd2936b6141278c37b22dc1fadbfb105a1783203..c8298a93bae8b84ab557f76e1ed55dea7ac2bf3e 100644 (file)
@@ -2280,32 +2280,6 @@ static bool CheckTemplateSpecializationScope(Sema &S, NamedDecl *Specialized,
                                              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 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
   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) {
index c7242aa5f9939ada2e2bdfa906dd53256827b748..3379ebcd900d63980a6865468904ad81ca92b925 100644 (file)
@@ -3365,7 +3365,7 @@ void Sema::BuildVariableInstantiation(
              OldVar->hasLinkage())
     LookupQualifiedName(Previous, NewVar->getDeclContext(), false);
 
-  CheckVariableDeclaration(NewVar, Previous);
+  CheckVariableDeclaration(NewVar, Previous, ForVarTemplate);
 
   if (OldVar->isOutOfLine()) {
     OldVar->getLexicalDeclContext()->addDecl(NewVar);
index 1eef54b14210144545e56f35fd51ffac751c86dd..7099d32b3d5464e57848dfc9967364d9fb707aab 100644 (file)
@@ -943,7 +943,7 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
   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 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
     }
   }
 
-  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 @@ void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) {
   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);
index c9f3a6541f88ecc1221cfe0091794e64d92a22b4..80726309417d902ef13e5b47f5ee5d9095e6d838 100644 (file)
@@ -712,14 +712,21 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
   } 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 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
       !isa<VarTemplateSpecializationDecl>(D) &&
       !D->isConstexpr() &&
       !D->isPreviousDeclInSameBlockScope() &&
-      !SpecInfo)
+      !D->getMemberSpecializationInfo())
     AbbrevToUse = Writer.getDeclVarAbbrev();
 
   Code = serialization::DECL_VAR;
index 4cff1e2e9df8f1ea5b13d3033f0f42b596de9837..edaae9f49d0517ae21f26e2023da60b61cc45081 100644 (file)
@@ -20,7 +20,7 @@ template<typename T>
 T pi0 = T(3.1415926535897932385); // expected-note {{previous definition is here}}
 
 template int pi0 = 10; // expected-error {{variable cannot be defined in an explicit instantiation; if this declaration is meant to be a variable definition, remove the 'template' keyword}} \
-                          expected-error{{redefinition of 'pi0' with a different type: 'int' vs 'T'}}
+                          expected-error{{redefinition of 'pi0' as different kind of symbol}}
 #endif
 
 template<typename T> 
index 3844ec99458ede27465ae1de5d8bf33d00612a25..d12feeff0bbca74307fb8bea356399f30d168a7c 100644 (file)
@@ -163,8 +163,7 @@ namespace PR9877 {
   template<> struct X<1>::Y { static const int Z = 1; };
 
   const int X<0>::Y::Z;
-  template<> const int X<1>::Y::Z;  // expected-error{{extraneous 'template<>' in declaration of variable 'Z'}} \
-                                    // expected-error{{forward declaration of variable template cannot have a nested name specifier}}
+  template<> const int X<1>::Y::Z;  // expected-error{{extraneous 'template<>' in declaration of variable 'Z'}}
 }
 
 namespace PR9913 {
index 8bc2129ebd59c6748e5aeb4db626d3f22a3f7a4f..0c600b29d39d7f549ae1c094b94286b4096b1d51 100644 (file)
@@ -168,5 +168,4 @@ namespace spec_join1 {
   int* intpb = vd<int>;
 }
 
-
 #endif
index dc721ce10fd44dca324cd3d2d1662a1cd70a28a2..82e3c116aad8c676b10904f40bd5ed425072ffde 100644 (file)
@@ -72,7 +72,7 @@ namespace odr_tmpl {
   }
   namespace pvt_cv {
     template<typename T> T v; // expected-note {{previous definition is here}}
-    int v;   // expected-error {{redefinition of 'v' with a different type: 'int' vs 'T'}}
+    int v;   // expected-error {{redefinition of 'v' as different kind of symbol}}
   }
   namespace pvt_cvt {
     template<typename T> T v0; // expected-note {{previous definition is here}}
@@ -107,6 +107,9 @@ namespace odr_tmpl {
 #ifdef CXX11
     template<typename T> extern auto v;   // expected-error {{declaration of variable 'v' with type 'auto' requires an initializer}}
 #endif
+
+    template<typename T> T var = T();     // expected-note {{previous definition is here}}
+    extern int var;                       // expected-error {{redefinition of 'var' as different kind of symbol}}
   }
 
 #ifdef CXX11