diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1673,6 +1673,14 @@ 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]>; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -1102,6 +1102,16 @@ }]; } +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 = [{ diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -2385,7 +2385,8 @@ if (DebugKind == codegenoptions::DebugLineTablesOnly) return true; - if (DebugKind > codegenoptions::LimitedDebugInfo) + if (DebugKind > codegenoptions::LimitedDebugInfo || + RD->hasAttr()) return false; if (!LangOpts.CPlusPlus) diff --git a/clang/test/CodeGenCXX/standalone-debug-attribute.cpp b/clang/test/CodeGenCXX/standalone-debug-attribute.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/standalone-debug-attribute.cpp @@ -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 struct ExternTemplate { + ExternTemplate() {} + T x; +}; +extern template struct STANDALONEDEBUGATTR ExternTemplate; +void f(ExternTemplate s) {} +// DEBUG: !DICompositeType({{.*}}name: "ExternTemplate" +// DEBUG-SAME: flags: {{.*}}DIFlagFwdDecl +// WITHATTR: !DICompositeType({{.*}}name: "ExternTemplate" +// 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 + diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -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) diff --git a/clang/test/Sema/attr-standalonedebug.cpp b/clang/test/Sema/attr-standalonedebug.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Sema/attr-standalonedebug.cpp @@ -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