[DebugInfo] Add an attribute to force type info to be emitted for types that are required to be complete.

This was motivated by the fact that constructor type homing (debug info
optimization that we want to turn on by default) drops some libc++ types,
so an attribute would allow us to override constructor homing and emit
them anyway. I'm currently looking into the particular libc++ issue, but
even if we do fix that, this issue might come up elsewhere and it might be
nice to have this.

As I've implemented it now, the attribute isn't specific to the
constructor homing optimization and overrides all of the debug info
optimizations.

Open to discussion about naming, specifics on what the attribute should do, etc.

Differential Revision: https://reviews.llvm.org/D97411
This commit is contained in:
Amy Huang 2021-02-16 13:13:52 -08:00
parent 579b8fc2e9
commit d7cd208f08
6 changed files with 89 additions and 1 deletions

View File

@ -1673,6 +1673,14 @@ def NoDebug : InheritableAttr {
let Documentation = [NoDebugDocs];
}
def StandaloneDebug : InheritableAttr {
let Spellings = [Clang<"standalone_debug", /*allowInC =*/0>];
let Subjects = SubjectList<[CXXRecord]>;
let Documentation = [StandaloneDebugDocs];
let SimpleHandler = 1;
let LangOpts = [CPlusPlus];
}
def NoDuplicate : InheritableAttr {
let Spellings = [Clang<"noduplicate">];
let Subjects = SubjectList<[Function]>;

View File

@ -1102,6 +1102,16 @@ data member, or for a typedef or using declaration.
}];
}
def StandaloneDebugDocs : Documentation {
let Category = DocCatVariable;
let Content = [{
The ``standalone_debug`` attribute causes debug info to be emitted for a record
type regardless of the debug info optimizations that are enabled with
-fno-standalone-debug. This attribute only has an effect when debug info
optimizations are enabled (e.g. with -fno-standalone-debug), and is C++-only.
}];
}
def NoDuplicateDocs : Documentation {
let Category = DocCatFunction;
let Content = [{

View File

@ -2385,7 +2385,8 @@ static bool shouldOmitDefinition(codegenoptions::DebugInfoKind DebugKind,
if (DebugKind == codegenoptions::DebugLineTablesOnly)
return true;
if (DebugKind > codegenoptions::LimitedDebugInfo)
if (DebugKind > codegenoptions::LimitedDebugInfo ||
RD->hasAttr<StandaloneDebugAttr>())
return false;
if (!LangOpts.CPlusPlus)

View File

@ -0,0 +1,54 @@
// RUN: %clang_cc1 -DSETATTR=0 -triple x86_64-unknown-linux-gnu -emit-llvm -debug-info-kind=constructor %s -o - | FileCheck %s --check-prefix=DEBUG
// RUN: %clang_cc1 -DSETATTR=1 -triple x86_64-unknown-linux-gnu -emit-llvm -debug-info-kind=constructor %s -o - | FileCheck %s --check-prefix=WITHATTR
// Use -debug-info-kind=constructor because it includes all the optimizations.
#if SETATTR
#define STANDALONEDEBUGATTR __attribute__((standalone_debug))
#else
#define STANDALONEDEBUGATTR
#endif
struct STANDALONEDEBUGATTR StructWithConstructor {
StructWithConstructor() {}
};
void f(StructWithConstructor s) {}
// DEBUG: !DICompositeType({{.*}}name: "StructWithConstructor"
// DEBUG-SAME: flags: {{.*}}DIFlagFwdDecl
// WITHATTR: !DICompositeType({{.*}}name: "StructWithConstructor"
// WITHATTR-NOT: DIFlagFwdDecl
union STANDALONEDEBUGATTR UnionWithConstructor {
UnionWithConstructor() {}
};
void f(UnionWithConstructor u) {}
// DEBUG: !DICompositeType({{.*}}name: "UnionWithConstructor"
// DEBUG-SAME: flags: {{.*}}DIFlagFwdDecl
// WITHATTR: !DICompositeType({{.*}}name: "UnionWithConstructor"
// WITHATTR-NOT: DIFlagFwdDecl
template <typename T> struct ExternTemplate {
ExternTemplate() {}
T x;
};
extern template struct STANDALONEDEBUGATTR ExternTemplate<int>;
void f(ExternTemplate<int> s) {}
// DEBUG: !DICompositeType({{.*}}name: "ExternTemplate<int>"
// DEBUG-SAME: flags: {{.*}}DIFlagFwdDecl
// WITHATTR: !DICompositeType({{.*}}name: "ExternTemplate<int>"
// WITHATTR-NOT: DIFlagFwdDecl
struct STANDALONEDEBUGATTR CompleteTypeRequired {};
void f(CompleteTypeRequired &s) {}
// DEBUG: !DICompositeType({{.*}}name: "CompleteTypeRequired"
// DEBUG-SAME: flags: {{.*}}DIFlagFwdDecl
// WITHATTR: !DICompositeType({{.*}}name: "CompleteTypeRequired"
// WITHATTR-NOT: DIFlagFwdDecl
struct STANDALONEDEBUGATTR Redecl;
struct Redecl {};
void f(Redecl &s) {}
// DEBUG: !DICompositeType({{.*}}name: "Redecl"
// DEBUG-SAME: flags: {{.*}}DIFlagFwdDecl
// WITHATTR: !DICompositeType({{.*}}name: "Redecl"
// WITHATTR-NOT: DIFlagFwdDecl

View File

@ -154,6 +154,7 @@
// CHECK-NEXT: Section (SubjectMatchRule_function, SubjectMatchRule_variable_is_global, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property)
// CHECK-NEXT: SetTypestate (SubjectMatchRule_function_is_member)
// CHECK-NEXT: SpeculativeLoadHardening (SubjectMatchRule_function, SubjectMatchRule_objc_method)
// CHECK-NEXT: StandaloneDebug (SubjectMatchRule_record)
// CHECK-NEXT: SwiftAsync (SubjectMatchRule_function, SubjectMatchRule_objc_method)
// CHECK-NEXT: SwiftAsyncError (SubjectMatchRule_function, SubjectMatchRule_objc_method)
// CHECK-NEXT: SwiftAsyncName (SubjectMatchRule_objc_method, SubjectMatchRule_function)

View File

@ -0,0 +1,14 @@
// RUN: %clang_cc1 %s -verify -fsyntax-only
// RUN: %clang_cc1 %s -verify -fsyntax-only -x c
#ifdef __cplusplus
int a __attribute__((standalone_debug)); // expected-warning {{'standalone_debug' attribute only applies to classes}}
void __attribute__((standalone_debug)) b(); // expected-warning {{'standalone_debug' attribute only applies to classes}}
struct __attribute__((standalone_debug(1))) c {}; // expected-error {{'standalone_debug' attribute takes no arguments}}
#else
// Check that attribute only works in C++.
struct __attribute__((standalone_debug)) a {}; // expected-warning {{'standalone_debug' attribute ignored}}
#endif