diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index f2c78e981e6b..e66c388b6bb4 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -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); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index bc46aae0a6b3..c58367462214 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -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(Previous.getFoundDecl()))) { + if (Previous.isSingleResult() && + (Old = dyn_cast(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; diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index bd2936b61412..c8298a93bae8 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -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) { diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index c7242aa5f993..3379ebcd900d 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -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); diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 1eef54b14210..7099d32b3d54 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -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(Record, Idx)); + break; + case StaticDataMemberSpecialization: { // HasMemberSpecializationInfo. VarDecl *Tmpl = ReadDeclAs(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 SpecIDs; SpecIDs.push_back(0); diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index c9f3a6541f88..80726309417d 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -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(D) && !D->isConstexpr() && !D->isPreviousDeclInSameBlockScope() && - !SpecInfo) + !D->getMemberSpecializationInfo()) AbbrevToUse = Writer.getDeclVarAbbrev(); Code = serialization::DECL_VAR; diff --git a/clang/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp b/clang/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp index 4cff1e2e9df8..edaae9f49d05 100644 --- a/clang/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp +++ b/clang/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp @@ -20,7 +20,7 @@ template 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 diff --git a/clang/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp b/clang/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp index 3844ec99458e..d12feeff0bbc 100644 --- a/clang/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp +++ b/clang/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp @@ -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 { diff --git a/clang/test/PCH/cxx1y-variable-templates.cpp b/clang/test/PCH/cxx1y-variable-templates.cpp index 8bc2129ebd59..0c600b29d39d 100644 --- a/clang/test/PCH/cxx1y-variable-templates.cpp +++ b/clang/test/PCH/cxx1y-variable-templates.cpp @@ -168,5 +168,4 @@ namespace spec_join1 { int* intpb = vd; } - #endif diff --git a/clang/test/SemaCXX/cxx1y-variable-templates_top_level.cpp b/clang/test/SemaCXX/cxx1y-variable-templates_top_level.cpp index dc721ce10fd4..82e3c116aad8 100644 --- a/clang/test/SemaCXX/cxx1y-variable-templates_top_level.cpp +++ b/clang/test/SemaCXX/cxx1y-variable-templates_top_level.cpp @@ -72,7 +72,7 @@ namespace odr_tmpl { } namespace pvt_cv { template 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 T v0; // expected-note {{previous definition is here}} @@ -107,6 +107,9 @@ namespace odr_tmpl { #ifdef CXX11 template extern auto v; // expected-error {{declaration of variable 'v' with type 'auto' requires an initializer}} #endif + + template T var = T(); // expected-note {{previous definition is here}} + extern int var; // expected-error {{redefinition of 'var' as different kind of symbol}} } #ifdef CXX11