From: Richard Smith Date: Sat, 2 Dec 2017 02:48:42 +0000 (+0000) Subject: PR35456: Track definedness of variable template specializations separately from X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e9089c9a34b0b14012858e6b33938a1c41160d1d;p=clang PR35456: Track definedness of variable template specializations separately from whether they have an initializer. We cannot distinguish between a declaration of a variable template specialization and a definition of one that lacks an initializer without this, and would previously mistake the latter for the former. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@319605 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 991f073606..96493fc78b 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -2540,6 +2540,12 @@ class VarTemplateSpecializationDecl : public VarDecl, /// Really a value of type TemplateSpecializationKind. unsigned SpecializationKind : 3; + /// \brief Whether this declaration is a complete definition of the + /// variable template specialization. We can't otherwise tell apart + /// an instantiated declaration from an instantiated definition with + /// no initializer. + unsigned IsCompleteDefinition : 1; + protected: VarTemplateSpecializationDecl(Kind DK, ASTContext &Context, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, @@ -2553,6 +2559,7 @@ protected: public: friend class ASTDeclReader; friend class ASTDeclWriter; + friend class VarDecl; static VarTemplateSpecializationDecl * Create(ASTContext &Context, DeclContext *DC, SourceLocation StartLoc, @@ -2616,6 +2623,8 @@ public: PointOfInstantiation = Loc; } + void setCompleteDefinition() { IsCompleteDefinition = true; } + /// \brief If this variable template specialization is an instantiation of /// a template (rather than an explicit specialization), return the /// variable template or variable template partial specialization from which diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 41c4fd0e6c..29846b6101 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2029,9 +2029,12 @@ VarDecl::isThisDeclarationADefinition(ASTContext &C) const { // A variable template specialization (other than a static data member // template or an explicit specialization) is a declaration until we // instantiate its initializer. - if (isa(this) && - getTemplateSpecializationKind() != TSK_ExplicitSpecialization) - return DeclarationOnly; + if (auto *VTSD = dyn_cast(this)) { + if (VTSD->getTemplateSpecializationKind() != TSK_ExplicitSpecialization && + !isa(VTSD) && + !VTSD->IsCompleteDefinition) + return DeclarationOnly; + } if (hasExternalStorage()) return DeclarationOnly; diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index f5a2ab07bf..54e8dd8662 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -1043,13 +1043,13 @@ VarTemplateSpecializationDecl::VarTemplateSpecializationDecl( SpecializedTemplate->getIdentifier(), T, TInfo, S), SpecializedTemplate(SpecializedTemplate), TemplateArgs(TemplateArgumentList::CreateCopy(Context, Args)), - SpecializationKind(TSK_Undeclared) {} + SpecializationKind(TSK_Undeclared), IsCompleteDefinition(false) {} VarTemplateSpecializationDecl::VarTemplateSpecializationDecl(Kind DK, ASTContext &C) : VarDecl(DK, C, nullptr, SourceLocation(), SourceLocation(), nullptr, QualType(), nullptr, SC_None), - SpecializationKind(TSK_Undeclared) {} + SpecializationKind(TSK_Undeclared), IsCompleteDefinition(false) {} VarTemplateSpecializationDecl *VarTemplateSpecializationDecl::Create( ASTContext &Context, DeclContext *DC, SourceLocation StartLoc, diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 5b528fa9c2..eacb325642 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -4021,6 +4021,8 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation( VarTemplateSpecializationDecl *Sema::CompleteVarTemplateSpecializationDecl( VarTemplateSpecializationDecl *VarSpec, VarDecl *PatternDecl, const MultiLevelTemplateArgumentList &TemplateArgs) { + assert(PatternDecl->isThisDeclarationADefinition() && + "don't have a definition to instantiate from"); // Do substitution on the type of the declaration TypeSourceInfo *DI = @@ -4032,6 +4034,9 @@ VarTemplateSpecializationDecl *Sema::CompleteVarTemplateSpecializationDecl( // Update the type of this variable template specialization. VarSpec->setType(DI->getType()); + // Convert the declaration into a definition now. + VarSpec->setCompleteDefinition(); + // Instantiate the initializer. InstantiateVariableInitializer(VarSpec, PatternDecl, TemplateArgs); @@ -4225,6 +4230,10 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, if (Var->isInvalidDecl()) return; + // FIXME: We're missing ASTMutationListener notifications for all of the work + // done here. (Some of our callers notify the listeners for the static data + // member case, but not in general.) + VarTemplateSpecializationDecl *VarSpec = dyn_cast(Var); VarDecl *PatternDecl = nullptr, *Def = nullptr; diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 126738b617..eb7c1777ac 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -2198,6 +2198,7 @@ ASTDeclReader::VisitVarTemplateSpecializationDeclImpl( D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs); D->PointOfInstantiation = ReadSourceLocation(); D->SpecializationKind = (TemplateSpecializationKind)Record.readInt(); + D->IsCompleteDefinition = Record.readInt(); bool writtenAsCanonicalDecl = Record.readInt(); if (writtenAsCanonicalDecl) { diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index fcf78e850b..041ccd47d0 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -1494,6 +1494,7 @@ void ASTDeclWriter::VisitVarTemplateSpecializationDecl( Record.AddTemplateArgumentList(&D->getTemplateArgs()); Record.AddSourceLocation(D->getPointOfInstantiation()); Record.push_back(D->getSpecializationKind()); + Record.push_back(D->IsCompleteDefinition); Record.push_back(D->isCanonicalDecl()); if (D->isCanonicalDecl()) { diff --git a/test/CodeGenCXX/cxx1y-variable-template.cpp b/test/CodeGenCXX/cxx1y-variable-template.cpp index cd73817d85..dd8f28e429 100644 --- a/test/CodeGenCXX/cxx1y-variable-template.cpp +++ b/test/CodeGenCXX/cxx1y-variable-template.cpp @@ -18,6 +18,12 @@ int init_arr(); template template template int Outer::Inner::arr[sizeof(T) + sizeof(U) + sizeof(V)] = { init_arr() }; int *p = Outer::Inner::arr; +namespace PR35456 { +// CHECK: @_ZN7PR354561nILi0EEE = linkonce_odr global i32 0 +template int n; +int *p = &n<0>; +} + // CHECK: @_ZN5OuterIA100_cE5InnerIA20_cE3arrIA3_cEE = linkonce_odr global [123 x i32] zeroinitializer // CHECK: @_ZGVN5OuterIA100_cE5InnerIA20_cE3arrIA3_cEE = linkonce_odr global diff --git a/test/CodeGenCXX/dllexport.cpp b/test/CodeGenCXX/dllexport.cpp index d79a19420a..a446147b6c 100644 --- a/test/CodeGenCXX/dllexport.cpp +++ b/test/CodeGenCXX/dllexport.cpp @@ -102,15 +102,9 @@ inline int __declspec(dllexport) inlineStaticLocalsFunc() { // Declarations are not exported. -// dllexport implies a definition. -// MSC-NOT: @"\01??$VarTmplDef@UExplicitInst_Exported@@@@3HA" -// GNU-NOT: @_Z10VarTmplDefI21ExplicitInst_ExportedE -template __declspec(dllexport) int VarTmplDef; -INSTVAR(VarTmplDef) - // MSC-DAG: @"\01??$VarTmplImplicitDef@UImplicitInst_Exported@@@@3HA" = external global // GNU-DAG: @_Z18VarTmplImplicitDefI21ImplicitInst_ExportedE = external global -template __declspec(dllexport) int VarTmplImplicitDef; +template __declspec(dllexport) extern int VarTmplImplicitDef; USEVAR(VarTmplImplicitDef) // Export definition.