[clang] [DebugInfo] Produce debuginfo for nested types when the outer type is [[clang::standalone_debug]] (PR #146175)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 27 16:15:12 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
@llvm/pr-subscribers-debuginfo
Author: Kyle Huey (khuey)
<details>
<summary>Changes</summary>
Without this, it's impossible to get debuginfo for a nested type that is unused (or that clang mistakenly believes is unused due to e.g. deficiencies in -debug-info-kind=limited), even by marking the "unused" nested type itself with [[clang::standalone_debug]]. This makes writing pretty-printers and similar things difficult.
The [[clang::standalone_debug]] attribute is not propagated to the nested type. But after applying [[clang::standalone_debug]] to the outer type to ensure the nested type appears in the debuginfo at all, a developer can also additionally apply the attribute to the nested type if desired.
---
Full diff: https://github.com/llvm/llvm-project/pull/146175.diff
2 Files Affected:
- (modified) clang/lib/CodeGen/CGDebugInfo.cpp (+4-3)
- (added) clang/test/CodeGenCXX/standalone-debug-attribute-limited.cpp (+29)
``````````diff
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 7ab0e2fdaa731..d28bbcd9d9835 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -2075,12 +2075,13 @@ void CGDebugInfo::CollectRecordFields(
// Bump field number for next field.
++fieldNo;
- } else if (CGM.getCodeGenOpts().EmitCodeView) {
+ } else if (CGM.getCodeGenOpts().EmitCodeView ||
+ record->hasAttr<StandaloneDebugAttr>()) {
// Debug info for nested types is included in the member list only for
- // CodeView.
+ // CodeView and types with the standalone_debug attribute.
if (const auto *nestedType = dyn_cast<TypeDecl>(I)) {
// MSVC doesn't generate nested type for anonymous struct/union.
- if (isa<RecordDecl>(I) &&
+ if (CGM.getCodeGenOpts().EmitCodeView && isa<RecordDecl>(I) &&
cast<RecordDecl>(I)->isAnonymousStructOrUnion())
continue;
if (!nestedType->isImplicit() &&
diff --git a/clang/test/CodeGenCXX/standalone-debug-attribute-limited.cpp b/clang/test/CodeGenCXX/standalone-debug-attribute-limited.cpp
new file mode 100644
index 0000000000000..43ec35db18c7d
--- /dev/null
+++ b/clang/test/CodeGenCXX/standalone-debug-attribute-limited.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -DSETATTR=0 -triple x86_64-unknown-linux-gnu -emit-llvm -debug-info-kind=limited %s -o - | FileCheck %s --check-prefix=DEBUG
+// RUN: %clang_cc1 -DSETATTR=1 -triple x86_64-unknown-linux-gnu -emit-llvm -debug-info-kind=limited %s -o - | FileCheck %s --check-prefix=WITHATTR
+// Use -debug-info-kind=limited because an unused type will never have a used ctor.
+
+#if SETATTR
+#define STANDALONEDEBUGATTR __attribute__((standalone_debug))
+#else
+#define STANDALONEDEBUGATTR
+#endif
+
+struct STANDALONEDEBUGATTR TypeWithNested {
+ struct Unused1 {
+ };
+ struct STANDALONEDEBUGATTR Unused2 {
+ };
+
+ int value = 0;
+};
+void f(TypeWithNested s) {}
+// DEBUG: !DICompositeType(tag: DW_TAG_structure_type, name: "TypeWithNested"
+// DEBUG-NOT: !DICompositeType(tag: DW_TAG_structure_type, name: "Unused1"
+// DEBUG-NOT: !DICompositeType(tag: DW_TAG_structure_type, name: "Unused2"
+// WITHATTR: !DICompositeType(tag: DW_TAG_structure_type, name: "TypeWithNested"
+// WITHATTR: !DICompositeType(tag: DW_TAG_structure_type, name: "Unused1"
+// The STANDALONEDEBUGATTR isn't propagated to the nested type by default, so
+// it should still be a forward declaration.
+// WITHATTR-SAME: DIFlagFwdDecl
+// WITHATTR: !DICompositeType(tag: DW_TAG_structure_type, name: "Unused2"
+// WITHATTR-NOT: DIFlagFwdDecl
``````````
</details>
https://github.com/llvm/llvm-project/pull/146175
More information about the cfe-commits
mailing list