From affbdbb5c5edf998ffc65b7f51ea00591be91dc2 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 7 Jul 2017 20:04:28 +0000 Subject: [PATCH] [modules ts] Basic for module linkage. In addition to the formal linkage rules, the Modules TS includes cases where internal-linkage symbols within a module interface unit can be referenced from outside the module via exported inline functions / templates. We give such declarations "module-internal linkage", which is formally internal linkage, but results in an externally-visible symbol. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@307434 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/Linkage.h | 24 +++++- lib/AST/Decl.cpp | 78 +++++++++++++++---- lib/CodeGen/CodeGenModule.cpp | 2 +- lib/CodeGen/ItaniumCXXABI.cpp | 2 + lib/CodeGen/MicrosoftCXXABI.cpp | 2 + lib/Index/IndexSymbol.cpp | 4 +- .../basic/basic.def.odr/p4/module.cpp | 25 +++++- .../basic/basic.def.odr/p4/module.cppm | 76 ++++++++++++++++-- .../basic/basic.def.odr/p4/user.cpp | 12 +++ 9 files changed, 198 insertions(+), 27 deletions(-) diff --git a/include/clang/Basic/Linkage.h b/include/clang/Basic/Linkage.h index e96fb568c0..6ec8763f24 100644 --- a/include/clang/Basic/Linkage.h +++ b/include/clang/Basic/Linkage.h @@ -45,6 +45,17 @@ enum Linkage : unsigned char { /// translation units because of types defined in a inline function. VisibleNoLinkage, + /// \brief Internal linkage according to the Modules TS, but can be referred + /// to from other translation units indirectly through inline functions and + /// templates in the module interface. + ModuleInternalLinkage, + + /// \brief Module linkage, which indicates that the entity can be referred + /// to from other translation units within the same module, and indirectly + /// from arbitrary other translation units through inline functions and + /// templates in the module interface. + ModuleLinkage, + /// \brief External linkage, which indicates that the entity can /// be referred to from other translation units. ExternalLinkage @@ -74,15 +85,20 @@ inline bool isDiscardableGVALinkage(GVALinkage L) { } inline bool isExternallyVisible(Linkage L) { - return L == ExternalLinkage || L == VisibleNoLinkage; + return L >= VisibleNoLinkage; } inline Linkage getFormalLinkage(Linkage L) { - if (L == UniqueExternalLinkage) + switch (L) { + case UniqueExternalLinkage: return ExternalLinkage; - if (L == VisibleNoLinkage) + case VisibleNoLinkage: return NoLinkage; - return L; + case ModuleInternalLinkage: + return InternalLinkage; + default: + return L; + } } inline bool isExternalFormalLinkage(Linkage L) { diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 24d9983912..573a98efe9 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -573,6 +573,44 @@ static bool isSingleLineLanguageLinkage(const Decl &D) { return false; } +static bool isExportedFromModuleIntefaceUnit(const NamedDecl *D) { + switch (D->getModuleOwnershipKind()) { + case Decl::ModuleOwnershipKind::Unowned: + case Decl::ModuleOwnershipKind::ModulePrivate: + return false; + case Decl::ModuleOwnershipKind::Visible: + case Decl::ModuleOwnershipKind::VisibleWhenImported: + if (auto *M = D->getOwningModule()) + return M->Kind == Module::ModuleInterfaceUnit; + } + llvm_unreachable("unexpected module ownership kind"); +} + +static LinkageInfo getInternalLinkageFor(const NamedDecl *D) { + // Internal linkage declarations within a module interface unit are modeled + // as "module-internal linkage", which means that they have internal linkage + // formally but can be indirectly accessed from outside the module via inline + // functions and templates defined within the module. + if (auto *M = D->getOwningModule()) + if (M->Kind == Module::ModuleInterfaceUnit) + return LinkageInfo(ModuleInternalLinkage, DefaultVisibility, false); + + return LinkageInfo::internal(); +} + +static LinkageInfo getExternalLinkageFor(const NamedDecl *D) { + // C++ Modules TS [basic.link]/6.8: + // - A name declared at namespace scope that does not have internal linkage + // by the previous rules and that is introduced by a non-exported + // declaration has module linkage. + if (auto *M = D->getOwningModule()) + if (M->Kind == Module::ModuleInterfaceUnit) + if (!isExportedFromModuleIntefaceUnit(D)) + return LinkageInfo(ModuleLinkage, DefaultVisibility, false); + + return LinkageInfo::external(); +} + static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVComputationKind computation) { assert(D->getDeclContext()->getRedeclContext()->isFileContext() && @@ -588,16 +626,18 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, if (const auto *Var = dyn_cast(D)) { // Explicitly declared static. if (Var->getStorageClass() == SC_Static) - return LinkageInfo::internal(); + return getInternalLinkageFor(Var); // - a non-inline, non-volatile object or reference that is explicitly // declared const or constexpr and neither explicitly declared extern // nor previously declared to have external linkage; or (there is no // equivalent in C99) + // The C++ modules TS adds "non-exported" to this list. if (Context.getLangOpts().CPlusPlus && Var->getType().isConstQualified() && !Var->getType().isVolatileQualified() && - !Var->isInline()) { + !Var->isInline() && + !isExportedFromModuleIntefaceUnit(Var)) { const VarDecl *PrevVar = Var->getPreviousDecl(); if (PrevVar) return getLVForDecl(PrevVar, computation); @@ -605,7 +645,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, if (Var->getStorageClass() != SC_Extern && Var->getStorageClass() != SC_PrivateExtern && !isSingleLineLanguageLinkage(*Var)) - return LinkageInfo::internal(); + return getInternalLinkageFor(Var); } for (const VarDecl *PrevVar = Var->getPreviousDecl(); PrevVar; @@ -615,7 +655,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, return PrevVar->getLinkageAndVisibility(); // Explicitly declared static. if (PrevVar->getStorageClass() == SC_Static) - return LinkageInfo::internal(); + return getInternalLinkageFor(Var); } } else if (const FunctionDecl *Function = D->getAsFunction()) { // C++ [temp]p4: @@ -624,7 +664,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // Explicitly declared static. if (Function->getCanonicalDecl()->getStorageClass() == SC_Static) - return LinkageInfo(InternalLinkage, DefaultVisibility, false); + return getInternalLinkageFor(Function); } else if (const auto *IFD = dyn_cast(D)) { // - a data member of an anonymous union. const VarDecl *VD = IFD->getVarDecl(); @@ -637,7 +677,12 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, const auto *Var = dyn_cast(D); const auto *Func = dyn_cast(D); // FIXME: In C++11 onwards, anonymous namespaces should give decls - // within them internal linkage, not unique external linkage. + // within them (including those inside extern "C" contexts) internal + // linkage, not unique external linkage: + // + // C++11 [basic.link]p4: + // An unnamed namespace or a namespace declared directly or indirectly + // within an unnamed namespace has internal linkage. if ((!Var || !isFirstInExternCContext(Var)) && (!Func || !isFirstInExternCContext(Func))) return LinkageInfo::uniqueExternal(); @@ -718,7 +763,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // because of this, but unique-external linkage suits us. if (Context.getLangOpts().CPlusPlus && !isFirstInExternCContext(Var)) { LinkageInfo TypeLV = getLVForType(*Var->getType(), computation); - if (TypeLV.getLinkage() != ExternalLinkage) + if (TypeLV.getLinkage() != ExternalLinkage && + TypeLV.getLinkage() != ModuleLinkage) return LinkageInfo::uniqueExternal(); if (!LV.isVisibilityExplicit()) LV.mergeVisibility(TypeLV); @@ -816,7 +862,9 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // - a namespace (7.3), unless it is declared within an unnamed // namespace. - } else if (isa(D) && !D->isInAnonymousNamespace()) { + // + // We handled names in anonymous namespaces above. + } else if (isa(D)) { return LV; // By extension, we assign external linkage to Objective-C @@ -1125,6 +1173,8 @@ static LinkageInfo getLVForClosure(const DeclContext *DC, Decl *ContextDecl, if (const auto *ND = dyn_cast(DC)) return getLVForDecl(ND, computation); + // FIXME: We have a closure at TU scope with no context declaration. This + // should probably have no linkage. return LinkageInfo::external(); } @@ -1137,7 +1187,7 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D, // This is a "void f();" which got merged with a file static. if (Function->getCanonicalDecl()->getStorageClass() == SC_Static) - return LinkageInfo::internal(); + return getInternalLinkageFor(Function); LinkageInfo LV; if (!hasExplicitVisibilityAlready(computation)) { @@ -1226,7 +1276,7 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D, LVComputationKind computation) { // Internal_linkage attribute overrides other considerations. if (D->hasAttr()) - return LinkageInfo::internal(); + return getInternalLinkageFor(D); // Objective-C: treat all Objective-C declarations as having external // linkage. @@ -1275,14 +1325,14 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D, case Decl::ObjCProperty: case Decl::ObjCPropertyImpl: case Decl::ObjCProtocol: - return LinkageInfo::external(); + return getExternalLinkageFor(D); case Decl::CXXRecord: { const auto *Record = cast(D); if (Record->isLambda()) { if (!Record->getLambdaManglingNumber()) { // This lambda has no mangling number, so it's internal. - return LinkageInfo::internal(); + return getInternalLinkageFor(D); } // This lambda has its linkage/visibility determined: @@ -1298,7 +1348,7 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D, const CXXRecordDecl *OuterMostLambda = getOutermostEnclosingLambda(Record); if (!OuterMostLambda->getLambdaManglingNumber()) - return LinkageInfo::internal(); + return getInternalLinkageFor(D); return getLVForClosure( OuterMostLambda->getDeclContext()->getRedeclContext(), @@ -1349,7 +1399,7 @@ public: LVComputationKind computation) { // Internal_linkage attribute overrides other considerations. if (D->hasAttr()) - return LinkageInfo::internal(); + return getInternalLinkageFor(D); if (computation == LVForLinkageOnly && D->hasCachedLinkage()) return LinkageInfo(D->getCachedLinkage(), DefaultVisibility, false); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 20d945fe50..10838b751c 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -1098,7 +1098,7 @@ static void setLinkageAndVisibilityForGV(llvm::GlobalValue *GV, const NamedDecl *ND) { // Set linkage and visibility in case we never see a definition. LinkageInfo LV = ND->getLinkageAndVisibility(); - if (LV.getLinkage() != ExternalLinkage) { + if (!isExternallyVisible(LV.getLinkage())) { // Don't set internal linkage on declarations. } else { if (ND->hasAttr()) { diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index e6d38aff34..c82b9677ea 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -2959,6 +2959,8 @@ static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(CodeGenModule &CGM, return llvm::GlobalValue::InternalLinkage; case VisibleNoLinkage: + case ModuleInternalLinkage: + case ModuleLinkage: case ExternalLinkage: // RTTI is not enabled, which means that this type info struct is going // to be used for exception handling. Give it linkonce_odr linkage. diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index e68a16e0bd..78b510bb46 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -3425,6 +3425,8 @@ static llvm::GlobalValue::LinkageTypes getLinkageForRTTI(QualType Ty) { return llvm::GlobalValue::InternalLinkage; case VisibleNoLinkage: + case ModuleInternalLinkage: + case ModuleLinkage: case ExternalLinkage: return llvm::GlobalValue::LinkOnceODRLinkage; } diff --git a/lib/Index/IndexSymbol.cpp b/lib/Index/IndexSymbol.cpp index bf358a3721..0dc3720208 100644 --- a/lib/Index/IndexSymbol.cpp +++ b/lib/Index/IndexSymbol.cpp @@ -69,11 +69,13 @@ bool index::isFunctionLocalSymbol(const Decl *D) { if (const NamedDecl *ND = dyn_cast(D)) { switch (ND->getFormalLinkage()) { case NoLinkage: - case VisibleNoLinkage: case InternalLinkage: return true; + case VisibleNoLinkage: case UniqueExternalLinkage: + case ModuleInternalLinkage: llvm_unreachable("Not a sema linkage"); + case ModuleLinkage: case ExternalLinkage: return false; } 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 c8b8725ed2..dc6a3635a8 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 @@ -1,6 +1,19 @@ // RUN: %clang_cc1 -fmodules-ts %S/module.cppm -triple %itanium_abi_triple -emit-module-interface -o %t // 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: @_ZL19static_var_exported = external global +// CHECK-DAG: @const_var_exported = external constant +// +// 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: @_ZL25static_var_module_linkage = external global +// CHECK-DAG: @_ZL24const_var_module_linkage = external constant + module Module; void use() { @@ -9,8 +22,13 @@ void use() { // CHECK: declare {{.*}}@_Z18noninline_exportedv noninline_exported(); + (void)&extern_var_exported; + (void)&inline_var_exported; + (void)&static_var_exported; // FIXME: Should not be exported. + (void)&const_var_exported; + // FIXME: This symbol should not be visible here. - // CHECK: define internal {{.*}}@_ZL26used_static_module_linkagev + // CHECK: declare {{.*}}@_ZL26used_static_module_linkagev used_static_module_linkage(); // FIXME: The module name should be mangled into the name of this function. @@ -20,4 +38,9 @@ void use() { // FIXME: The module name should be mangled into the name of this function. // CHECK: declare {{.*}}@_Z24noninline_module_linkagev noninline_module_linkage(); + + (void)&extern_var_module_linkage; + (void)&inline_var_module_linkage; + (void)&static_var_module_linkage; // FIXME: Should not be visible here. + (void)&const_var_module_linkage; } diff --git a/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm b/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm index be3644efa5..d452f741a0 100644 --- a/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm +++ b/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm @@ -1,9 +1,39 @@ -// RUN: %clang_cc1 -fmodules-ts %s -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s --implicit-check-not=unused +// RUN: %clang_cc1 -fmodules-ts %s -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s --implicit-check-not unused_inline --implicit-check-not unused_stastic_global_module + +// CHECK-DAG: @extern_var_global_module = external global +// CHECK-DAG: @inline_var_global_module = linkonce_odr global +// CHECK-DAG: @_ZL24static_var_global_module = internal global +// CHECK-DAG: @_ZL23const_var_global_module = internal constant +// +// For ABI compatibility, these symbols do not include the module name. +// CHECK-DAG: @extern_var_exported = external global +// FIXME: Should this be 'weak_odr global'? Presumably it must be, since we +// can discard this global and its initializer (if any), and other TUs are not +// permitted to run the initializer for this variable. +// CHECK-DAG: @inline_var_exported = linkonce_odr global +// CHECK-DAG: @_ZL19static_var_exported = global +// CHECK-DAG: @const_var_exported = constant +// +// FIXME: The module name should be mangled into all of these. +// CHECK-DAG: @extern_var_module_linkage = external global +// FIXME: Should this be 'weak_odr global'? Presumably it must be, since we +// can discard this global and its initializer (if any), and other TUs are not +// permitted to run the initializer for this variable. +// CHECK-DAG: @inline_var_module_linkage = linkonce_odr global +// CHECK-DAG: @_ZL25static_var_module_linkage = global +// CHECK-DAG: @_ZL24const_var_module_linkage = constant static void unused_static_global_module() {} static void used_static_global_module() {} + inline void unused_inline_global_module() {} inline void used_inline_global_module() {} + +extern int extern_var_global_module; +inline int inline_var_global_module; +static int static_var_global_module; +const int const_var_global_module = 3; + // CHECK: define void {{.*}}@_Z23noninline_global_modulev void noninline_global_module() { // FIXME: This should be promoted to module linkage and given a @@ -15,6 +45,11 @@ void noninline_global_module() { used_static_global_module(); // CHECK: define linkonce_odr {{.*}}@_Z25used_inline_global_modulev used_inline_global_module(); + + (void)&extern_var_global_module; + (void)&inline_var_global_module; + (void)&static_var_global_module; + (void)&const_var_global_module; } export module Module; @@ -22,33 +57,62 @@ export module Module; export { // FIXME: These should be ill-formed: you can't export an internal linkage // symbol, per [dcl.module.interface]p2. + // CHECK: define void {{.*}}@_ZL22unused_static_exportedv static void unused_static_exported() {} + // CHECK: define void {{.*}}@_ZL20used_static_exportedv static void used_static_exported() {} inline void unused_inline_exported() {} inline void used_inline_exported() {} + + extern int extern_var_exported; + inline int inline_var_exported; + // FIXME: This should be ill-formed: you can't export an internal linkage + // symbol. + static int static_var_exported; + const int const_var_exported = 3; + // CHECK: define void {{.*}}@_Z18noninline_exportedv void noninline_exported() { - // CHECK: define internal {{.*}}@_ZL20used_static_exportedv used_static_exported(); // CHECK: define linkonce_odr {{.*}}@_Z20used_inline_exportedv used_inline_exported(); + + (void)&extern_var_exported; + (void)&inline_var_exported; + (void)&static_var_exported; + (void)&const_var_exported; } } +// FIXME: Ideally we wouldn't emit this as its name is not visible outside this +// TU, but this module interface might contain a template that can use this +// function so we conservatively emit it for now. +// FIXME: The module name should be mangled into the name of this function. +// CHECK: define void {{.*}}@_ZL28unused_static_module_linkagev static void unused_static_module_linkage() {} +// FIXME: The module name should be mangled into the name of this function. +// CHECK: define void {{.*}}@_ZL26used_static_module_linkagev static void used_static_module_linkage() {} + inline void unused_inline_module_linkage() {} inline void used_inline_module_linkage() {} + +extern int extern_var_module_linkage; +inline int inline_var_module_linkage; +static int static_var_module_linkage; +const int const_var_module_linkage = 3; + // FIXME: The module name should be mangled into the name of this function. // CHECK: define void {{.*}}@_Z24noninline_module_linkagev void noninline_module_linkage() { - // FIXME: This should be promoted to module linkage and given a - // module-mangled name, if it's called from an inline function within - // the module interface. - // CHECK: define internal {{.*}}@_ZL26used_static_module_linkagev used_static_module_linkage(); // FIXME: The module name should be mangled into the name of this function. // CHECK: define linkonce_odr {{.*}}@_Z26used_inline_module_linkagev used_inline_module_linkage(); + + (void)&extern_var_module_linkage; + (void)&inline_var_module_linkage; + (void)&static_var_module_linkage; + (void)&const_var_module_linkage; } 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 bbd67e2c89..f6e0238c6b 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 @@ -1,6 +1,13 @@ // RUN: %clang_cc1 -fmodules-ts %S/module.cppm -triple %itanium_abi_triple -emit-module-interface -o %t // 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: @_ZL19static_var_exported = global +// CHECK-DAG: @const_var_exported = constant + import Module; void use() { @@ -9,5 +16,10 @@ void use() { // CHECK: declare {{.*}}@_Z18noninline_exportedv noninline_exported(); + (void)&extern_var_exported; + (void)&inline_var_exported; + (void)&static_var_exported; + (void)&const_var_exported; + // Module-linkage declarations are not visible here. } -- 2.40.0