[clang] cc5185b - [C++20] [Modules] Check TULocal entity within exported entities

Chuanqi Xu via cfe-commits cfe-commits at lists.llvm.org
Thu Nov 20 21:58:08 PST 2025


Author: Chuanqi Xu
Date: 2025-11-21T13:57:41+08:00
New Revision: cc5185bd146bed96d0d9e23263a56b6965d8572f

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

LOG: [C++20] [Modules] Check TULocal entity within exported entities

See the attached test for example.

Added: 
    clang/test/Modules/reference-tu-local-var.cppm

Modified: 
    clang/lib/Sema/SemaModule.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp
index a2aa3eaaa7f6d..cbe37cd47793b 100644
--- a/clang/lib/Sema/SemaModule.cpp
+++ b/clang/lib/Sema/SemaModule.cpp
@@ -1282,7 +1282,16 @@ bool ExposureChecker::isExposureCandidate(const NamedDecl *D) {
   //   (outside the private-module-fragment, if any) or
   //   module partition is an exposure, the program is ill-formed.
   Module *M = D->getOwningModule();
-  if (!M || !M->isInterfaceOrPartition())
+  if (!M)
+    return false;
+  // If M is implicit global module, the declaration must be in the purview of
+  // a module unit.
+  if (M->isImplicitGlobalModule()) {
+    M = M->Parent;
+    assert(M && "Implicit global module must have a parent");
+  }
+
+  if (!M->isInterfaceOrPartition())
     return false;
 
   if (D->isImplicit())
@@ -1495,6 +1504,16 @@ bool ExposureChecker::checkExposure(const Stmt *S, bool Diag) {
 
 void ExposureChecker::checkExposureInContext(const DeclContext *DC) {
   for (auto *TopD : DC->noload_decls()) {
+    if (auto *Export = dyn_cast<ExportDecl>(TopD)) {
+      checkExposureInContext(Export);
+      continue;
+    }
+
+    if (auto *LinkageSpec = dyn_cast<LinkageSpecDecl>(TopD)) {
+      checkExposureInContext(LinkageSpec);
+      continue;
+    }
+
     auto *TopND = dyn_cast<NamedDecl>(TopD);
     if (!TopND)
       continue;

diff  --git a/clang/test/Modules/reference-tu-local-var.cppm b/clang/test/Modules/reference-tu-local-var.cppm
new file mode 100644
index 0000000000000..74a74d6b2f650
--- /dev/null
+++ b/clang/test/Modules/reference-tu-local-var.cppm
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -std=c++23 %s -verify -fsyntax-only
+export module M;
+static int local;
+export inline int exposure1() { return local; } // expected-warning {{TU local entity 'local' is exposed}}
+
+static int local2 = 43;
+export extern "C++" {
+inline int exposure2() { return local2; } // expected-warning {{TU local entity 'local2' is exposed}}
+}


        


More information about the cfe-commits mailing list