Skip to content

Commit e486921

Browse files
[Clang] implement -fno-eliminate-unused-debug-types
Fixes pr/11710. Signed-off-by: Nick Desaulniers <[email protected]> Reviewed By: dblaikie Differential Revision: https://reviews.llvm.org/D80242
1 parent 645de36 commit e486921

File tree

16 files changed

+185
-21
lines changed

16 files changed

+185
-21
lines changed

clang/docs/ClangCommandLineReference.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2154,6 +2154,10 @@ Emit section containing metadata on function stack sizes
21542154

21552155
Emit full debug info for all types used by the program
21562156

2157+
.. option:: -feliminate-unused-debug-types, -fno-eliminate-unused-debug-types
2158+
2159+
Suppress (or emit) debug info for types that are unused but defined by the program.
2160+
21572161
.. option:: -fstrict-aliasing, -fno-strict-aliasing
21582162

21592163
.. option:: -fstrict-enums, -fno-strict-enums

clang/docs/CommandGuide/clang.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,12 @@ Code Generation Options
433433
never emit type information for types that are not referenced at all by the
434434
program.
435435

436+
.. option:: -feliminate-unused-debug-types
437+
438+
By default, Clang does not emit type information for types that are defined
439+
but not used in a program. To retain the debug info for these unused types,
440+
the negation **-fno-eliminate-unused-debug-types** can be used.
441+
436442
.. option:: -fexceptions
437443

438444
Enable generation of unwind information. This allows exceptions to be thrown

clang/docs/UsersManual.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2352,6 +2352,12 @@ below. If multiple flags are present, the last one is used.
23522352

23532353
Generate complete debug info.
23542354

2355+
.. option:: -feliminate-unused-debug-types
2356+
2357+
By default, Clang does not emit type information for types that are defined
2358+
but not used in a program. To retain the debug info for these unused types,
2359+
the negation **-fno-eliminate-unused-debug-types** can be used.
2360+
23552361
Controlling Macro Debug Info Generation
23562362
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
23572363

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,6 @@ CODEGENOPT(DebugFwdTemplateParams, 1, 0) ///< Whether to emit complete
288288
///< template parameter descriptions in
289289
///< forward declarations (versus just
290290
///< including them in the name).
291-
292291
CODEGENOPT(EmitLLVMUseLists, 1, 0) ///< Control whether to serialize use-lists.
293292

294293
CODEGENOPT(WholeProgramVTables, 1, 0) ///< Whether to apply whole-program
@@ -313,7 +312,7 @@ VALUE_CODEGENOPT(SmallDataLimit, 32, 0)
313312
VALUE_CODEGENOPT(SSPBufferSize, 32, 0)
314313

315314
/// The kind of generated debug info.
316-
ENUM_CODEGENOPT(DebugInfo, codegenoptions::DebugInfoKind, 3, codegenoptions::NoDebugInfo)
315+
ENUM_CODEGENOPT(DebugInfo, codegenoptions::DebugInfoKind, 4, codegenoptions::NoDebugInfo)
317316

318317
/// Whether to generate macro debug info.
319318
CODEGENOPT(MacroDebugInfo, 1, 0)

clang/include/clang/Basic/CodeGenOptions.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,11 @@ class CodeGenOptions : public CodeGenOptionsBase {
388388
bool hasReducedDebugInfo() const {
389389
return getDebugInfo() >= codegenoptions::DebugInfoConstructor;
390390
}
391+
392+
/// Check if maybe unused type info should be emitted.
393+
bool hasMaybeUnusedDebugInfo() const {
394+
return getDebugInfo() >= codegenoptions::UnusedTypeInfo;
395+
}
391396
};
392397

393398
} // end namespace clang

clang/include/clang/Basic/DebugInfoOptions.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,11 @@ enum DebugInfoKind {
4646
LimitedDebugInfo,
4747

4848
/// Generate complete debug info.
49-
FullDebugInfo
49+
FullDebugInfo,
50+
51+
/// Generate debug info for types that may be unused in the source
52+
/// (-fno-eliminate-unused-debug-types).
53+
UnusedTypeInfo,
5054
};
5155

5256
} // end namespace codegenoptions

