nickdesaulniers updated this revision to Diff 271884.
nickdesaulniers added a comment.
- rebase
- make feature progression of debug-info-kind
- fix docs (define, not declare)
- add driver tests
- use OptOutFFlag tablegen helper
- rename helper to EmitAndRetainType
- dont emit debug info for declarations
- rewrite tests
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D80242/new/
https://reviews.llvm.org/D80242
Files:
clang/docs/ClangCommandLineReference.rst
clang/docs/CommandGuide/clang.rst
clang/docs/UsersManual.rst
clang/include/clang/Basic/CodeGenOptions.def
clang/include/clang/Basic/CodeGenOptions.h
clang/include/clang/Basic/DebugInfoOptions.h
clang/include/clang/Driver/Options.td
clang/lib/CodeGen/CGDebugInfo.cpp
clang/lib/CodeGen/CGDebugInfo.h
clang/lib/CodeGen/CGDecl.cpp
clang/lib/CodeGen/CodeGenModule.cpp
clang/lib/Driver/ToolChains/Clang.cpp
clang/lib/Frontend/CompilerInvocation.cpp
clang/test/CodeGen/debug-info-unused-types.c
clang/test/CodeGen/debug-info-unused-types.cpp
clang/test/Driver/debug-options.c
Index: clang/test/Driver/debug-options.c
===================================================================
--- clang/test/Driver/debug-options.c
+++ clang/test/Driver/debug-options.c
@@ -361,3 +361,12 @@
// GEMBED_2: error: invalid argument '-gembed-source' only allowed with '-gdwarf-5'
// NOGEMBED_5-NOT: "-gembed-source"
// NOGEMBED_2-NOT: error: invalid argument '-gembed-source' only allowed with '-gdwarf-5'
+//
+// RUN: %clang -### -g -fno-eliminate-unused-debug-types -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=DEBUG_UNUSED_TYPES %s
+// DEBUG_UNUSED_TYPES: "-debug-info-kind=unused-types"
+// DEBUG_UNUSED_TYPES-NOT: "-debug-info-kind=limited"
+// RUN: %clang -### -g -feliminate-unused-debug-types -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=NO_DEBUG_UNUSED_TYPES %s
+// NO_DEBUG_UNUSED_TYPES: "-debug-info-kind=limited"
+// NO_DEBUG_UNUSED_TYPES-NOT: "-debug-info-kind=unused-types"
Index: clang/test/CodeGen/debug-info-unused-types.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/debug-info-unused-types.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang++ -fno-eliminate-unused-debug-types -g -emit-llvm -S -o - %s | FileCheck %s
+// RUN: %clang++ -feliminate-unused-debug-types -g -emit-llvm -S -o - %s | FileCheck --check-prefix=NODBG %s
+// RUN: %clang++ -g -emit-llvm -S -o - %s | FileCheck --check-prefix=NODBG %s
+// RUN: %clang++ -emit-llvm -S -o - %s | FileCheck --check-prefix=NODBG %s
+using foo = int;
+class bar {};
+enum class baz { BAZ };
+
+void quux() {
+ using x = int;
+ class y {};
+ enum class z { Z };
+}
+
+// CHECK: !DICompositeType(tag: DW_TAG_enumeration_type, name: "baz"
+// CHECK: !DIEnumerator(name: "BAZ"
+// CHECK: !DICompositeType(tag: DW_TAG_enumeration_type, name: "z"
+// CHECK: !DIEnumerator(name: "Z"
+// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "foo"
+// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "bar"
+// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "y"
+
+// NODBG-NOT: !DICompositeType(tag: DW_TAG_enumeration_type, name: "baz"
+// NODBG-NOT: !DIEnumerator(name: "BAZ"
+// NODBG-NOT: !DICompositeType(tag: DW_TAG_enumeration_type, name: "z"
+// NODBG-NOT: !DIEnumerator(name: "Z"
+// NODBG-NOT: !DIDerivedType(tag: DW_TAG_typedef, name: "foo"
+// NODBG-NOT: !DICompositeType(tag: DW_TAG_class_type, name: "bar"
+// NODBG-NOT: !DICompositeType(tag: DW_TAG_class_type, name: "y"
+
+class aaaaaaaaaaaa;
+enum class bbbbbbbbbbbb;
+
+// NODBG-NOT: aaaaaaaaaaaa;
+// NODBG-NOT: bbbbbbbbbbbb;
Index: clang/test/CodeGen/debug-info-unused-types.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/debug-info-unused-types.c
@@ -0,0 +1,60 @@
+// RUN: %clang -fno-eliminate-unused-debug-types -g -emit-llvm -S -o - %s | FileCheck %s
+// RUN: %clang -feliminate-unused-debug-types -g -emit-llvm -S -o - %s | FileCheck --check-prefix=NODBG %s
+// RUN: %clang -g -emit-llvm -S -o - %s | FileCheck --check-prefix=NODBG %s
+// RUN: %clang -emit-llvm -S -o - %s | FileCheck --check-prefix=NODBG %s
+typedef int my_int;
+struct foo {};
+enum bar { BAR };
+union baz {};
+
+void quux(void) {
+ typedef int x;
+ struct y {};
+ enum z { Z };
+ union w {};
+}
+
+// Check that debug info is emitted for the typedef, struct, enum, and union
+// when -fno-eliminate-unused-debug-types and -g are set.
+
+// CHECK: !DICompositeType(tag: DW_TAG_enumeration_type, name: "bar"
+// CHECK: !DIEnumerator(name: "BAR"
+// CHECK: !DICompositeType(tag: DW_TAG_enumeration_type, name: "z"
+// CHECK: !DIEnumerator(name: "Z"
+// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "my_int"
+// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "foo"
+// CHECK: !DICompositeType(tag: DW_TAG_union_type, name: "baz"
+// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "y"
+// CHECK: !DICompositeType(tag: DW_TAG_union_type, name: "w"
+
+// Check that debug info is not emitted for the typedef, struct, enum, and
+// union when -fno-eliminate-unused-debug-types and -g are not set. These are
+// the same checks as above with `NODBG-NOT` rather than `CHECK`.
+
+// NODBG-NOT: !DICompositeType(tag: DW_TAG_enumeration_type, name: "bar"
+// NODBG-NOT: !DIEnumerator(name: "BAR"
+// NODBG-NOT: !DICompositeType(tag: DW_TAG_enumeration_type, name: "z"
+// NODBG-NOT: !DIEnumerator(name: "Z"
+// NODBG-NOT: !DIDerivedType(tag: DW_TAG_typedef, name: "my_int"
+// NODBG-NOT: !DICompositeType(tag: DW_TAG_structure_type, name: "foo"
+// NODBG-NOT: !DICompositeType(tag: DW_TAG_union_type, name: "baz"
+// NODBG-NOT: !DICompositeType(tag: DW_TAG_structure_type, name: "y"
+// NODBG-NOT: !DICompositeType(tag: DW_TAG_union_type, name: "w"
+
+// Check that debug info is not emitted for declarations. Obnoxious
+// indentifiers are to avoid collisions with the SHA emittied as debug info.
+struct aaaaaaaaaaaa;
+enum bbbbbbbbbbbb;
+union cccccccccccc;
+void b0(void) {
+ struct dddddddddddd;
+ enum eeeeeeeeeeee;
+ union ffffffffffff;
+}
+
+// NODBG-NOT: aaaaaaaaaaaa
+// NODBG-NOT: bbbbbbbbbbbb
+// NODBG-NOT: cccccccccccc
+// NODBG-NOT: dddddddddddd
+// NODBG-NOT: eeeeeeeeeeee
+// NODBG-NOT: ffffffffffff
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -730,6 +730,7 @@
.Case("constructor", codegenoptions::DebugInfoConstructor)
.Case("limited", codegenoptions::LimitedDebugInfo)
.Case("standalone", codegenoptions::FullDebugInfo)
+ .Case("unused-types", codegenoptions::UnusedTypeInfo)
.Default(~0U);
if (Val == ~0U)
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args)
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -1020,6 +1020,9 @@
case codegenoptions::FullDebugInfo:
CmdArgs.push_back("-debug-info-kind=standalone");
break;
+ case codegenoptions::UnusedTypeInfo:
+ CmdArgs.push_back("-debug-info-kind=unused-types");
+ break;
default:
break;
}
@@ -3845,6 +3848,10 @@
DebugInfoKind <= codegenoptions::DebugDirectivesOnly)
DebugInfoKind = codegenoptions::DebugLineTablesOnly;
+ if (EmitDwarf && Args.hasFlag(options::OPT_fno_eliminate_unused_debug_types,
+ options::OPT_feliminate_unused_debug_types, false))
+ DebugInfoKind = codegenoptions::UnusedTypeInfo;
+
RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DWARFVersion,
DebuggerTuning);
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -5378,16 +5378,21 @@
Spec->hasDefinition())
DI->completeTemplateDefinition(*Spec);
} LLVM_FALLTHROUGH;
- case Decl::CXXRecord:
- if (CGDebugInfo *DI = getModuleDebugInfo())
- if (auto *ES = D->getASTContext().getExternalSource())
+ case Decl::CXXRecord: {
+ CXXRecordDecl *CRD = cast<CXXRecordDecl>(D);
+ if (CGDebugInfo *DI = getModuleDebugInfo()) {
+ if (getCodeGenOpts().hasMaybeUnusedDebugInfo() && CRD->hasDefinition())
+ DI->completeUnusedClass(*CRD);
+ else if (auto *ES = D->getASTContext().getExternalSource())
if (ES->hasExternalDefinitions(D) == ExternalASTSource::EK_Never)
- DI->completeUnusedClass(cast<CXXRecordDecl>(*D));
+ DI->completeUnusedClass(*CRD);
+ }
// Emit any static data members, they may be definitions.
- for (auto *I : cast<CXXRecordDecl>(D)->decls())
+ for (auto *I : CRD->decls())
if (isa<VarDecl>(I) || isa<CXXRecordDecl>(I))
EmitTopLevelDecl(I);
break;
+ }
// No code generation needed.
case Decl::UsingShadow:
case Decl::ClassTemplate:
@@ -5573,6 +5578,30 @@
EmitOMPRequiresDecl(cast<OMPRequiresDecl>(D));
break;
+ case Decl::Typedef:
+ case Decl::TypeAlias: // using foo = bar; [C++11]
+ if (CGDebugInfo *DI = getModuleDebugInfo()) {
+ QualType QT = getContext().getTypedefType(cast<TypedefNameDecl>(D));
+ DI->EmitAndRetainType(QT);
+ }
+ break;
+
+ case Decl::Record:
+ if (CGDebugInfo *DI = getModuleDebugInfo())
+ if (cast<RecordDecl>(D)->getDefinition()) {
+ QualType QT = getContext().getRecordType(cast<RecordDecl>(D));
+ DI->EmitAndRetainType(QT);
+ }
+ break;
+
+ case Decl::Enum:
+ if (CGDebugInfo *DI = getModuleDebugInfo())
+ if (cast<EnumDecl>(D)->getDefinition()) {
+ QualType QT = getContext().getEnumType(cast<EnumDecl>(D));
+ DI->EmitAndRetainType(QT);
+ }
+ break;
+
default:
// Make sure we handled everything we should, every other kind is a
// non-top-level decl. FIXME: Would be nice to have an isTopLevelDeclKind
Index: clang/lib/CodeGen/CGDecl.cpp
===================================================================
--- clang/lib/CodeGen/CGDecl.cpp
+++ clang/lib/CodeGen/CGDecl.cpp
@@ -100,11 +100,23 @@
case Decl::ObjCTypeParam:
case Decl::Binding:
llvm_unreachable("Declaration should not be in declstmts!");
- case Decl::Function: // void X();
+ case Decl::CXXRecord: // struct/union/class X; [C++]
+ if (CGDebugInfo *DI = getDebugInfo())
+ if (CGM.getCodeGenOpts().hasMaybeUnusedDebugInfo() && cast<CXXRecordDecl>(D).hasDefinition())
+ DI->completeUnusedClass(cast<CXXRecordDecl>(D));
+ return;
case Decl::Record: // struct/union/class X;
+ if (CGDebugInfo *DI = getDebugInfo())
+ if (cast<RecordDecl>(&D)->getDefinition())
+ DI->EmitAndRetainType(getContext().getRecordType(cast<RecordDecl>(&D)));
+ return;
case Decl::Enum: // enum X;
+ if (CGDebugInfo *DI = getDebugInfo())
+ if (cast<EnumDecl>(&D)->getDefinition())
+ DI->EmitAndRetainType(getContext().getEnumType(cast<EnumDecl>(&D)));
+ return;
+ case Decl::Function: // void X();
case Decl::EnumConstant: // enum ? { X = ? }
- case Decl::CXXRecord: // struct/union/class X; [C++]
case Decl::StaticAssert: // static_assert(X, ""); [C++0x]
case Decl::Label: // __label__ x;
case Decl::Import:
@@ -157,12 +169,11 @@
case Decl::Typedef: // typedef int X;
case Decl::TypeAlias: { // using X = int; [C++0x]
- const TypedefNameDecl &TD = cast<TypedefNameDecl>(D);
- QualType Ty = TD.getUnderlyingType();
-
+ QualType Ty = cast<TypedefNameDecl>(D).getUnderlyingType();
+ if (CGDebugInfo *DI = getDebugInfo())
+ return DI->EmitAndRetainType(Ty);
if (Ty->isVariablyModifiedType())
EmitVariablyModifiedType(Ty);
-
return;
}
}
Index: clang/lib/CodeGen/CGDebugInfo.h
===================================================================
--- clang/lib/CodeGen/CGDebugInfo.h
+++ clang/lib/CodeGen/CGDebugInfo.h
@@ -490,6 +490,9 @@
/// Emit the type explicitly casted to.
void EmitExplicitCastType(QualType Ty);
+ /// Emit the type even if it might not be used.
+ void EmitAndRetainType(QualType Ty);
+
/// Emit C++ using declaration.
void EmitUsingDecl(const UsingDecl &UD);
Index: clang/lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- clang/lib/CodeGen/CGDebugInfo.cpp
+++ clang/lib/CodeGen/CGDebugInfo.cpp
@@ -606,6 +606,7 @@
case codegenoptions::DebugInfoConstructor:
case codegenoptions::LimitedDebugInfo:
case codegenoptions::FullDebugInfo:
+ case codegenoptions::UnusedTypeInfo:
EmissionKind = llvm::DICompileUnit::FullDebug;
break;
}
@@ -4954,13 +4955,17 @@
DBuilder.finalize();
}
+// Don't ignore in case of explicit cast where it is referenced indirectly.
void CGDebugInfo::EmitExplicitCastType(QualType Ty) {
- if (!CGM.getCodeGenOpts().hasReducedDebugInfo())
- return;
+ if (CGM.getCodeGenOpts().hasReducedDebugInfo())
+ if (auto *DieTy = getOrCreateType(Ty, TheCU->getFile()))
+ DBuilder.retainType(DieTy);
+}
- if (auto *DieTy = getOrCreateType(Ty, TheCU->getFile()))
- // Don't ignore in case of explicit cast where it is referenced indirectly.
- DBuilder.retainType(DieTy);
+void CGDebugInfo::EmitAndRetainType(QualType Ty) {
+ if (CGM.getCodeGenOpts().hasMaybeUnusedDebugInfo())
+ if (auto *DieTy = getOrCreateType(Ty, TheCU->getFile()))
+ DBuilder.retainType(DieTy);
}
llvm::DebugLoc CGDebugInfo::SourceLocToDebugLoc(SourceLocation Loc) {
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -921,6 +921,8 @@
Flags<[CC1Option]>,
HelpText<"Do not elide types when printing diagnostics">;
def feliminate_unused_debug_symbols : Flag<["-"], "feliminate-unused-debug-symbols">, Group<f_Group>;
+defm eliminate_unused_debug_types : OptOutFFlag<"eliminate-unused-debug-types",
+ "Emit ", "Do not emit ", " debug info for defined but unused types">;
def femit_all_decls : Flag<["-"], "femit-all-decls">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Emit all declarations, even if unused">;
def femulated_tls : Flag<["-"], "femulated-tls">, Group<f_Group>, Flags<[CC1Option]>,
@@ -3243,7 +3245,6 @@
defm fcheck_new : BooleanFFlag<"check-new">, Group<clang_ignored_f_Group>;
defm caller_saves : BooleanFFlag<"caller-saves">, Group<clang_ignored_gcc_optimization_f_Group>;
defm reorder_blocks : BooleanFFlag<"reorder-blocks">, Group<clang_ignored_gcc_optimization_f_Group>;
-defm eliminate_unused_debug_types : BooleanFFlag<"eliminate-unused-debug-types">, Group<clang_ignored_f_Group>;
defm branch_count_reg : BooleanFFlag<"branch-count-reg">, Group<clang_ignored_gcc_optimization_f_Group>;
defm default_inline : BooleanFFlag<"default-inline">, Group<clang_ignored_gcc_optimization_f_Group>;
defm fat_lto_objects : BooleanFFlag<"fat-lto-objects">, Group<clang_ignored_gcc_optimization_f_Group>;
Index: clang/include/clang/Basic/DebugInfoOptions.h
===================================================================
--- clang/include/clang/Basic/DebugInfoOptions.h
+++ clang/include/clang/Basic/DebugInfoOptions.h
@@ -46,7 +46,11 @@
LimitedDebugInfo,
/// Generate complete debug info.
- FullDebugInfo
+ FullDebugInfo,
+
+ /// Generate debug info for types that may be unused in the source
+ /// (-fno-eliminate-unused-debug-types).
+ UnusedTypeInfo,
};
} // end namespace codegenoptions
Index: clang/include/clang/Basic/CodeGenOptions.h
===================================================================
--- clang/include/clang/Basic/CodeGenOptions.h
+++ clang/include/clang/Basic/CodeGenOptions.h
@@ -388,6 +388,11 @@
bool hasReducedDebugInfo() const {
return getDebugInfo() >= codegenoptions::DebugInfoConstructor;
}
+
+ /// Check if maybe unused type info should be emitted.
+ bool hasMaybeUnusedDebugInfo() const {
+ return getDebugInfo() >= codegenoptions::UnusedTypeInfo;
+ }
};
} // end namespace clang
Index: clang/include/clang/Basic/CodeGenOptions.def
===================================================================
--- clang/include/clang/Basic/CodeGenOptions.def
+++ clang/include/clang/Basic/CodeGenOptions.def
@@ -287,7 +287,6 @@
///< template parameter descriptions in
///< forward declarations (versus just
///< including them in the name).
-
CODEGENOPT(EmitLLVMUseLists, 1, 0) ///< Control whether to serialize use-lists.
CODEGENOPT(WholeProgramVTables, 1, 0) ///< Whether to apply whole-program
@@ -312,7 +311,7 @@
VALUE_CODEGENOPT(SSPBufferSize, 32, 0)
/// The kind of generated debug info.
-ENUM_CODEGENOPT(DebugInfo, codegenoptions::DebugInfoKind, 3, codegenoptions::NoDebugInfo)
+ENUM_CODEGENOPT(DebugInfo, codegenoptions::DebugInfoKind, 4, codegenoptions::NoDebugInfo)
/// Whether to generate macro debug info.
CODEGENOPT(MacroDebugInfo, 1, 0)
Index: clang/docs/UsersManual.rst
===================================================================
--- clang/docs/UsersManual.rst
+++ clang/docs/UsersManual.rst
@@ -2352,6 +2352,12 @@
Generate complete debug info.
+.. option:: -feliminate-unused-debug-types
+
+ By default, Clang does not emit type information for types that are defined
+ but not used in a program. To retain the debug info for these unused types,
+ the negation **-fno-eliminate-unused-debug-types** can be used.
+
Controlling Macro Debug Info Generation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Index: clang/docs/CommandGuide/clang.rst
===================================================================
--- clang/docs/CommandGuide/clang.rst
+++ clang/docs/CommandGuide/clang.rst
@@ -433,6 +433,12 @@
never emit type information for types that are not referenced at all by the
program.
+.. option:: -feliminate-unused-debug-types
+
+ By default, Clang does not emit type information for types that are defined
+ but not used in a program. To retain the debug info for these unused types,
+ the negation **-fno-eliminate-unused-debug-types** can be used.
+
.. option:: -fexceptions
Enable generation of unwind information. This allows exceptions to be thrown
Index: clang/docs/ClangCommandLineReference.rst
===================================================================
--- clang/docs/ClangCommandLineReference.rst
+++ clang/docs/ClangCommandLineReference.rst
@@ -2150,6 +2150,10 @@
Emit full debug info for all types used by the program
+.. option:: -feliminate-unused-debug-types, -fno-eliminate-unused-debug-types
+
+Emit debug info for types that are unused but defined by the program.
+
.. option:: -fstrict-aliasing, -fno-strict-aliasing
.. option:: -fstrict-enums, -fno-strict-enums
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits