From beef3453cd12923bd8100a40d6a2e6281dd250ab Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 16 Jan 2014 23:39:20 +0000 Subject: [PATCH] Clean up variable template handling a bit, and correct the behavior of name lookup when declaring a variable template specialization. llvm-svn: 199438 --- clang/include/clang/AST/DeclTemplate.h | 4 +- clang/include/clang/Sema/Sema.h | 2 +- clang/lib/AST/ASTImporter.cpp | 3 +- clang/lib/AST/DeclTemplate.cpp | 7 +- clang/lib/Sema/SemaDecl.cpp | 201 ++++++++---------- clang/lib/Sema/SemaTemplate.cpp | 17 +- clang/lib/Sema/SemaTemplateInstantiate.cpp | 14 +- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 16 +- .../cxx1y-variable-template-no-body.cpp | 6 +- .../temp/temp.spec/temp.expl.spec/p2-0x.cpp | 42 +++- .../cxx1y-variable-templates_top_level.cpp | 13 +- 11 files changed, 176 insertions(+), 149 deletions(-) diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 2b8b24d37e7a..31a18d4c674f 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -2704,8 +2704,8 @@ public: /// \brief Create a variable template node. static VarTemplateDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName Name, - TemplateParameterList *Params, NamedDecl *Decl, - VarTemplateDecl *PrevDecl); + TemplateParameterList *Params, + VarDecl *Decl); /// \brief Create an empty variable template node. static VarTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 4a82e4316860..85fb4f2cd11d 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5141,7 +5141,7 @@ public: SourceLocation RAngleLoc); DeclResult ActOnVarTemplateSpecialization( - Scope *S, VarTemplateDecl *VarTemplate, Declarator &D, TypeSourceInfo *DI, + Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, StorageClass SC, bool IsPartialSpecialization); diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 508fa0a201d3..d1a606f853a4 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -4241,8 +4241,7 @@ Decl *ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) { return 0; VarTemplateDecl *D2 = VarTemplateDecl::Create( - Importer.getToContext(), DC, Loc, Name, TemplateParams, D2Templated, - /*PrevDecl=*/0); + Importer.getToContext(), DC, Loc, Name, TemplateParams, D2Templated); D2Templated->setDescribedVarTemplate(D2); D2->setAccess(D->getAccess()); diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index bab29cb1682e..fc73e6f41252 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -941,11 +941,8 @@ VarTemplateDecl *VarTemplateDecl::getDefinition() { VarTemplateDecl *VarTemplateDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateParameterList *Params, - NamedDecl *Decl, - VarTemplateDecl *PrevDecl) { - VarTemplateDecl *New = new (C, DC) VarTemplateDecl(DC, L, Name, Params, Decl); - New->setPreviousDecl(PrevDecl); - return New; + VarDecl *Decl) { + return new (C, DC) VarTemplateDecl(DC, L, Name, Params, Decl); } VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 76472651e1e1..e14fc53750c5 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -3000,14 +3000,17 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { if (New->isInvalidDecl()) return; + VarTemplateDecl *NewTemplate = New->getDescribedVarTemplate(); + // Verify the old decl was also a variable or variable template. VarDecl *Old = 0; - if (Previous.isSingleResult() && - (Old = dyn_cast(Previous.getFoundDecl()))) { - if (New->getDescribedVarTemplate()) - Old = Old->getDescribedVarTemplate() ? Old : 0; - else - Old = Old->getDescribedVarTemplate() ? 0 : Old; + VarTemplateDecl *OldTemplate = 0; + if (Previous.isSingleResult()) { + if (NewTemplate) { + OldTemplate = dyn_cast(Previous.getFoundDecl()); + Old = OldTemplate ? OldTemplate->getTemplatedDecl() : 0; + } else + Old = dyn_cast(Previous.getFoundDecl()); } if (!Old) { Diag(New->getLocation(), diag::err_redefinition_different_kind) @@ -3020,6 +3023,13 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { if (!shouldLinkPossiblyHiddenDecl(Old, New)) return; + // Ensure the template parameters are compatible. + if (NewTemplate && + !TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(), + OldTemplate->getTemplateParameters(), + /*Complain=*/true, TPL_TemplateMatch)) + return; + // C++ [class.mem]p1: // A member shall not be declared twice in the member-specification [...] // @@ -3145,14 +3155,13 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { // Keep a chain of previous declarations. New->setPreviousDecl(Old); + if (NewTemplate) + NewTemplate->setPreviousDecl(OldTemplate); // Inherit access appropriately. New->setAccess(Old->getAccess()); - - if (VarTemplateDecl *VTD = New->getDescribedVarTemplate()) { - if (New->isStaticDataMember() && New->isOutOfLine()) - VTD->setAccess(New->getAccess()); - } + if (NewTemplate) + NewTemplate->setAccess(New->getAccess()); } /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with @@ -5065,9 +5074,9 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, bool IsVariableTemplateSpecialization = false; bool IsPartialSpecialization = false; bool IsVariableTemplate = false; - VarTemplateDecl *PrevVarTemplate = 0; VarDecl *NewVD = 0; VarTemplateDecl *NewTemplate = 0; + TemplateParameterList *TemplateParams = 0; if (!getLangOpts().CPlusPlus) { NewVD = VarDecl::Create(Context, DC, D.getLocStart(), D.getIdentifierLoc(), II, @@ -5129,18 +5138,33 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } - NamedDecl *PrevDecl = 0; - if (Previous.begin() != Previous.end()) - PrevDecl = (*Previous.begin())->getUnderlyingDecl(); - PrevVarTemplate = dyn_cast_or_null(PrevDecl); - // Match up the template parameter lists with the scope specifier, then // determine whether we have a template or a template specialization. - TemplateParameterList *TemplateParams = - MatchTemplateParametersToScopeSpecifier( - D.getDeclSpec().getLocStart(), D.getIdentifierLoc(), - D.getCXXScopeSpec(), TemplateParamLists, - /*never a friend*/ false, IsExplicitSpecialization, Invalid); + TemplateParams = MatchTemplateParametersToScopeSpecifier( + D.getDeclSpec().getLocStart(), D.getIdentifierLoc(), + D.getCXXScopeSpec(), TemplateParamLists, + /*never a friend*/ false, IsExplicitSpecialization, Invalid); + + if (D.getName().getKind() == UnqualifiedId::IK_TemplateId && + !TemplateParams) { + TemplateIdAnnotation *TemplateId = D.getName().TemplateId; + + // We have encountered something that the user meant to be a + // specialization (because it has explicitly-specified template + // arguments) but that was not introduced with a "template<>" (or had + // too few of them). + // FIXME: Differentiate between attempts for explicit instantiations + // (starting with "template") and the rest. + Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header) + << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc) + << FixItHint::CreateInsertion(D.getDeclSpec().getLocStart(), + "template<> "); + IsVariableTemplateSpecialization = true; + TemplateParams = TemplateParameterList::Create(Context, SourceLocation(), + SourceLocation(), 0, 0, + SourceLocation()); + } + if (TemplateParams) { if (!TemplateParams->size() && D.getName().getKind() != UnqualifiedId::IK_TemplateId) { @@ -5151,6 +5175,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, << II << SourceRange(TemplateParams->getTemplateLoc(), TemplateParams->getRAngleLoc()); + TemplateParams = 0; } else { // Only C++1y supports variable templates (N3651). Diag(D.getIdentifierLoc(), @@ -5160,11 +5185,9 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { // This is an explicit specialization or a partial specialization. - // Check that we can declare a specialization here - + // FIXME: Check that we can declare a specialization here. IsVariableTemplateSpecialization = true; IsPartialSpecialization = TemplateParams->size() > 0; - } else { // if (TemplateParams->size() > 0) // This is a template declaration. IsVariableTemplate = true; @@ -5172,89 +5195,17 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Check that we can declare a template here. if (CheckTemplateDeclScope(S, TemplateParams)) return 0; - - // If there is a previous declaration with the same name, check - // whether this is a valid redeclaration. - if (PrevDecl && !isDeclInScope(PrevDecl, DC, S)) - PrevDecl = PrevVarTemplate = 0; - - if (PrevVarTemplate) { - // Ensure that the template parameter lists are compatible. - if (!TemplateParameterListsAreEqual( - TemplateParams, PrevVarTemplate->getTemplateParameters(), - /*Complain=*/true, TPL_TemplateMatch)) - return 0; - } else if (PrevDecl && PrevDecl->isTemplateParameter()) { - // Maybe we will complain about the shadowed template parameter. - DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl); - - // Just pretend that we didn't see the previous declaration. - PrevDecl = 0; - } else if (PrevDecl) { - // C++ [temp]p5: - // ... a template name declared in namespace scope or in class - // scope shall be unique in that scope. - Diag(D.getIdentifierLoc(), diag::err_redefinition_different_kind) - << Name; - Diag(PrevDecl->getLocation(), diag::note_previous_definition); - return 0; - } - - // Check the template parameter list of this declaration, possibly - // merging in the template parameter list from the previous variable - // template declaration. - if (CheckTemplateParameterList( - TemplateParams, - PrevVarTemplate ? PrevVarTemplate->getTemplateParameters() - : 0, - (D.getCXXScopeSpec().isSet() && DC && DC->isRecord() && - DC->isDependentContext()) - ? TPC_ClassTemplateMember - : TPC_VarTemplate)) - Invalid = true; - - if (D.getCXXScopeSpec().isSet()) { - // If the name of the template was qualified, we must be defining - // the template out-of-line. - if (!D.getCXXScopeSpec().isInvalid() && !Invalid && - !PrevVarTemplate) { - Diag(D.getIdentifierLoc(), diag::err_member_decl_does_not_match) - << Name << DC << /*IsDefinition*/true - << D.getCXXScopeSpec().getRange(); - Invalid = true; - } - } } } - } else if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { - TemplateIdAnnotation *TemplateId = D.getName().TemplateId; - - // We have encountered something that the user meant to be a - // specialization (because it has explicitly-specified template - // arguments) but that was not introduced with a "template<>" (or had - // too few of them). - // FIXME: Differentiate between attempts for explicit instantiations - // (starting with "template") and the rest. - Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header) - << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc) - << FixItHint::CreateInsertion(D.getDeclSpec().getLocStart(), - "template<> "); - IsVariableTemplateSpecialization = true; } if (IsVariableTemplateSpecialization) { - if (!PrevVarTemplate) { - Diag(D.getIdentifierLoc(), diag::err_var_spec_no_template) - << IsPartialSpecialization; - return 0; - } - SourceLocation TemplateKWLoc = TemplateParamLists.size() > 0 ? TemplateParamLists[0]->getTemplateLoc() : SourceLocation(); DeclResult Res = ActOnVarTemplateSpecialization( - S, PrevVarTemplate, D, TInfo, TemplateKWLoc, TemplateParams, SC, + S, D, TInfo, TemplateKWLoc, TemplateParams, SC, IsPartialSpecialization); if (Res.isInvalid()) return 0; @@ -5268,7 +5219,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (IsVariableTemplate) { NewTemplate = VarTemplateDecl::Create(Context, DC, D.getIdentifierLoc(), Name, - TemplateParams, NewVD, PrevVarTemplate); + TemplateParams, NewVD); NewVD->setDescribedVarTemplate(NewTemplate); } @@ -5453,6 +5404,11 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (!getLangOpts().CPlusPlus) { D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous)); } else { + // If this is an explicit specialization of a static data member, check it. + if (IsExplicitSpecialization && !NewVD->isInvalidDecl() && + CheckMemberSpecialization(NewVD, Previous)) + NewVD->setInvalidDecl(); + // Merge the decl with the existing one if appropriate. if (!Previous.empty()) { if (Previous.isSingleResult() && @@ -5473,20 +5429,34 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewVD->setInvalidDecl(); } - if (!IsVariableTemplateSpecialization) { - if (PrevVarTemplate) { - LookupResult PrevDecl(*this, GetNameForDeclarator(D), - LookupOrdinaryName, ForRedeclaration); - PrevDecl.addDecl(PrevVarTemplate->getTemplatedDecl()); - D.setRedeclaration(CheckVariableDeclaration(NewVD, PrevDecl)); - } else - D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous)); - } + if (!IsVariableTemplateSpecialization) + D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous)); + + if (NewTemplate) { + VarTemplateDecl *PrevVarTemplate = + NewVD->getPreviousDecl() + ? NewVD->getPreviousDecl()->getDescribedVarTemplate() + : 0; + + // Check the template parameter list of this declaration, possibly + // merging in the template parameter list from the previous variable + // template declaration. + if (CheckTemplateParameterList( + TemplateParams, + PrevVarTemplate ? PrevVarTemplate->getTemplateParameters() + : 0, + (D.getCXXScopeSpec().isSet() && DC && DC->isRecord() && + DC->isDependentContext()) + ? TPC_ClassTemplateMember + : TPC_VarTemplate)) + NewVD->setInvalidDecl(); - // This is an explicit specialization of a static data member. Check it. - if (IsExplicitSpecialization && !NewVD->isInvalidDecl() && - CheckMemberSpecialization(NewVD, Previous)) - NewVD->setInvalidDecl(); + // If we are providing an explicit specialization of a static variable + // template, make a note of that. + if (PrevVarTemplate && + PrevVarTemplate->getInstantiatedFromMemberTemplate()) + PrevVarTemplate->setMemberSpecialization(); + } } ProcessPragmaWeak(S, NewVD); @@ -5507,12 +5477,9 @@ 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()) - PrevVarTemplate->setMemberSpecialization(); - if (NewTemplate) { + if (NewVD->isInvalidDecl()) + NewTemplate->setInvalidDecl(); ActOnDocumentableDecl(NewTemplate); return NewTemplate; } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 97137184c298..ca81472b3c55 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2340,11 +2340,9 @@ static bool isSameAsPrimaryTemplate(TemplateParameterList *Params, } DeclResult Sema::ActOnVarTemplateSpecialization( - Scope *S, VarTemplateDecl *VarTemplate, Declarator &D, TypeSourceInfo *DI, - SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, - VarDecl::StorageClass SC, bool IsPartialSpecialization) { - assert(VarTemplate && "A variable template id without template?"); - + Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc, + TemplateParameterList *TemplateParams, VarDecl::StorageClass SC, + bool IsPartialSpecialization) { // D must be variable template id. assert(D.getName().getKind() == UnqualifiedId::IK_TemplateId && "Variable template specialization is declared with a template it."); @@ -2357,7 +2355,14 @@ DeclResult Sema::ActOnVarTemplateSpecialization( TemplateId->NumArgs); TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc); translateTemplateArguments(TemplateArgsPtr, TemplateArgs); - TemplateName Name(VarTemplate); + TemplateName Name = TemplateId->Template.get(); + + // The template-id must name a variable template. + VarTemplateDecl *VarTemplate = + dyn_cast(Name.getAsTemplateDecl()); + if (!VarTemplate) + return Diag(D.getIdentifierLoc(), diag::err_var_spec_no_template) + << IsPartialSpecialization; // Check for unexpanded parameter packs in any of the template arguments. for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 53ea8c7b05d4..66203e6d5c5e 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -76,8 +76,18 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, // If this variable template specialization was instantiated from a // specialized member that is a variable template, we're done. assert(Spec->getSpecializedTemplate() && "No variable template?"); - if (Spec->getSpecializedTemplate()->isMemberSpecialization()) - return Result; + llvm::PointerUnion Specialized + = Spec->getSpecializedTemplateOrPartial(); + if (VarTemplatePartialSpecializationDecl *Partial = + Specialized.dyn_cast()) { + if (Partial->isMemberSpecialization()) + return Result; + } else { + VarTemplateDecl *Tmpl = Specialized.get(); + if (Tmpl->isMemberSpecialization()) + return Result; + } } // If we have a template template parameter with translation unit context, diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 2961e08cc800..773fd923f1a6 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1033,8 +1033,9 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateDecl(VarTemplateDecl *D) { VarTemplateDecl *Inst = VarTemplateDecl::Create( SemaRef.Context, DC, D->getLocation(), D->getIdentifier(), InstParams, - VarInst, PrevVarTemplate); + VarInst); VarInst->setDescribedVarTemplate(Inst); + Inst->setPreviousDecl(PrevVarTemplate); Inst->setAccess(D->getAccess()); if (!PrevVarTemplate) @@ -3516,7 +3517,18 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation( // 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->getFirstDecl(); + // + // If we're instantiating an explicitly-specialized member template or member + // partial specialization, don't do this. The member specialization completely + // replaces the original declaration in this case. + bool IsMemberSpec = false; + if (VarTemplatePartialSpecializationDecl *PartialSpec = + dyn_cast(FromVar)) + IsMemberSpec = PartialSpec->isMemberSpecialization(); + else if (VarTemplateDecl *FromTemplate = FromVar->getDescribedVarTemplate()) + IsMemberSpec = FromTemplate->isMemberSpecialization(); + if (!IsMemberSpec) + FromVar = FromVar->getFirstDecl(); MultiLevelTemplateArgumentList MultiLevelList(TemplateArgList); TemplateDeclInstantiator Instantiator(*this, FromVar->getDeclContext(), 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 93f8ff1697bf..7eb5e3744d18 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 @@ -24,14 +24,14 @@ template int pi0 = 10; // expected-error {{variable cannot be defined in an expl #endif template -T pi1 = T(3.1415926535897932385); +T pi1 = T(3.1415926535897932385); // expected-note 0-2 {{here}} // Should recover as if specialization template float pi1 = 1.0; // expected-error {{explicit template instantiation cannot have a definition; if this definition is meant to be an explicit specialization, add '<>' after the 'template' keyword}} #ifndef FIXING namespace expected_global { - template<> double pi1 = 1.5; // expected-error {{no variable template matches specialization}} + template<> double pi1 = 1.5; // expected-error {{variable template specialization of 'pi1' must originally be declared in the global scope}} template int pi1 = 10; // expected-error {{explicit template instantiation cannot have a definition; if this definition is meant to be an explicit specialization, add '<>' after the 'template' keyword}} \ - expected-error {{no variable template matches specialization}} + expected-error {{variable template specialization of 'pi1' must originally be declared in the global scope}} } #endif diff --git a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp index 1a7065e0022b..d0e24f547723 100644 --- a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp +++ b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -Wno-c++1y-extensions // This test creates cases where implicit instantiations of various entities // would cause a diagnostic, but provides expliict specializations for those @@ -10,6 +10,8 @@ struct NonDefaultConstructible { NonDefaultConstructible(int); }; +// FIXME: The "must originally be declared in namespace" diagnostics throughout +// this file are wrong. // C++ [temp.expl.spec]p1: // An explicit specialization of any of the following: @@ -90,6 +92,44 @@ template<> struct N0::X0 { void f1(void *); }; +// -- variable template [C++1y] +namespace N0 { +template int v0; // expected-note +{{here}} +template<> extern int v0; +template<> extern int v0; +template<> extern int v0; +template<> extern int v0; +} +using N0::v0; + +template int v1; // expected-note +{{here}} +template<> extern int v1; +template<> extern int v1; +template<> extern int v1; +template<> extern int v1; + +template<> int N0::v0; +template<> int v0; // FIXME: ill-formed +template<> int ::v1; // expected-warning {{extra qualification}} +template<> int v1; + +template<> int N0::v0; +template<> int v0; // FIXME: ill-formed +template<> int ::v1; // expected-warning {{extra qualification}} +template<> int v1; + +namespace N1 { +template<> int N0::v0; // expected-error {{must originally be declared in namespace 'N0'}} expected-error {{does not enclose namespace}} +template<> int v0; // expected-error {{must originally be declared in namespace 'N0'}} +template<> int ::v1; // expected-error {{must originally be declared in the global scope}} expected-error {{cannot name the global scope}} +template<> int v1; // expected-error {{must originally be declared in the global scope}} + +template<> int N0::v0; // expected-error {{does not enclose namespace 'N0'}} +template<> int v0; // FIXME: ill-formed +template<> int ::v1; // expected-error {{cannot name the global scope}} +template<> int v1; // FIXME: ill-formed +} + // -- member function of a class template template<> void N0::X0::f1(void *) { } diff --git a/clang/test/SemaCXX/cxx1y-variable-templates_top_level.cpp b/clang/test/SemaCXX/cxx1y-variable-templates_top_level.cpp index 58aad34edd1d..d2c429413478 100644 --- a/clang/test/SemaCXX/cxx1y-variable-templates_top_level.cpp +++ b/clang/test/SemaCXX/cxx1y-variable-templates_top_level.cpp @@ -81,7 +81,7 @@ namespace odr_tmpl { template T v; // expected-note {{previous definition is here}} template int v; // expected-error {{redefinition of 'v'}} - template int v1; // expected-note {{previous template declaration is here}} + template extern int v1; // expected-note {{previous template declaration is here}} template int v1; // expected-error {{template parameter has a different kind in template redeclaration}} } namespace pvt_use { @@ -90,11 +90,8 @@ namespace odr_tmpl { } namespace pvt_diff_params { - // FIXME: (?) Redefinitions should simply be not allowed, whether the - // template parameters match or not. However, this current behaviour also - // matches that of class templates... - template T v; // expected-note 2{{previous template declaration is here}} - template T v; // expected-error {{too few template parameters in template redeclaration}} + template T v; // expected-note {{previous template declaration is here}} + template T v; // expected-error {{too few template parameters in template redeclaration}} expected-note {{previous template declaration is here}} template T v; // expected-error {{too many template parameters in template redeclaration}} } @@ -391,7 +388,7 @@ namespace nested { namespace n1 { template - T pi1a = T(3.1415926535897932385); + T pi1a = T(3.1415926535897932385); // expected-note {{explicitly specialized declaration is here}} #ifndef PRECXX11 // expected-note@-2 {{explicit instantiation refers here}} #endif @@ -413,7 +410,7 @@ namespace nested { #endif float f1 = pi1a; - template<> double pi1a = 5.2; // expected-error {{no variable template matches specialization}} + template<> double pi1a = 5.2; // expected-error {{variable template specialization of 'pi1a' must originally be declared in namespace 'n1'}} double d1 = pi1a; } -- GitLab