clang/include/clang/Driver/Options.td

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -943,6 +943,8 @@ def fno_elide_type : Flag<["-"], "fno-elide-type">, Group<f_Group>,
943943
Flags<[CC1Option]>,
944944
HelpText<"Do not elide types when printing diagnostics">;
945945
def feliminate_unused_debug_symbols : Flag<["-"], "feliminate-unused-debug-symbols">, Group<f_Group>;
946+
defm eliminate_unused_debug_types : OptOutFFlag<"eliminate-unused-debug-types",
947+
"Do not emit ", "Emit ", " debug info for defined but unused types">;
946948
def femit_all_decls : Flag<["-"], "femit-all-decls">, Group<f_Group>, Flags<[CC1Option]>,
947949
HelpText<"Emit all declarations, even if unused">;
948950
def femulated_tls : Flag<["-"], "femulated-tls">, Group<f_Group>, Flags<[CC1Option]>,
@@ -3321,7 +3323,6 @@ def fdiagnostics_show_location_EQ : Joined<["-"], "fdiagnostics-show-location=">
33213323
defm fcheck_new : BooleanFFlag<"check-new">, Group<clang_ignored_f_Group>;
33223324
defm caller_saves : BooleanFFlag<"caller-saves">, Group<clang_ignored_gcc_optimization_f_Group>;
33233325
defm reorder_blocks : BooleanFFlag<"reorder-blocks">, Group<clang_ignored_gcc_optimization_f_Group>;
3324-
defm eliminate_unused_debug_types : BooleanFFlag<"eliminate-unused-debug-types">, Group<clang_ignored_f_Group>;
33253326
defm branch_count_reg : BooleanFFlag<"branch-count-reg">, Group<clang_ignored_gcc_optimization_f_Group>;
33263327
defm default_inline : BooleanFFlag<"default-inline">, Group<clang_ignored_gcc_optimization_f_Group>;
33273328
defm fat_lto_objects : BooleanFFlag<"fat-lto-objects">, Group<clang_ignored_gcc_optimization_f_Group>;

clang/lib/CodeGen/CGDebugInfo.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,7 @@ void CGDebugInfo::CreateCompileUnit() {
606606
case codegenoptions::DebugInfoConstructor:
607607
case codegenoptions::LimitedDebugInfo:
608608
case codegenoptions::FullDebugInfo:
609+
case codegenoptions::UnusedTypeInfo:
609610
EmissionKind = llvm::DICompileUnit::FullDebug;
610611
break;
611612
}
@@ -4960,13 +4961,17 @@ void CGDebugInfo::finalize() {
49604961
DBuilder.finalize();
49614962
}
49624963

4964+
// Don't ignore in case of explicit cast where it is referenced indirectly.
49634965
void CGDebugInfo::EmitExplicitCastType(QualType Ty) {
4964-
if (!CGM.getCodeGenOpts().hasReducedDebugInfo())
4965-
return;
4966+
if (CGM.getCodeGenOpts().hasReducedDebugInfo())
4967+
if (auto *DieTy = getOrCreateType(Ty, TheCU->getFile()))
4968+
DBuilder.retainType(DieTy);
4969+
}
49664970

4967-
if (auto *DieTy = getOrCreateType(Ty, TheCU->getFile()))
4968-
// Don't ignore in case of explicit cast where it is referenced indirectly.
4969-
DBuilder.retainType(DieTy);
4971+
void CGDebugInfo::EmitAndRetainType(QualType Ty) {
4972+
if (CGM.getCodeGenOpts().hasMaybeUnusedDebugInfo())
4973+
if (auto *DieTy = getOrCreateType(Ty, TheCU->getFile()))
4974+
DBuilder.retainType(DieTy);
49704975
}
49714976

