From 04592e7c1260a6a671a24d91dab16f5d5a024fe0 Mon Sep 17 00:00:00 2001 From: Larisse Voufo <lvoufo@google.com> Date: Thu, 22 Aug 2013 00:28:27 +0000 Subject: [PATCH] Improve support for static data member templates. This revision still has at least one bug, as it does not respect the variable template specialization hierarchy well. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@188969 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaDecl.cpp | 7 +- lib/Sema/SemaTemplate.cpp | 5 +- lib/Sema/SemaTemplateInstantiateDecl.cpp | 37 +++++------ .../cxx1y-variable-templates_in_class.cpp | 65 ++++++++++++++++--- 4 files changed, 78 insertions(+), 36 deletions(-) diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 9dad47fb8f5..9f2e757dc2f 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -5333,18 +5333,13 @@ 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()) - NewTemplate->setMemberSpecialization(); + PrevVarTemplate->setMemberSpecialization(); // Set the lexical context of this template NewTemplate->setLexicalDeclContext(CurContext); if (NewVD->isStaticDataMember() && NewVD->isOutOfLine()) NewTemplate->setAccess(NewVD->getAccess()); - if (PrevVarTemplate) - mergeDeclAttributes(NewVD, PrevVarTemplate->getTemplatedDecl()); - - AddPushedVisibilityAttribute(NewVD); - PushOnScopeChains(NewTemplate, S); AddToScope = false; diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 5d0169173cd..f4f43ab05b6 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -2391,7 +2391,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization( // If we are providing an explicit specialization of a member variable // template specialization, make a note of that. if (PrevPartial && PrevPartial->getInstantiatedFromMember()) - Partial->setMemberSpecialization(); + PrevPartial->setMemberSpecialization(); // Check that all of the template parameters of the variable template // partial specialization are deducible from the template @@ -2477,6 +2477,9 @@ DeclResult Sema::ActOnVarTemplateSpecialization( ForRedeclaration); PrevSpec.addDecl(PrevDecl); D.setRedeclaration(CheckVariableDeclaration(Specialization, PrevSpec)); + } else if (Specialization->isStaticDataMember() && + Specialization->isOutOfLine()) { + Specialization->setAccess(VarTemplate->getAccess()); } // Link instantiations of static data members back to the template from diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index b53c197d526..8d066a0ac2b 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -952,7 +952,6 @@ TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl( Decl *TemplateDeclInstantiator::VisitVarTemplateDecl(VarTemplateDecl *D) { assert(D->getTemplatedDecl()->isStaticDataMember() && "Only static data member templates are allowed."); - // FIXME: Also only when instantiating a class? // Create a local instantiation scope for this variable template, which // will contain the instantiations of the template parameters. @@ -971,28 +970,11 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateDecl(VarTemplateDecl *D) { PrevVarTemplate = dyn_cast<VarTemplateDecl>(Found.front()); } - // FIXME: This, and ForVarTemplate, is a hack that is probably unnecessary. - // We should use a simplified version of VisitVarDecl. VarDecl *VarInst = cast_or_null<VarDecl>(VisitVarDecl(Pattern, /*ForVarTemplate=*/ true)); DeclContext *DC = Owner; - /* FIXME: This should be handled in VisitVarDecl, as used to produce - VarInst above. - // Instantiate the qualifier. - NestedNameSpecifierLoc QualifierLoc = Pattern->getQualifierLoc(); - if (QualifierLoc) { - QualifierLoc = - SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc, TemplateArgs); - if (!QualifierLoc) - return 0; - } - - if (QualifierLoc) - VarInst->setQualifierInfo(QualifierLoc); - */ - VarTemplateDecl *Inst = VarTemplateDecl::Create( SemaRef.Context, DC, D->getLocation(), D->getIdentifier(), InstParams, VarInst, PrevVarTemplate); @@ -1028,7 +1010,6 @@ Decl *TemplateDeclInstantiator::VisitVarTemplatePartialSpecializationDecl( VarTemplatePartialSpecializationDecl *D) { assert(D->isStaticDataMember() && "Only static data member templates are allowed."); - // FIXME: Also only when instantiating a class? VarTemplateDecl *VarTemplate = D->getSpecializedTemplate(); @@ -2669,11 +2650,18 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization( InstPartialSpec->setTypeAsWritten(WrittenTy); InstPartialSpec->setAccess(PartialSpec->getAccess()); - // FIXME: How much of BuildVariableInstantiation() should go in here? // Add this partial specialization to the set of variable template partial // 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, StartingScope); + InstPartialSpec->setInit(PartialSpec->getInit()); + return InstPartialSpec; } @@ -3303,8 +3291,10 @@ VarTemplateSpecializationDecl *Sema::CompleteVarTemplateSpecializationDecl( const MultiLevelTemplateArgumentList &TemplateArgs) { // Do substitution on the type of the declaration + MultiLevelTemplateArgumentList Innermost; + Innermost.addOuterTemplateArguments(TemplateArgs.getInnermost()); TypeSourceInfo *DI = - SubstType(PatternDecl->getTypeSourceInfo(), TemplateArgs, + SubstType(PatternDecl->getTypeSourceInfo(), Innermost, PatternDecl->getTypeSpecStartLoc(), PatternDecl->getDeclName()); if (!DI) return 0; @@ -3386,6 +3376,11 @@ void Sema::BuildVariableInstantiation( if (isa<VarTemplateSpecializationDecl>(NewVar)) { // Do not instantiate the variable just yet. + } else if (ForVarTemplate) { + 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 InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs); diff --git a/test/SemaCXX/cxx1y-variable-templates_in_class.cpp b/test/SemaCXX/cxx1y-variable-templates_in_class.cpp index 7f2823c5c2c..077394f2130 100644 --- a/test/SemaCXX/cxx1y-variable-templates_in_class.cpp +++ b/test/SemaCXX/cxx1y-variable-templates_in_class.cpp @@ -127,13 +127,13 @@ struct matrix_constants { }; namespace in_class_template { - // FIXME: member data templates of class templates are not well supported yet. template<typename T> class D0 { template<typename U> static U Data; template<typename U> static const U Data<U*> = U(); }; + template const int D0<float>::Data<int*>; template<typename T> class D1 { @@ -142,14 +142,63 @@ namespace in_class_template { }; template<typename T> template<typename U> U* D1<T>::Data<U*> = (U*)(0); - - namespace to_be_fixed { - // FIXME: The following generate runtime exceptions! + template int* D1<float>::Data<int*>; + + template<typename T> + class D2 { + template<typename U> static U Data; + template<typename U> static U* Data<U*>; + }; + template<> + template<typename U> U* D2<float>::Data<U*> = (U*)(0) + 1; + template int* D1<float>::Data<int*>; + + template<typename T> + struct D3 { + template<typename U> static const U Data = U(100); + }; + template const int D3<float>::Data<int>; +#ifndef PRECXX11 + static_assert(D3<float>::Data<int> == 100, ""); +#endif - //template<> - //template<typename U> U* D1<float>::Data<U*> = (U*)(0) + 1; - //template const int D0<float>::Data<int*>; - //template int* D1<float>::Data<int*>; + 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 { + 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 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<> + template<typename U> U* D1<float>::Data<U*> = (U*)(0) + 1; // expected-error{{redefinition of 'Data'}} + } + + namespace other_bugs { + // FIXME: This fails to properly initilize the variable 'k'. + + template<typename A> struct S { + template<typename B> static int V; + template<typename B> static int V0; + }; + template struct S<int>; + template<typename A> template<typename B> int S<A>::V0 = 123; + template<typename A> template<typename B> int S<A>::V<B> = 123; + int k = S<int>::V<void>; } } -- GitLab