From 04ff0837060d4d872ec450d0e01c809db26530da Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 6 Sep 2017 20:01:14 +0000 Subject: [PATCH] [modules ts] Emit global variables in a module interface unit as part of that unit, not in importers. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@312665 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Serialization/ASTReader.h | 2 +- lib/AST/ASTContext.cpp | 40 ++++++++++++++----- lib/Serialization/ASTReader.cpp | 4 +- lib/Serialization/ASTReaderDecl.cpp | 11 +++-- lib/Serialization/ASTWriterDecl.cpp | 19 +++++++++ .../basic/basic.def.odr/p4/module.cpp | 10 ++--- .../basic/basic.def.odr/p4/user.cpp | 6 +-- 7 files changed, 64 insertions(+), 28 deletions(-) diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 94ac9f2fac..f9a026067e 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -1133,7 +1133,7 @@ private: /// predefines buffer may contain additional definitions. std::string SuggestedPredefines; - llvm::DenseMap BodySource; + llvm::DenseMap DefinitionSource; /// \brief Reads a statement from the specified cursor. Stmt *ReadStmtFromStream(ModuleFile &F); diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 1fb146e839..fbc8874e93 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -8908,7 +8908,7 @@ static GVALinkage basicGVALinkageForFunction(const ASTContext &Context, } static GVALinkage adjustGVALinkageForAttributes(const ASTContext &Context, - GVALinkage L, const Decl *D) { + const Decl *D, GVALinkage L) { // See http://msdn.microsoft.com/en-us/library/xa0d9ste.aspx // dllexport/dllimport on inline functions. if (D->hasAttr()) { @@ -8927,25 +8927,37 @@ static GVALinkage adjustGVALinkageForAttributes(const ASTContext &Context, return L; } -GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) const { - auto L = adjustGVALinkageForAttributes( - *this, basicGVALinkageForFunction(*this, FD), FD); - auto EK = ExternalASTSource::EK_ReplyHazy; - if (auto *Ext = getExternalSource()) - EK = Ext->hasExternalDefinitions(FD); - switch (EK) { +/// Adjust the GVALinkage for a declaration based on what an external AST source +/// knows about whether there can be other definitions of this declaration. +static GVALinkage +adjustGVALinkageForExternalDefinitionKind(const ASTContext &Ctx, const Decl *D, + GVALinkage L) { + ExternalASTSource *Source = Ctx.getExternalSource(); + if (!Source) + return L; + + switch (Source->hasExternalDefinitions(D)) { case ExternalASTSource::EK_Never: + // Other translation units rely on us to provide the definition. if (L == GVA_DiscardableODR) return GVA_StrongODR; break; + case ExternalASTSource::EK_Always: return GVA_AvailableExternally; + case ExternalASTSource::EK_ReplyHazy: break; } return L; } +GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) const { + return adjustGVALinkageForExternalDefinitionKind(*this, FD, + adjustGVALinkageForAttributes(*this, FD, + basicGVALinkageForFunction(*this, FD))); +} + static GVALinkage basicGVALinkageForVariable(const ASTContext &Context, const VarDecl *VD) { if (!VD->isExternallyVisible()) @@ -9024,8 +9036,9 @@ static GVALinkage basicGVALinkageForVariable(const ASTContext &Context, } GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) { - return adjustGVALinkageForAttributes( - *this, basicGVALinkageForVariable(*this, VD), VD); + return adjustGVALinkageForExternalDefinitionKind(*this, VD, + adjustGVALinkageForAttributes(*this, VD, + basicGVALinkageForVariable(*this, VD))); } bool ASTContext::DeclMustBeEmitted(const Decl *D) { @@ -9108,9 +9121,14 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { return false; // Variables that can be needed in other TUs are required. - if (!isDiscardableGVALinkage(GetGVALinkageForVariable(VD))) + auto Linkage = GetGVALinkageForVariable(VD); + if (!isDiscardableGVALinkage(Linkage)) return true; + // We never need to emit a variable that is available in another TU. + if (Linkage == GVA_AvailableExternally) + return false; + // Variables that have destruction with side-effects are required. if (VD->getType().isDestructedType()) return true; diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 4ba54fb712..3221d78d16 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -8291,8 +8291,8 @@ ASTReader::getSourceDescriptor(unsigned ID) { } ExternalASTSource::ExtKind ASTReader::hasExternalDefinitions(const Decl *FD) { - auto I = BodySource.find(FD); - if (I == BodySource.end()) + auto I = DefinitionSource.find(FD); + if (I == DefinitionSource.end()) return EK_ReplyHazy; return I->second ? EK_Never : EK_Always; } diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 533a3f9bdc..6932261ad9 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -453,7 +453,7 @@ uint64_t ASTDeclReader::GetCurrentCursorOffset() { void ASTDeclReader::ReadFunctionDefinition(FunctionDecl *FD) { if (Record.readInt()) - Reader.BodySource[FD] = Loc.F->Kind == ModuleKind::MK_MainFile; + Reader.DefinitionSource[FD] = Loc.F->Kind == ModuleKind::MK_MainFile; if (auto *CD = dyn_cast(FD)) { CD->NumCtorInitializers = Record.readInt(); if (CD->NumCtorInitializers) @@ -1294,6 +1294,9 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) { } } + if (VD->getStorageDuration() == SD_Static && Record.readInt()) + Reader.DefinitionSource[VD] = Loc.F->Kind == ModuleKind::MK_MainFile; + enum VarKind { VarNotTemplate = 0, VarTemplate, StaticDataMemberSpecialization }; @@ -1589,9 +1592,9 @@ void ASTDeclReader::ReadCXXDefinitionData( Data.HasODRHash = true; if (Record.readInt()) { - Reader.BodySource[D] = Loc.F->Kind == ModuleKind::MK_MainFile - ? ExternalASTSource::EK_Never - : ExternalASTSource::EK_Always; + Reader.DefinitionSource[D] = Loc.F->Kind == ModuleKind::MK_MainFile + ? ExternalASTSource::EK_Never + : ExternalASTSource::EK_Always; } Data.NumBases = Record.readInt(); diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 76021e270b..bdf3fca49a 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -928,6 +928,24 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { } else { Record.push_back(0); } + + if (D->getStorageDuration() == SD_Static) { + bool ModulesCodegen = false; + if (Writer.WritingModule && + !D->getDescribedVarTemplate() && !D->getMemberSpecializationInfo() && + !isa(D)) { + // When building a C++ Modules TS module interface unit, a strong + // definition in the module interface is provided by the compilation of + // that module interface unit, not by its users. (Inline variables are + // still emitted in module users.) + ModulesCodegen = + (Writer.WritingModule->Kind == Module::ModuleInterfaceUnit && + Writer.Context->GetGVALinkageForVariable(D) == GVA_StrongExternal); + } + Record.push_back(ModulesCodegen); + if (ModulesCodegen) + Writer.ModularCodegenDecls.push_back(Writer.GetDeclRef(D)); + } enum { VarNotTemplate = 0, VarTemplate, StaticDataMemberSpecialization @@ -963,6 +981,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { !D->isConstexpr() && !D->isInitCapture() && !D->isPreviousDeclInSameBlockScope() && + D->getStorageDuration() != SD_Static && !D->getMemberSpecializationInfo()) AbbrevToUse = Writer.getDeclVarAbbrev(); diff --git a/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp b/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp index 83cad5cc9b..bdb541e9c4 100644 --- a/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp +++ b/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp @@ -2,17 +2,15 @@ // RUN: %clang_cc1 -fmodules-ts %s -triple %itanium_abi_triple -fmodule-file=%t -emit-llvm -o - | FileCheck %s --implicit-check-not=unused --implicit-check-not=global_module // CHECK-DAG: @extern_var_exported = external global -// FIXME: Should this be 'external global'? // CHECK-DAG: @inline_var_exported = linkonce_odr global -// CHECK-DAG: @_ZW6ModuleE19static_var_exported = external global -// CHECK-DAG: @const_var_exported = external constant +// CHECK-DAG: @_ZW6ModuleE19static_var_exported = available_externally global i32 0, +// CHECK-DAG: @const_var_exported = available_externally constant i32 3, // // FIXME: The module name should be mangled into all of these. // CHECK-DAG: @extern_var_module_linkage = external global -// FIXME: Should this be 'external global'? // CHECK-DAG: @inline_var_module_linkage = linkonce_odr global -// CHECK-DAG: @_ZW6ModuleE25static_var_module_linkage = external global -// CHECK-DAG: @_ZW6ModuleE24const_var_module_linkage = external constant +// CHECK-DAG: @_ZW6ModuleE25static_var_module_linkage = available_externally global i32 0, +// CHECK-DAG: @_ZW6ModuleE24const_var_module_linkage = available_externally constant i32 3, module Module; diff --git a/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp b/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp index ccbf222658..5e9f7ecf5b 100644 --- a/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp +++ b/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp @@ -2,11 +2,9 @@ // RUN: %clang_cc1 -fmodules-ts %s -triple %itanium_abi_triple -fmodule-file=%t -emit-llvm -o - | FileCheck %s --implicit-check-not=unused --implicit-check-not=global_module // CHECK-DAG: @extern_var_exported = external global -// FIXME: Should this be 'external global'? // CHECK-DAG: @inline_var_exported = linkonce_odr global -// FIXME: These should be 'extern global' and 'extern constant'. -// CHECK-DAG: @_ZW6ModuleE19static_var_exported = global -// CHECK-DAG: @const_var_exported = constant +// CHECK-DAG: @_ZW6ModuleE19static_var_exported = available_externally global i32 0 +// CHECK-DAG: @const_var_exported = available_externally constant i32 3 import Module; -- 2.50.0