Author: Chuanqi Xu Date: 2026-08-31T10:18:34Z New Revision: 08eb97dea196ec5bc76c231c97e7810bfe86ec4b
URL: https://github.com/llvm/llvm-project/commit/08eb97dea196ec5bc76c231c97e7810bfe86ec4b DIFF: https://github.com/llvm/llvm-project/commit/08eb97dea196ec5bc76c231c97e7810bfe86ec4b.diff LOG: [C++20] [Modules] Correct the redecl chain (#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. Added: clang/test/Modules/pr219639.cppm Modified: clang/lib/Serialization/ASTReaderDecl.cpp Removed: ################################################################################ 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 diff erent 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