49724977
llvm::DebugLoc CGDebugInfo::SourceLocToDebugLoc(SourceLocation Loc) {

clang/lib/CodeGen/CGDebugInfo.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,9 @@ class CGDebugInfo {
490490
/// Emit the type explicitly casted to.
491491
void EmitExplicitCastType(QualType Ty);
492492

493+
/// Emit the type even if it might not be used.
494+
void EmitAndRetainType(QualType Ty);
495+
493496
/// Emit C++ using declaration.
494497
void EmitUsingDecl(const UsingDecl &UD);
495498

clang/lib/CodeGen/CGDecl.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,19 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
100100
case Decl::ObjCTypeParam:
101101
case Decl::Binding:
102102
llvm_unreachable("Declaration should not be in declstmts!");
103-
case Decl::Function: // void X();
104103
case Decl::Record: // struct/union/class X;
104+
case Decl::CXXRecord: // struct/union/class X; [C++]
105+
if (CGDebugInfo *DI = getDebugInfo())
106+
if (cast<RecordDecl>(D).getDefinition())
107+
DI->EmitAndRetainType(getContext().getRecordType(cast<RecordDecl>(&D)));
108+
return;
105109
case Decl::Enum: // enum X;
110+
if (CGDebugInfo *DI = getDebugInfo())
111+
if (cast<EnumDecl>(D).getDefinition())
112+
DI->EmitAndRetainType(getContext().getEnumType(cast<EnumDecl>(&D)));
113+
return;
114+
case Decl::Function: // void X();
106115
case Decl::EnumConstant: // enum ? { X = ? }
107-
case Decl::CXXRecord: // struct/union/class X; [C++]
108116
case Decl::StaticAssert: // static_assert(X, ""); [C++0x]
109117
case Decl::Label: // __label__ x;
110118
case Decl::Import:
@@ -157,12 +165,11 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
157165

158166
case Decl::Typedef: // typedef int X;
159167
case Decl::TypeAlias: { // using X = int; [C++0x]
160-
const TypedefNameDecl &TD = cast<TypedefNameDecl>(D);
161-
QualType Ty = TD.getUnderlyingType();
162-
168+
QualType Ty = cast<TypedefNameDecl>(D).getUnderlyingType();
169+
if (CGDebugInfo *DI = getDebugInfo())
170+
DI->EmitAndRetainType(Ty);
163171
if (Ty->isVariablyModifiedType())
164172
EmitVariablyModifiedType(Ty);
165-
166173
return;
167174
}
168175
}

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5392,16 +5392,21 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
53925392
Spec->hasDefinition())
53935393
DI->completeTemplateDefinition(*Spec);
53945394
} LLVM_FALLTHROUGH;
5395-
case Decl::CXXRecord:
5396-
if (CGDebugInfo *DI = getModuleDebugInfo())
5395+
case Decl::CXXRecord: {
5396+
CXXRecordDecl *CRD = cast<CXXRecordDecl>(D);
5397+
if (CGDebugInfo *DI = getModuleDebugInfo()) {
5398+
if (CRD->hasDefinition())
5399+
DI->EmitAndRetainType(getContext().getRecordType(cast<RecordDecl>(D)));
53975400
if (auto *ES = D->getASTContext().getExternalSource())
53985401
if (ES->hasExternalDefinitions(D) == ExternalASTSource::EK_Never)
5399-
DI->completeUnusedClass(cast<CXXRecordDecl>(*D));
5402+
DI->completeUnusedClass(*CRD);
5403+
}
54005404
// Emit any static data members, they may be definitions.
5401-
for (auto *I : cast<CXXRecordDecl>(D)->decls())
5405+
for (auto *I : CRD->decls())
54025406
if (isa<VarDecl>(I) || isa<CXXRecordDecl>(I))
54035407
EmitTopLevelDecl(I);
54045408
break;
5409+
}
54055410
// No code generation needed.
54065411
case Decl::UsingShadow:
54075412
case Decl::ClassTemplate:
@@ -5587,6 +5592,25 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
55875592
EmitOMPRequiresDecl(cast<OMPRequiresDecl>(D));
55885593
break;
55895594

