diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -138,6 +138,11 @@ /// Keep track of our current nested lexical block. std::vector> LexicalBlockStack; + + /// Map of AST declaration to its lexical block scope. + llvm::DenseMap> + LexicalBlockMap; + llvm::DenseMap RegionMap; /// Keep track of LexicalBlockStack counter at the beginning of a /// function. This is used to pop unbalanced regions at the end of a @@ -542,6 +547,12 @@ /// Emit an Objective-C interface type standalone debug info. llvm::DIType *getOrCreateInterfaceType(QualType Ty, SourceLocation Loc); + /// Map AST declaration to its lexical block scope if available. + void recordDeclarationLexicalScope(const Decl &D); + + /// Get lexical scope of AST declaration. + llvm::DIScope *getDeclarationLexicalScope(const Decl *D); + /// Emit standalone debug info for a type. llvm::DIType *getOrCreateStandaloneType(QualType Ty, SourceLocation Loc); 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 @@ -227,6 +227,22 @@ return Default; } +void CGDebugInfo::recordDeclarationLexicalScope(const Decl &D) { + assert(LexicalBlockMap.find(&D) == LexicalBlockMap.end() && + "D is already mapped to a lexical block scope"); + if (!LexicalBlockStack.empty()) + LexicalBlockMap.insert({&D, LexicalBlockStack.back()}); +} + +llvm::DIScope *CGDebugInfo::getDeclarationLexicalScope(const Decl *D) { + if (CGM.getCodeGenOpts().getDebuggerTuning() == llvm::DebuggerKind::GDB) { + auto I = LexicalBlockMap.find(D); + if (I != LexicalBlockMap.end()) + return I->second; + } + return getDeclContextDescriptor(cast(D)); +} + PrintingPolicy CGDebugInfo::getPrintingPolicy() const { PrintingPolicy PP = CGM.getContext().getPrintingPolicy(); @@ -1295,13 +1311,13 @@ // declared. SourceLocation Loc = Ty->getDecl()->getLocation(); + llvm::DIScope *TDContext = getDeclarationLexicalScope(Ty->getDecl()); uint32_t Align = getDeclAlignIfRequired(Ty->getDecl(), CGM.getContext()); // Typedefs are derived from some other type. llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(Ty->getDecl()); return DBuilder.createTypedef(Underlying, Ty->getDecl()->getName(), getOrCreateFile(Loc), getLineNumber(Loc), - getDeclContextDescriptor(Ty->getDecl()), Align, - Annotations); + TDContext, Align, Annotations); } static unsigned getDwarfCC(CallingConv CC) { @@ -3194,7 +3210,7 @@ // entered into the ReplaceMap: finalize() will replace the first // FwdDecl with the second and then replace the second with // complete type. - llvm::DIScope *EDContext = getDeclContextDescriptor(ED); + llvm::DIScope *EDContext = getDeclarationLexicalScope(ED); llvm::DIFile *DefUnit = getOrCreateFile(ED->getLocation()); llvm::TempDIScope TmpContext(DBuilder.createReplaceableCompositeType( llvm::dwarf::DW_TAG_enumeration_type, "", TheCU, DefUnit, 0)); @@ -3237,7 +3253,7 @@ llvm::DIFile *DefUnit = getOrCreateFile(ED->getLocation()); unsigned Line = getLineNumber(ED->getLocation()); - llvm::DIScope *EnumContext = getDeclContextDescriptor(ED); + llvm::DIScope *EnumContext = getDeclarationLexicalScope(ED); llvm::DIType *ClassTy = getOrCreateType(ED->getIntegerType(), DefUnit); return DBuilder.createEnumerationType(EnumContext, ED->getName(), DefUnit, Line, Size, Align, EltArray, ClassTy, @@ -3546,7 +3562,7 @@ Line = getLineNumber(Loc); } - llvm::DIScope *RDContext = getDeclContextDescriptor(RD); + llvm::DIScope *RDContext = getDeclarationLexicalScope(RD); // If we ended up creating the type during the context chain construction, // just return that. diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -103,17 +103,21 @@ llvm_unreachable("Declaration should not be in declstmts!"); case Decl::Record: // struct/union/class X; case Decl::CXXRecord: // struct/union/class X; [C++] - if (CGDebugInfo *DI = getDebugInfo()) + if (CGDebugInfo *DI = getDebugInfo()) { + DI->recordDeclarationLexicalScope(D); if (cast(D).getDefinition()) DI->EmitAndRetainType(getContext().getRecordType(cast(&D))); + } return; case Decl::Enum: // enum X; - if (CGDebugInfo *DI = getDebugInfo()) + if (CGDebugInfo *DI = getDebugInfo()) { + DI->recordDeclarationLexicalScope(D); if (cast(D).getDefinition()) DI->EmitAndRetainType(getContext().getEnumType(cast(&D))); + } return; - case Decl::Function: // void X(); case Decl::EnumConstant: // enum ? { X = ? } + case Decl::Function: // void X(); case Decl::StaticAssert: // static_assert(X, ""); [C++0x] case Decl::Label: // __label__ x; case Decl::Import: @@ -133,11 +137,11 @@ case Decl::NamespaceAlias: if (CGDebugInfo *DI = getDebugInfo()) - DI->EmitNamespaceAlias(cast(D)); + DI->EmitNamespaceAlias(cast(D)); return; case Decl::Using: // using X; [C++] if (CGDebugInfo *DI = getDebugInfo()) - DI->EmitUsingDecl(cast(D)); + DI->EmitUsingDecl(cast(D)); return; case Decl::UsingEnum: // using enum X; [C++] if (CGDebugInfo *DI = getDebugInfo()) @@ -173,8 +177,10 @@ case Decl::Typedef: // typedef int X; case Decl::TypeAlias: { // using X = int; [C++0x] QualType Ty = cast(D).getUnderlyingType(); - if (CGDebugInfo *DI = getDebugInfo()) + if (CGDebugInfo *DI = getDebugInfo()) { + DI->recordDeclarationLexicalScope(D); DI->EmitAndRetainType(Ty); + } if (Ty->isVariablyModifiedType()) EmitVariablyModifiedType(Ty); return; diff --git a/clang/test/CodeGenCXX/debug-info-local-types.cpp b/clang/test/CodeGenCXX/debug-info-local-types.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-local-types.cpp @@ -0,0 +1,101 @@ +// RUN: %clang_cc1 -triple x86_64-none-linux-gnu -emit-llvm -debug-info-kind=limited -debugger-tuning=gdb %s -o - | FileCheck %s --check-prefixes=CHECK,LIMITED +// RUN: %clang_cc1 -triple x86_64-none-linux-gnu -emit-llvm -debug-info-kind=unused-types -debugger-tuning=gdb %s -o - | FileCheck %s --check-prefixes=UNUSED_TYPES + +void test() { + { + struct S { int a; }; + class C { int b; }; + S s; + { + C c; + } + } + + { + typedef char Char; + using Int = int; + Char c; + { + Int i; + } + } + + { + enum E { a, b, c }; + enum class T { aa, bb, cc }; + E e = E::a; + { + T t = T::aa; + } + } + + { + union U { int i; char c; }; + U u = { 256 }; + } +} + +// LIMITED: distinct !DICompileUnit +// LIMITED-NOT: retainedTypes: + +// CHECK: !DILocalVariable(name: "s", scope: [[LBSCOPE_1:![0-9]+]] +// CHECK-SAME: type: [[STRUCT:![0-9]+]] +// CHECK: [[LBSCOPE_1]] = distinct !DILexicalBlock({{.*}}, localDecls: [[LB1_DECLS:![0-9]+]] +// CHECK: [[LB1_DECLS]] = !{[[STRUCT]], [[CLASS:![0-9]+]]} +// CHECK: [[STRUCT]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "S", scope: [[LBSCOPE_1]] +// CHECK: [[CLASS]] = distinct !DICompositeType(tag: DW_TAG_class_type, name: "C", scope: [[LBSCOPE_1]] +// CHECK: !DILocalVariable(name: "c", scope: [[LBSCOPE_11:![0-9]+]] +// CHECK-SAME: type: [[CLASS]] +// CHECK: [[LBSCOPE_11]] = distinct !DILexicalBlock(scope: [[LBSCOPE_1]] +// +// CHECK: !DILocalVariable(name: "c", scope: [[LBSCOPE_2:![0-9]+]] +// CHECK-SAME: type: [[TYPEDEF:![0-9]+]] +// CHECK: [[LBSCOPE_2]] = distinct !DILexicalBlock({{.*}}, localDecls: [[LB2_DECLS:![0-9]+]] +// CHECK: [[LB2_DECLS]] = !{[[TYPEDEF]], [[USING:![0-9]+]]} +// CHECK: [[TYPEDEF]] = !DIDerivedType(tag: DW_TAG_typedef, name: "Char", scope: [[LBSCOPE_2]] +// CHECK: [[USING]] = !DIDerivedType(tag: DW_TAG_typedef, name: "Int", scope: [[LBSCOPE_2]] +// CHECK: !DILocalVariable(name: "i", scope: [[LBSCOPE_21:![0-9]+]] +// CHECK-SAME: type: [[USING]] +// CHECK: [[LBSCOPE_21]] = distinct !DILexicalBlock(scope: [[LBSCOPE_2]] +// +// CHECK: !DILocalVariable(name: "e", scope: [[LBSCOPE_3:![0-9]+]] +// CHECK-SAME: type: [[ENUM:![0-9]+]] +// CHECK: [[LBSCOPE_3]] = distinct !DILexicalBlock({{.*}}, localDecls: [[LB3_DECLS:![0-9]+]] +// CHECK: [[LB3_DECLS]] = !{[[ENUM]], [[ENUM_CLASS:![0-9]+]]} +// CHECK: [[ENUM]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "E", scope: [[LBSCOPE_3]] +// CHECK: [[ENUM_CLASS]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "T", scope: [[LBSCOPE_3]] +// CHECK: !DILocalVariable(name: "t", scope: [[LBSCOPE_31:![0-9]+]] +// CHECK-SAME: type: [[ENUM_CLASS]] +// CHECK: [[LBSCOPE_31]] = distinct !DILexicalBlock(scope: [[LBSCOPE_3]] +// +// CHECK: !DILocalVariable(name: "u", scope: [[LBSCOPE_4:![0-9]+]] +// CHECK-SAME: type: [[UNION:![0-9]+]] +// CHECK: [[LBSCOPE_4]] = distinct !DILexicalBlock({{.*}}, localDecls: [[LB4_DECLS:![0-9]+]] +// CHECK: [[LB4_DECLS]] = !{[[UNION]]} +// CHECK: [[UNION]] = distinct !DICompositeType(tag: DW_TAG_union_type, name: "U", scope: [[LBSCOPE_4]] + +void test_unused() { + { + struct X {}; + typedef int Y; // typedef doesn't go to retainedTypes. + enum Z { z }; + } +} + +// UNUSED_TYPES: distinct !DICompileUnit +// UNUSED_TYPES-SAME: retainedTypes: [[RETAINED_TYPES:![0-9]+]] +// +// struct, class, char, int, enum, enum class, union, unused struct, unused enum, ::F +// UNUSED_TYPES: [[RETAINED_TYPES]] = !{!{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, [[UNUSED_STRUCT:![0-9]+]], [[UNUSED_ENUM:![0-9]+]], !{{.*}}} +// UNUSED_TYPES: [[UNUSED_STRUCT]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "X", scope: [[UNUSED_LB:![0-9]+]] +// UNUSED_TYPES: [[UNUSED_LB]] = distinct !DILexicalBlock({{.*}}, localDecls: [[UNUSED_LB_DECLS:![0-9]+]] +// UNUSED_TYPES: [[UNUSED_LB_DECLS]] = !{[[UNUSED_STRUCT]], [[UNUSED_ENUM]]} +// UNUSED_TYPES: [[UNUSED_ENUM]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "Z", scope: [[UNUSED_LB]] + +void test_lambda() { + auto t = []() { struct F {}; return F(); }; + auto v = t(); +} + +// TODO: ::F doesn't have its scope specified. +// CHECK: distinct !DICompositeType(tag: DW_TAG_structure_type, name: "F", file