https://github.com/VitorRamos updated https://github.com/llvm/llvm-project/pull/197928
>From f5bc8d2f166fdb4dc03ef610483f7be3ebd8faf1 Mon Sep 17 00:00:00 2001 From: vitorramos89 <[email protected]> Date: Thu, 14 May 2026 20:11:55 -0300 Subject: [PATCH 1/2] [clang][CodeGen] Fix crash in CGDebugInfo on incomplete record type (#156352) Fix a crash when generating debug info for a template class that is still being defined when its forward declaration is needed. getTypeIdentifier() called getVTableLinkage() on a record that was only "being defined" (not yet complete), which triggered premature ASTRecordLayout computation and cached a layout with zero fields. Later, CollectRecordFields used the stale cached layout and crashed on an out-of-bounds field offset access. Replace getDefinition() with isCompleteDefinition() to correctly skip records whose definition is not yet complete. Fixes #156352 --- clang/lib/CodeGen/CGDebugInfo.cpp | 2 +- .../debug-info-template-incomplete-record.cpp | 83 +++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 clang/test/CodeGenCXX/debug-info-template-incomplete-record.cpp diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 578d09f7971d6..71a21f19fbd5b 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1290,7 +1290,7 @@ static SmallString<256> getTypeIdentifier(const TagType *Ty, CodeGenModule &CGM, if (!needsTypeIdentifier(TD, CGM, TheCU)) return Identifier; if (const auto *RD = dyn_cast<CXXRecordDecl>(TD)) - if (RD->getDefinition()) + if (RD->isCompleteDefinition()) if (RD->isDynamicClass() && CGM.getVTableLinkage(RD) == llvm::GlobalValue::ExternalLinkage) return Identifier; diff --git a/clang/test/CodeGenCXX/debug-info-template-incomplete-record.cpp b/clang/test/CodeGenCXX/debug-info-template-incomplete-record.cpp new file mode 100644 index 0000000000000..f81433d53d296 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-template-incomplete-record.cpp @@ -0,0 +1,83 @@ +// RUN: %clang_cc1 -std=c++20 -debug-info-kind=standalone -fvisibility=hidden \ +// RUN: -O2 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s +// +// Verify that we don't crash when generating debug info for a template class +// that is still being defined when its forward declaration is needed. The bug +// was that getTypeIdentifier() called getVTableLinkage() on a record that was +// only "being defined" (not yet complete), which triggered premature +// ASTRecordLayout computation and cached a layout with zero fields. Later, +// CollectRecordFields used the stale cached layout and crashed on an +// out-of-bounds field offset access. + +class a; +template<class> +class b; +class c +{ +public: + using d = a; +}; +template<class> +class f; +template<class e> +class h +{ + using j = typename e::j; + j k(); +}; +class l; +class m +{ + using i = f<l>; + i n(); +}; +template<class> +class f +{ +public: + using e = l; + using o = e; + using d = b<e>; + d *p; +}; +class L; +class q +{ +public: + using j = L; +}; +class r +{ + ~r(); + h<q> s; +}; +r::~r() = default; +class l +{ +public: + using j = m; + using g = c; +}; +class J +{ + h<l> t; +}; +class a +{ +public: + virtual ~a(); +}; +template<class e> +class b : e::g::d +{ + using u = typename f<e>::o; + int v; +}; +class L : J +{ +}; +extern template class b<l>; + +// Just verify we produce debug info for b<l> with its field v. +// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "b<l>" +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "v" >From f9abd8091568af108162c5d0316f41df5107be8b Mon Sep 17 00:00:00 2001 From: Vitor Ramos Gomes Da Silva <[email protected]> Date: Fri, 15 May 2026 15:41:37 +0000 Subject: [PATCH 2/2] Reduced test-case --- .../debug-info-template-incomplete-record.cpp | 111 +++++------------- 1 file changed, 30 insertions(+), 81 deletions(-) diff --git a/clang/test/CodeGenCXX/debug-info-template-incomplete-record.cpp b/clang/test/CodeGenCXX/debug-info-template-incomplete-record.cpp index f81433d53d296..4c914f8747857 100644 --- a/clang/test/CodeGenCXX/debug-info-template-incomplete-record.cpp +++ b/clang/test/CodeGenCXX/debug-info-template-incomplete-record.cpp @@ -1,83 +1,32 @@ -// RUN: %clang_cc1 -std=c++20 -debug-info-kind=standalone -fvisibility=hidden \ -// RUN: -O2 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -std=c++17 -debug-info-kind=standalone -O2 \ +// RUN: -triple x86_64-linux-gnu -emit-llvm %s -o /dev/null // -// Verify that we don't crash when generating debug info for a template class -// that is still being defined when its forward declaration is needed. The bug -// was that getTypeIdentifier() called getVTableLinkage() on a record that was -// only "being defined" (not yet complete), which triggered premature -// ASTRecordLayout computation and cached a layout with zero fields. Later, -// CollectRecordFields used the stale cached layout and crashed on an -// out-of-bounds field offset access. - -class a; -template<class> -class b; -class c -{ -public: - using d = a; -}; -template<class> -class f; -template<class e> -class h -{ - using j = typename e::j; - j k(); -}; -class l; -class m -{ - using i = f<l>; - i n(); -}; -template<class> -class f -{ -public: - using e = l; - using o = e; - using d = b<e>; - d *p; -}; -class L; -class q -{ -public: - using j = L; -}; -class r -{ - ~r(); - h<q> s; -}; -r::~r() = default; -class l -{ -public: - using j = m; - using g = c; -}; -class J -{ - h<l> t; -}; -class a -{ -public: - virtual ~a(); -}; -template<class e> -class b : e::g::d -{ - using u = typename f<e>::o; - int v; -}; -class L : J -{ -}; -extern template class b<l>; +// REQUIRES: asserts +// +// Verify we don't crash when generating debug info for a polymorphic +// template class that is still being defined when its type identifier is +// requested. +// +// getTypeIdentifier() called getVTableLinkage() on a record that was only +// "being defined" (not yet complete). getVTableLinkage() in turn calls +// ItaniumCXXABI::canSpeculativelyEmitVTable(), which builds the vtable +// layout via FinalOverriders, which calls getASTRecordLayout() on the +// incomplete type, triggering: +// Assertion `D->isCompleteDefinition() && +// "Cannot layout type before complete!"' failed. +// In release (no-asserts) builds the same path silently caches a layout +// with zero fields, leading to an out-of-bounds field offset crash later +// in CollectRecordFields. -// Just verify we produce debug info for b<l> with its field v. -// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "b<l>" -// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "v" +struct l; +template <typename> struct b; +template <typename> struct f { + struct e; + b<l> *p; +}; +template <typename e> struct b { + virtual ~b(); + typename f<e>::e x(); +}; +f<l> *s; +extern template struct b<l>; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
