[clang] 2e9977c - [C++20] [Modules] Treat module linkage as formal linkage only

Chuanqi Xu via cfe-commits cfe-commits at lists.llvm.org
Mon Mar 13 00:55:01 PDT 2023


Author: Chuanqi Xu
Date: 2023-03-13T15:54:40+08:00
New Revision: 2e9977c2815653c141c6c060c4e0ab6c0db27911

URL: https://github.com/llvm/llvm-project/commit/2e9977c2815653c141c6c060c4e0ab6c0db27911
DIFF: https://github.com/llvm/llvm-project/commit/2e9977c2815653c141c6c060c4e0ab6c0db27911.diff

LOG: [C++20] [Modules] Treat module linkage as formal linkage only

Close https://github.com/llvm/llvm-project/issues/61321

There are two linkage modes in clang now: one for internal linkage and
one for formal linkage. The internal linkage is for the implementation
details and the formal linkage is for the consistency with the C++
standard.

Since we previously implemented the strong ownership for modules, the
module linkage is not meaningful for linkers any more. So the module
linkage should only be used for formal linkage.

Added: 
    clang/test/Modules/inconsistent-export.cppm

Modified: 
    clang/include/clang/AST/Decl.h
    clang/lib/AST/Decl.cpp
    clang/unittests/AST/DeclTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index e213c5fe29c68..0585fda3a566c 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -395,9 +395,7 @@ class NamedDecl : public Decl {
 
   /// Get the linkage from a semantic point of view. Entities in
   /// anonymous namespaces are external (in c++98).
-  Linkage getFormalLinkage() const {
-    return clang::getFormalLinkage(getLinkageInternal());
-  }
+  Linkage getFormalLinkage() const;
 
   /// True if this decl has external linkage.
   bool hasExternalFormalLinkage() const {

diff  --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 240e744ee6449..484a4a294aa5e 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -605,20 +605,6 @@ static LinkageInfo getInternalLinkageFor(const NamedDecl *D) {
 }
 
 static LinkageInfo getExternalLinkageFor(const NamedDecl *D) {
-  // C++ [basic.link]p4.8:
-  //   - if the declaration of the name is attached to a named module and is not
-  //   exported
-  //     the name has module linkage;
-  //
-  // [basic.namespace.general]/p2
-  //   A namespace is never attached to a named module and never has a name with
-  //   module linkage.
-  if (isInModulePurview(D) &&
-      !isExportedFromModuleInterfaceUnit(
-          cast<NamedDecl>(D->getCanonicalDecl())) &&
-      !isa<NamespaceDecl>(D))
-    return LinkageInfo(ModuleLinkage, DefaultVisibility, false);
-
   return LinkageInfo::external();
 }
 
@@ -1165,6 +1151,29 @@ Linkage NamedDecl::getLinkageInternal() const {
       .getLinkage();
 }
 
+/// Get the linkage from a semantic point of view. Entities in
+/// anonymous namespaces are external (in c++98).
+Linkage NamedDecl::getFormalLinkage() const {
+  Linkage InternalLinkage = getLinkageInternal();
+
+  // C++ [basic.link]p4.8:
+  //   - if the declaration of the name is attached to a named module and is not
+  //   exported
+  //     the name has module linkage;
+  //
+  // [basic.namespace.general]/p2
+  //   A namespace is never attached to a named module and never has a name with
+  //   module linkage.
+  if (isInModulePurview(this) &&
+      InternalLinkage == ExternalLinkage &&
+      !isExportedFromModuleInterfaceUnit(
+          cast<NamedDecl>(this->getCanonicalDecl())) &&
+      !isa<NamespaceDecl>(this))
+    InternalLinkage = ModuleLinkage;
+
+  return clang::getFormalLinkage(InternalLinkage);
+}
+
 LinkageInfo NamedDecl::getLinkageAndVisibility() const {
   return LinkageComputer{}.getDeclLinkageAndVisibility(this);
 }

diff  --git a/clang/test/Modules/inconsistent-export.cppm b/clang/test/Modules/inconsistent-export.cppm
new file mode 100644
index 0000000000000..5e94d2b37b757
--- /dev/null
+++ b/clang/test/Modules/inconsistent-export.cppm
@@ -0,0 +1,46 @@
+// RUN: rm -fr %t
+// RUN: mkdir %t
+// RUN: split-file %s %t
+//
+// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-module-interface -o %t/m-a.pcm
+// RUN: %clang_cc1 -std=c++20 %t/b.cppm -emit-module-interface -o %t/m-b.pcm \
+// RUN:     -fprebuilt-module-path=%t
+// RUN: %clang_cc1 -std=c++20 %t/m.cppm -emit-module-interface -o %t/m.pcm \
+// RUN:     -fprebuilt-module-path=%t
+// RUN: %clang_cc1 -std=c++20 %t/use.cppm -fprebuilt-module-path=%t -emit-obj
+
+//--- a.cppm
+export module m:a;
+namespace n {
+export class a {
+public:
+    virtual ~a() {}
+};
+}
+
+//--- b.cppm
+export module m:b;
+namespace n {
+class a;
+}
+
+//--- m.cppm
+export module m;
+export import :a;
+export import :b;
+
+//--- use.cppm
+// expected-no-diagnostics
+export module u;
+export import m;
+
+struct aa : public n::a {
+    aa() {}
+};
+auto foo(n::a*) {
+    return;
+}
+
+void use() {
+    n::a _;
+}

diff  --git a/clang/unittests/AST/DeclTest.cpp b/clang/unittests/AST/DeclTest.cpp
index 119551bb44453..a6535119afb53 100644
--- a/clang/unittests/AST/DeclTest.cpp
+++ b/clang/unittests/AST/DeclTest.cpp
@@ -232,16 +232,16 @@ TEST(Decl, ModuleAndInternalLinkage) {
   const auto *f = selectFirst<FunctionDecl>(
       "f", match(functionDecl(hasName("f")).bind("f"), Ctx));
 
-  EXPECT_EQ(a->getLinkageInternal(), InternalLinkage);
-  EXPECT_EQ(f->getLinkageInternal(), InternalLinkage);
+  EXPECT_EQ(a->getFormalLinkage(), InternalLinkage);
+  EXPECT_EQ(f->getFormalLinkage(), InternalLinkage);
 
   const auto *b =
       selectFirst<VarDecl>("b", match(varDecl(hasName("b")).bind("b"), Ctx));
   const auto *g = selectFirst<FunctionDecl>(
       "g", match(functionDecl(hasName("g")).bind("g"), Ctx));
 
-  EXPECT_EQ(b->getLinkageInternal(), ModuleLinkage);
-  EXPECT_EQ(g->getLinkageInternal(), ModuleLinkage);
+  EXPECT_EQ(b->getFormalLinkage(), ModuleLinkage);
+  EXPECT_EQ(g->getFormalLinkage(), ModuleLinkage);
 
   AST = tooling::buildASTFromCodeWithArgs(
       Code.code(), /*Args=*/{"-std=c++20"});
@@ -250,15 +250,15 @@ TEST(Decl, ModuleAndInternalLinkage) {
   f = selectFirst<FunctionDecl>(
       "f", match(functionDecl(hasName("f")).bind("f"), CtxTS));
 
-  EXPECT_EQ(a->getLinkageInternal(), InternalLinkage);
-  EXPECT_EQ(f->getLinkageInternal(), InternalLinkage);
+  EXPECT_EQ(a->getFormalLinkage(), InternalLinkage);
+  EXPECT_EQ(f->getFormalLinkage(), InternalLinkage);
 
   b = selectFirst<VarDecl>("b", match(varDecl(hasName("b")).bind("b"), CtxTS));
   g = selectFirst<FunctionDecl>(
       "g", match(functionDecl(hasName("g")).bind("g"), CtxTS));
 
-  EXPECT_EQ(b->getLinkageInternal(), ModuleLinkage);
-  EXPECT_EQ(g->getLinkageInternal(), ModuleLinkage);
+  EXPECT_EQ(b->getFormalLinkage(), ModuleLinkage);
+  EXPECT_EQ(g->getFormalLinkage(), ModuleLinkage);
 }
 
 TEST(Decl, GetNonTransparentDeclContext) {


        


More information about the cfe-commits mailing list