[clang] [C++20] [Modules] Don't update MarkAsUsed information for decls from named modules (PR #174687)
Chuanqi Xu via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 6 18:55:24 PST 2026
https://github.com/ChuanqiXu9 created https://github.com/llvm/llvm-project/pull/174687
Declarations from named modules are used naturally. Thet are declarations in other TU. We don't need to record the information for updating them.
>From 12768cb8dcf0b1675cf2c0193dd7ee8256ee2ef6 Mon Sep 17 00:00:00 2001
From: Chuanqi Xu <yedeng.yd at linux.alibaba.com>
Date: Wed, 7 Jan 2026 10:53:31 +0800
Subject: [PATCH] [C++20] [Modules] Don't update MarkAsUsed information for
decls from named modules
Declarations from named modules are used naturally. Thet are
declarations in other TU. We don't need to record the information for
updating them.
---
clang/lib/Serialization/ASTWriter.cpp | 4 ++
.../Modules/class-instantiate-no-change.cppm | 50 +++++++++++++++++++
2 files changed, 54 insertions(+)
create mode 100644 clang/test/Modules/class-instantiate-no-change.cppm
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index f9176b7e68f73..a211e98667829 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -7769,6 +7769,10 @@ void ASTWriter::DeclarationMarkedUsed(const Decl *D) {
if (Chain && Chain->isProcessingUpdateRecords()) return;
assert(!WritingAST && "Already writing the AST!");
+ // If the declaration comes from module unit, it is meaningless to mark it as used.
+ if (auto *M = D->getOwningModule(); M && M->getTopLevelModule()->isNamedModule())
+ return;
+
// If there is *any* declaration of the entity that's not from an AST file,
// we can skip writing the update record. We make sure that isUsed() triggers
// completion of the redeclaration chain of the entity.
diff --git a/clang/test/Modules/class-instantiate-no-change.cppm b/clang/test/Modules/class-instantiate-no-change.cppm
new file mode 100644
index 0000000000000..6ea7d24252ab5
--- /dev/null
+++ b/clang/test/Modules/class-instantiate-no-change.cppm
@@ -0,0 +1,50 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+
+// RUN: %clang_cc1 -std=c++20 %t/impl.cppm -emit-reduced-module-interface -o %t/impl.pcm
+// RUN: %clang_cc1 -std=c++20 %t/impl.v2.cppm -emit-reduced-module-interface -o %t/impl.v2.pcm
+// RUN: %clang_cc1 -std=c++20 %t/m.cppm -emit-reduced-module-interface -o %t/m.pcm \
+// RUN: -fmodule-file=impl=%t/impl.pcm
+// RUN: %clang_cc1 -std=c++20 %t/m.cppm -emit-reduced-module-interface -o %t/m.v2.pcm \
+// RUN: -fmodule-file=impl=%t/impl.v2.pcm
+
+// Since m only uses impl in the definition, the change in impl shouldn't affect m.
+// RUN: diff %t/m.pcm %t/m.v2.pcm &> /dev/null
+
+//--- impl.cppm
+export module impl;
+export struct Impl {
+ Impl() {}
+ Impl(const Impl &) {}
+ ~Impl() {}
+ int get() {
+ return 43;
+ }
+};
+
+//--- impl.v2.cppm
+export module impl;
+export struct Impl {
+ Impl() {}
+ Impl(const Impl &) {}
+ ~Impl() {}
+ int get() {
+ return 43;
+ }
+};
+
+export struct ImplV2 {
+ int get() {
+ return 43;
+ }
+};
+
+//--- m.cppm
+export module m;
+import impl;
+
+export int interface() {
+ Impl impl;
+ return impl.get();
+};
More information about the cfe-commits
mailing list