diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 12fe5516883eb..4507f415ce606 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1604,17 +1604,20 @@ LinkageInfo LinkageComputer::getLVForDecl(const NamedDecl *D, // We have just computed the linkage for this decl. By induction we know // that all other computed linkages match, check that the one we just // computed also does. - NamedDecl *Old = nullptr; - for (auto *I : D->redecls()) { - auto *T = cast(I); - if (T == D) + // We can't assume the redecl chain is well formed at this point, + // so keep track of already visited declarations. + for (llvm::SmallPtrSet AlreadyVisited{D}; /**/; /**/) { + D = cast(const_cast(D)->getNextRedeclarationImpl()); + if (!AlreadyVisited.insert(D).second) + break; + if (D->isInvalidDecl()) continue; - if (!T->isInvalidDecl() && T->hasCachedLinkage()) { - Old = T; + if (auto OldLinkage = D->getCachedLinkage(); + OldLinkage != Linkage::Invalid) { + assert(LV.getLinkage() == OldLinkage); break; } } - assert(!Old || Old->getCachedLinkage() == D->getCachedLinkage()); #endif return LV; diff --git a/clang/test/Modules/GH153933.cpp b/clang/test/Modules/GH153933.cpp new file mode 100644 index 0000000000000..41184c6b00607 --- /dev/null +++ b/clang/test/Modules/GH153933.cpp @@ -0,0 +1,23 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 %t/B.cppm -emit-module-interface -o %t/B.pcm +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fprebuilt-module-path=%t %t/C.cpp + +//--- A.hpp +template struct A {}; +template struct B { + virtual A v() { return {}; } +}; +B x; + +//--- B.cppm +module; +#include "A.hpp" +export module B; +using ::x; + +//--- C.cpp +#include "A.hpp" +import B;