From cc5185bd146bed96d0d9e23263a56b6965d8572f Mon Sep 17 00:00:00 2001 From: Chuanqi Xu Date: Fri, 21 Nov 2025 13:55:32 +0800 Subject: [C++20] [Modules] Check TULocal entity within exported entities See the attached test for example. --- clang/lib/Sema/SemaModule.cpp | 21 ++++++++++++++++++++- clang/test/Modules/reference-tu-local-var.cppm | 9 +++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 clang/test/Modules/reference-tu-local-var.cppm (limited to 'clang') diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp index a2aa3eaaa7f6..cbe37cd47793 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(TopD)) { + checkExposureInContext(Export); + continue; + } + + if (auto *LinkageSpec = dyn_cast(TopD)) { + checkExposureInContext(LinkageSpec); + continue; + } + auto *TopND = dyn_cast(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 000000000000..74a74d6b2f65 --- /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}} +} -- cgit v1.2.3