[modules ts] Basic for module linkage.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 7 Jul 2017 20:04:28 +0000 (20:04 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 7 Jul 2017 20:04:28 +0000 (20:04 +0000)
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.

llvm-svn: 307434

clang/include/clang/Basic/Linkage.h
clang/lib/AST/Decl.cpp
clang/lib/CodeGen/CodeGenModule.cpp
clang/lib/CodeGen/ItaniumCXXABI.cpp
clang/lib/CodeGen/MicrosoftCXXABI.cpp
clang/lib/Index/IndexSymbol.cpp
clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp
clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm
clang/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp

index e96fb56..6ec8763 100644 (file)
@@ -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) {
index 24d9983..573a98e 100644 (file)
@@ -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<VarDecl>(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<IndirectFieldDecl>(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<VarDecl>(D);
     const auto *Func = dyn_cast<FunctionDecl>(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<NamespaceDecl>(D) && !D->isInAnonymousNamespace()) {
+  //
+  // We handled names in anonymous namespaces above.
+  } else if (isa<NamespaceDecl>(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<NamedDecl>(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<InternalLinkageAttr>())
-    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<CXXRecordDecl>(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<InternalLinkageAttr>())
-      return LinkageInfo::internal();
+      return getInternalLinkageFor(D);
 
     if (computation == LVForLinkageOnly && D->hasCachedLinkage())
       return LinkageInfo(D->getCachedLinkage(), DefaultVisibility, false);
index 20d945f..10838b7 100644 (file)
@@ -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<DLLImportAttr>()) {
index e6d38af..c82b967 100644 (file)
@@ -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.
index e68a16e..78b510b 100644 (file)
@@ -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;
   }
index bf358a3..0dc3720 100644 (file)
@@ -69,11 +69,13 @@ bool index::isFunctionLocalSymbol(const Decl *D) {
   if (const NamedDecl *ND = dyn_cast<NamedDecl>(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;
     }
index c8b8725..dc6a363 100644 (file)
@@ -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;
 }
index be3644e..d452f74 100644 (file)
@@ -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;
 }
index bbd67e2..f6e0238 100644 (file)
@@ -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.
 }