[clang] c560f1c - [Serialization] Stop demote var definition as declaration (#172430)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 13 18:54:08 PST 2026
Author: Chuanqi Xu
Date: 2026-01-14T02:54:03Z
New Revision: c560f1cf03aa06c0bdd00c5a9b558c16d882af6f
URL: https://github.com/llvm/llvm-project/commit/c560f1cf03aa06c0bdd00c5a9b558c16d882af6f
DIFF: https://github.com/llvm/llvm-project/commit/c560f1cf03aa06c0bdd00c5a9b558c16d882af6f.diff
LOG: [Serialization] Stop demote var definition as declaration (#172430)
Close https://github.com/llvm/llvm-project/issues/172241
Close https://github.com/llvm/llvm-project/issues/64034
Close https://github.com/llvm/llvm-project/issues/149404
Close https://github.com/llvm/llvm-project/issues/174858
After this patch, we (the clang dev) no longer assumes there are at
most one definition in a redeclaration chain.
See
https://discourse.llvm.org/t/rfc-clang-not-assuming-there-is-at-most-one-definition-in-a-redeclaration-chain/89360
for details.
Added:
clang/test/Modules/pr149404-02.cppm
clang/test/Modules/pr172241.cppm
Modified:
clang/lib/Serialization/ASTReaderDecl.cpp
Removed:
################################################################################
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index f8e9caa3f5d1d..f0fb247f1afb9 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -3642,23 +3642,9 @@ template<>
void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader,
Redeclarable<VarDecl> *D,
Decl *Previous, Decl *Canon) {
- auto *VD = static_cast<VarDecl *>(D);
auto *PrevVD = cast<VarDecl>(Previous);
D->RedeclLink.setPrevious(PrevVD);
D->First = PrevVD->First;
-
- // We should keep at most one definition on the chain.
- // FIXME: Cache the definition once we've found it. Building a chain with
- // N definitions currently takes O(N^2) time here.
- if (VD->isThisDeclarationADefinition() == VarDecl::Definition) {
- for (VarDecl *CurD = PrevVD; CurD; CurD = CurD->getPreviousDecl()) {
- if (CurD->isThisDeclarationADefinition() == VarDecl::Definition) {
- Reader.mergeDefinitionVisibility(CurD, VD);
- VD->demoteThisDefinitionToDeclaration();
- break;
- }
- }
- }
}
static bool isUndeducedReturnType(QualType T) {
diff --git a/clang/test/Modules/pr149404-02.cppm b/clang/test/Modules/pr149404-02.cppm
new file mode 100644
index 0000000000000..291619ea05b8a
--- /dev/null
+++ b/clang/test/Modules/pr149404-02.cppm
@@ -0,0 +1,104 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface -o %t/format.pcm %t/format.cppm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface -o %t/includes_in_gmf.pcm %t/includes_in_gmf.cppm
+// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %t/test.cpp -verify -fsyntax-only
+
+// RUN: %clang_cc1 -std=c++20 -emit-reduced-module-interface -o %t/format.pcm %t/format.cppm
+// RUN: %clang_cc1 -std=c++20 -emit-reduced-module-interface -o %t/includes_in_gmf.pcm %t/includes_in_gmf.cppm
+// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %t/test.cpp -verify -fsyntax-only
+
+//--- format.h
+#pragma once
+
+namespace test {
+
+template <class _Tp>
+struct type_identity {
+ typedef _Tp type;
+};
+
+template <class _Tp>
+using type_identity_t = typename type_identity<_Tp>::type;
+
+
+template <class _Tp, class _CharT>
+struct formatter
+{
+ formatter() = delete;
+};
+
+template <>
+struct formatter<char, char>
+{};
+
+template <class _CharT, class... _Args>
+struct basic_format_string {
+ static inline const int __handles_{ [] {
+ formatter<char, _CharT> f;
+ (void)f;
+ return 0;
+ }() };
+
+ consteval basic_format_string(const _CharT*) {
+ (void)__handles_;
+ }
+};
+
+template <class... _Args>
+using wformat_string = basic_format_string<wchar_t, type_identity_t<_Args>...>;
+
+template <class... _Args>
+using format_string = basic_format_string<char, type_identity_t<_Args>...>;
+
+template <class... _Args>
+void format(format_string<_Args...> __fmt, _Args&&... __args) {}
+
+template <class... _Args>
+void format(wformat_string<_Args...> __fmt, _Args&&... __args) {}
+
+}
+
+//--- format.cppm
+module;
+#include "format.h"
+export module format;
+
+export namespace test {
+ using test::format;
+ using test::formatter;
+ using test::format_string;
+}
+
+auto something() -> void
+{
+ auto a = 'a';
+ test::format("{}", a);
+}
+
+//--- includes_in_gmf.cppm
+module;
+#include "format.h"
+export module includes_in_gmf;
+
+namespace test {
+ using test::format;
+ using test::formatter;
+ using test::format_string;
+}
+
+//--- test.cpp
+// expected-no-diagnostics
+import format;
+import includes_in_gmf;
+
+auto what() -> void
+{
+ auto a = 'a';
+ test::format("{}", a);
+
+ constexpr auto fs = "{}"; // test::format_string<char>{ "{}" }; // <- same result even passing exact param type
+ test::format(fs, 'r');
+}
diff --git a/clang/test/Modules/pr172241.cppm b/clang/test/Modules/pr172241.cppm
new file mode 100644
index 0000000000000..3eb885e8b2d9f
--- /dev/null
+++ b/clang/test/Modules/pr172241.cppm
@@ -0,0 +1,47 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+//
+// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %t/m.cppm -emit-module-interface -o %t/m.pcm
+// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %t/use.cpp -fmodule-file=m=%t/m.pcm -emit-llvm -o - | FileCheck %t/use.cpp
+//
+// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %t/m.cppm -emit-reduced-module-interface -o %t/m.pcm
+// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %t/use.cpp -fmodule-file=m=%t/m.pcm -emit-llvm -o - | FileCheck %t/use.cpp
+
+//--- header.h
+#pragma once
+
+template <unsigned T>
+class Templ {
+public:
+ void lock() { __set_locked_bit(); }
+
+private:
+ static constexpr auto __set_locked_bit = [](){};
+};
+
+class JT {
+public:
+ ~JT() {
+ Templ<4> state;
+ state.lock();
+ }
+};
+
+//--- m.cppm
+module;
+#include "header.h"
+export module m;
+export struct M {
+ JT jt;
+};
+//--- use.cpp
+#include "header.h"
+import m;
+
+int main() {
+ M m;
+ return 0;
+}
+
+// CHECK: @_ZN5TemplILj4EE16__set_locked_bitE = {{.*}}linkonce_odr
More information about the cfe-commits
mailing list