https://github.com/ChuanqiXu9 created https://github.com/llvm/llvm-project/pull/219926
Close https://github.com/llvm/llvm-project/issues/219639 The root cause of the problem is the incorrect redecl chain. A valid redecl chain should be a circle where each decl refers to the previous one and the first decl refers to the most recent decl (latest one). However, in the example, the redecl chain became to: D2 -> D1 -> D1 .... so that the range of `for (... : D->redecls())` never ends. The real cause of the issue is we didn't merge correctly in the ASTReader. Previous code assumes about the most recent decl while the new code makes the behavior more clearly. >From 039b1d2534310893bda9b2bc78ac0607699e5ea7 Mon Sep 17 00:00:00 2001 From: Chuanqi Xu <[email protected]> Date: Mon, 31 Aug 2026 17:29:35 +0800 Subject: [PATCH] [C++20] [Modules] Correct the redecl chain Close https://github.com/llvm/llvm-project/issues/219639 The root cause of the problem is the incorrect redecl chain. A valid redecl chain should be a circle where each decl refers to the previous one and the first decl refers to the most recent decl (latest one). However, in the example, the redecl chain became to: D2 -> D1 -> D1 .... so that the range of `for (... : D->redecls())` never ends. The real cause of the issue is we didn't merge correctly in the ASTReader. Previous code assumes about the most recent decl while the new code makes the behavior more clearly. --- clang/lib/Serialization/ASTReaderDecl.cpp | 15 ++++---- clang/test/Modules/pr219639.cppm | 45 +++++++++++++++++++++++ 2 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 clang/test/Modules/pr219639.cppm diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index d27aa1dd64268..d4c47a81ed32f 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -4616,17 +4616,19 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { } void ASTReader::loadPendingDeclChain(Decl *FirstLocal, uint64_t LocalOffset) { - // Attach FirstLocal to the end of the decl chain. Decl *CanonDecl = FirstLocal->getCanonicalDecl(); + + Decl *MostRecent = ASTDeclReader::getMostRecentDecl(CanonDecl); + if (!MostRecent) + MostRecent = CanonDecl; if (FirstLocal != CanonDecl) { - Decl *PrevMostRecent = ASTDeclReader::getMostRecentDecl(CanonDecl); - ASTDeclReader::attachPreviousDecl( - *this, FirstLocal, PrevMostRecent ? PrevMostRecent : CanonDecl, - CanonDecl); + // Attach FirstLocal to the end of the decl chain. + ASTDeclReader::attachPreviousDecl(*this, FirstLocal, MostRecent, CanonDecl); + MostRecent = FirstLocal; } if (!LocalOffset) { - ASTDeclReader::attachLatestDecl(CanonDecl, FirstLocal); + ASTDeclReader::attachLatestDecl(CanonDecl, MostRecent); return; } @@ -4658,7 +4660,6 @@ void ASTReader::loadPendingDeclChain(Decl *FirstLocal, uint64_t LocalOffset) { // FIXME: We have several different dispatches on decl kind here; maybe // we should instead generate one loop per kind and dispatch up-front? - Decl *MostRecent = FirstLocal; for (unsigned I = 0, N = Record.size(); I != N; ++I) { unsigned Idx = N - I - 1; auto *D = ReadDecl(*M, Record, Idx); diff --git a/clang/test/Modules/pr219639.cppm b/clang/test/Modules/pr219639.cppm new file mode 100644 index 0000000000000..bdc2f6441e92a --- /dev/null +++ b/clang/test/Modules/pr219639.cppm @@ -0,0 +1,45 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/M.cppm -o %t/M.pcm +// RUN: %clang_cc1 -std=c++20 -emit-module-interface -fmodule-file=M=%t/M.pcm %t/B.cppm -o %t/B.pcm +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fmodule-file=M=%t/M.pcm -fmodule-file=B=%t/B.pcm %t/A.cppm +// +// Test again with reduced BMI +// RUN: %clang_cc1 -std=c++20 -emit-reduced-module-interface %t/M.cppm -o %t/M.pcm +// RUN: %clang_cc1 -std=c++20 -emit-reduced-module-interface -fmodule-file=M=%t/M.pcm %t/B.cppm -o %t/B.pcm +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fmodule-file=M=%t/M.pcm -fmodule-file=B=%t/B.pcm %t/A.cppm + +//--- decls.h +void f(int); + +namespace N { +inline namespace I { +void f(); +using ::f; +} // namespace I +} // namespace N + +//--- M.cppm +module; +#include "decls.h" + +export module M; + +export namespace N { using N::f; } +export namespace N { using N::f; } + +//--- B.cppm +export module B; + +import M; + +//--- A.cppm +module; +#include "decls.h" + +export module A; + +import B; + +export void test() { N::f(); } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