5595+
case Decl::Typedef:
5596+
case Decl::TypeAlias: // using foo = bar; [C++11]
5597+
if (CGDebugInfo *DI = getModuleDebugInfo())
5598+
DI->EmitAndRetainType(
5599+
getContext().getTypedefType(cast<TypedefNameDecl>(D)));
5600+
break;
5601+
5602+
case Decl::Record:
5603+
if (CGDebugInfo *DI = getModuleDebugInfo())
5604+
if (cast<RecordDecl>(D)->getDefinition())
5605+
DI->EmitAndRetainType(getContext().getRecordType(cast<RecordDecl>(D)));
5606+
break;
5607+
5608+
case Decl::Enum:
5609+
if (CGDebugInfo *DI = getModuleDebugInfo())
5610+
if (cast<EnumDecl>(D)->getDefinition())
5611+
DI->EmitAndRetainType(getContext().getEnumType(cast<EnumDecl>(D)));
5612+
break;
5613+
55905614
default:
55915615
// Make sure we handled everything we should, every other kind is a
55925616
// non-top-level decl. FIXME: Would be nice to have an isTopLevelDeclKind

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -976,6 +976,9 @@ static void RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs,
976976
case codegenoptions::FullDebugInfo:
977977
CmdArgs.push_back("-debug-info-kind=standalone");
978978
break;
979+
case codegenoptions::UnusedTypeInfo:
980+
CmdArgs.push_back("-debug-info-kind=unused-types");
981+
break;
979982
default:
980983
break;
981984
}
@@ -3781,8 +3784,14 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D,
37813784
TC.GetDefaultStandaloneDebug());
37823785
if (const Arg *A = Args.getLastArg(options::OPT_fstandalone_debug))
37833786
(void)checkDebugInfoOption(A, Args, D, TC);
3784-
if (DebugInfoKind == codegenoptions::LimitedDebugInfo && NeedFullDebug)
3785-
DebugInfoKind = codegenoptions::FullDebugInfo;
3787+
3788+
if (DebugInfoKind == codegenoptions::LimitedDebugInfo) {
3789+
if (Args.hasFlag(options::OPT_fno_eliminate_unused_debug_types,
3790+
options::OPT_feliminate_unused_debug_types, false))
3791+
DebugInfoKind = codegenoptions::UnusedTypeInfo;
3792+
else if (NeedFullDebug)
3793+
DebugInfoKind = codegenoptions::FullDebugInfo;
3794+
}
37863795

37873796
if (Args.hasFlag(options::OPT_gembed_source, options::OPT_gno_embed_source,
37883797
false)) {

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
767767
.Case("constructor", codegenoptions::DebugInfoConstructor)
768768
.Case("limited", codegenoptions::LimitedDebugInfo)
769769
.Case("standalone", codegenoptions::FullDebugInfo)
770+
.Case("unused-types", codegenoptions::UnusedTypeInfo)
770771
.Default(~0U);
771772
if (Val == ~0U)
772773
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// RUN: %clang -fno-eliminate-unused-debug-types -g -emit-llvm -S -o - %s | FileCheck %s
2+
// RUN: %clang -fno-eliminate-unused-debug-types -g1 -emit-llvm -S -o - %s | FileCheck --check-prefix=NODBG %s
3+
// RUN: %clang -feliminate-unused-debug-types -g -emit-llvm -S -o - %s | FileCheck --check-prefix=NODBG %s
4+
// RUN: %clang -g -emit-llvm -S -o - %s | FileCheck --check-prefix=NODBG %s
5+
// RUN: %clang -emit-llvm -S -o - %s | FileCheck --check-prefix=NODBG %s
6+
typedef int my_int;
7+
struct foo {};
8+
enum bar { BAR };
9+
union baz {};
10+
11+
void quux(void) {
12+
typedef int x;
13+
struct y {};
14+
enum z { Z };
15+
union w {};
16+
}
17+
18+
// Check that debug info is emitted for the typedef, struct, enum, and union
19+
// when -fno-eliminate-unused-debug-types and -g are set.
20+
21+
// CHECK: !DICompileUnit{{.+}}retainedTypes: [[RETTYPES:![0-9]+]]
22+
// CHECK: [[TYPE0:![0-9]+]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "bar"
23+
// CHECK: [[TYPE1:![0-9]+]] = !DIEnumerator(name: "BAR"
24+
// CHECK: [[TYPE2:![0-9]+]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "z"
25+
// CHECK: [[TYPE3:![0-9]+]] = !DIEnumerator(name: "Z"
26+
// CHECK: [[RETTYPES]] = !{[[TYPE4:![0-9]+]], [[TYPE5:![0-9]+]], [[TYPE0]], [[TYPE6:![0-9]+]], !17, [[TYPE7:![0-9]+]], [[TYPE2]], [[TYPE8:![0-9]+]]}
27+
// CHECK: [[TYPE4]] = !DIDerivedType(tag: DW_TAG_typedef, name: "my_int"
28+
// CHECK: [[TYPE5]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "foo"
29+
// CHECK: [[TYPE6]] = distinct !DICompositeType(tag: DW_TAG_union_type, name: "baz"
30+
// CHECK: [[TYPE7]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "y"
31+
// CHECK: [[TYPE8]] = distinct !DICompositeType(tag: DW_TAG_union_type, name: "w"
32+
33+
// Check that debug info is not emitted for the typedef, struct, enum, and
34+
// union when -fno-eliminate-unused-debug-types and -g are not set. These are
35+
// the same checks as above with `NODBG-NOT` rather than `CHECK`.
36+
37+
// NODBG-NOT: !DI{{CompositeType|Enumerator|DerivedType}}
38+
39+
// Check that debug info is not emitted for declarations. Obnoxious
40+
// indentifiers are to avoid collisions with the SHA emittied as debug info.
41+
struct unused_struct;
42+
enum unused_enum;
43+
union unused_union;
44+
void b0(void) {
45+
struct unused_local_struct;
46+
enum unused_local_enum;
47+
union unused_local_union;
48+
}
49+
50+
// NODBG-NOT: name: "unused_
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// RUN: %clang++ -fno-eliminate-unused-debug-types -g -emit-llvm -S -o - %s | FileCheck %s
2+
// RUN: %clang++ -fno-eliminate-unused-debug-types -g1 -emit-llvm -S -o - %s | FileCheck --check-prefix=NODBG %s
3+
// RUN: %clang++ -feliminate-unused-debug-types -g -emit-llvm -S -o - %s | FileCheck --check-prefix=NODBG %s
4+
// RUN: %clang++ -g -emit-llvm -S -o - %s | FileCheck --check-prefix=NODBG %s
5+
// RUN: %clang++ -emit-llvm -S -o - %s | FileCheck --check-prefix=NODBG %s
6+
using foo = int;
7+
class bar {};
8+
enum class baz { BAZ };
9+
10+
void quux() {
11+
using x = int;
12+
class y {};
13+
enum class z { Z };
14+
}
15+
16+
// CHECK: !DICompileUnit{{.+}}retainedTypes: [[RETTYPES:![0-9]+]]
17+
// CHECK: [[TYPE0:![0-9]+]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "baz"
18+
// CHECK: [[TYPE1:![0-9]+]] = !DIEnumerator(name: "BAZ"
19+
// CHECK: [[TYPE2:![0-9]+]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "z"
20+
// CHECK: [[TYPE3:![0-9]+]] = !DIEnumerator(name: "Z"
21+
// CHECK: [[RETTYPES]] = !{[[TYPE4:![0-9]+]], [[TYPE5:![0-9]+]], [[TYPE0]], !5, [[TYPE6:![0-9]+]], [[TYPE2]]}
22+
// CHECK: [[TYPE4]] = !DIDerivedType(tag: DW_TAG_typedef, name: "foo"
23+
// CHECK: [[TYPE5]] = distinct !DICompositeType(tag: DW_TAG_class_type, name: "bar"
24+
// CHECK: [[TYPE6]] = distinct !DICompositeType(tag: DW_TAG_class_type, name: "y"
25+
26+
// NODBG-NOT: !DI{{CompositeType|Enumerator|DerivedType}}
27+
28+
class unused_class;
29+
enum class unused_enum_class;
30+
31+
// NODBG-NOT: name: "unused_

clang/test/Driver/debug-options.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,3 +361,12 @@
361361
// GEMBED_2: error: invalid argument '-gembed-source' only allowed with '-gdwarf-5'
362362
// NOGEMBED_5-NOT: "-gembed-source"
363363
// NOGEMBED_2-NOT: error: invalid argument '-gembed-source' only allowed with '-gdwarf-5'
364+
//
365+
// RUN: %clang -### -g -fno-eliminate-unused-debug-types -c %s 2>&1 \
366+
// RUN: | FileCheck -check-prefix=DEBUG_UNUSED_TYPES %s
367+
// DEBUG_UNUSED_TYPES: "-debug-info-kind=unused-types"
368+
// DEBUG_UNUSED_TYPES-NOT: "-debug-info-kind=limited"
369+
// RUN: %clang -### -g -feliminate-unused-debug-types -c %s 2>&1 \
370+
// RUN: | FileCheck -check-prefix=NO_DEBUG_UNUSED_TYPES %s
371+
// NO_DEBUG_UNUSED_TYPES: "-debug-info-kind=limited"
372+
// NO_DEBUG_UNUSED_TYPES-NOT: "-debug-info-kind=unused-types"

0 commit comments

Comments
 (0)