Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -143,7 +143,7 @@ /// A helper function to create children of a Scope DIE. DIE *createScopeChildrenDIE(LexicalScope *Scope, SmallVectorImpl &Children, - unsigned *ChildScopeCount = nullptr); + bool *HasNoneScopeChild = nullptr); /// \brief Construct a DIE for this subprogram scope. void constructSubprogramScopeDIE(LexicalScope *Scope); Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -333,23 +333,15 @@ if (DD->isLexicalScopeDIENull(Scope)) return; - unsigned ChildScopeCount; + bool HasNoneScopeChild; // We create children here when we know the scope DIE is not going to be // null and the children will be added to the scope DIE. - createScopeChildrenDIE(Scope, Children, &ChildScopeCount); - - // Skip imported directives in gmlt-like data. - if (!includeMinimalInlineScopes()) { - // There is no need to emit empty lexical block DIE. - for (const auto &E : DD->findImportedEntitiesForScope(DS)) - Children.push_back( - constructImportedEntityDIE(cast(E.second))); - } + createScopeChildrenDIE(Scope, Children, &HasNoneScopeChild); // If there are only other scopes as children, put them directly in the // parent instead, as this scope would serve no purpose. - if (Children.size() == ChildScopeCount) { + if (!HasNoneScopeChild) { FinalChildren.insert(FinalChildren.end(), std::make_move_iterator(Children.begin()), std::make_move_iterator(Children.end())); @@ -543,20 +535,26 @@ DIE *DwarfCompileUnit::createScopeChildrenDIE(LexicalScope *Scope, SmallVectorImpl &Children, - unsigned *ChildScopeCount) { + bool *HasNoneScopeChild) { DIE *ObjectPointer = nullptr; + auto *DS = Scope->getScopeNode(); for (DbgVariable *DV : DU->getScopeVariables().lookup(Scope)) Children.push_back(constructVariableDIE(*DV, *Scope, ObjectPointer)); - unsigned ChildCountWithoutScopes = Children.size(); + // Skip imported directives in gmlt-like data. + if (!includeMinimalInlineScopes()) { + for (const auto &E : DD->findImportedEntitiesForScope(DS)) + Children.push_back( + constructImportedEntityDIE(cast(E.second))); + } + + if (HasNoneScopeChild) + *HasNoneScopeChild = !Children.empty(); for (LexicalScope *LS : Scope->getChildren()) constructScopeDIE(LS, Children); - if (ChildScopeCount) - *ChildScopeCount = Children.size() - ChildCountWithoutScopes; - return ObjectPointer; } Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -466,7 +466,12 @@ void DwarfDebug::constructAndAddImportedEntityDIE(DwarfCompileUnit &TheCU, const DIImportedEntity *N) { - if (DIE *D = TheCU.getOrCreateContextDIE(N->getScope())) + auto S = N->getScope(); + if (S && isa(S) || isa(S)) + // Delay handling imported entity defined in function/lexical block scope. + // It will be handled when processing the function/lexical block. + return; + if (DIE *D = TheCU.getOrCreateContextDIE(S)) D->addChild(TheCU.constructImportedEntityDIE(N)); } Index: test/DebugInfo/imported_entities.ll =================================================================== --- test/DebugInfo/imported_entities.ll +++ test/DebugInfo/imported_entities.ll @@ -0,0 +1,132 @@ +; RUN: %llc_dwarf -O0 -filetype=obj -dwarf-linkage-names=Enable < %s | llvm-dwarfdump -debug-dump=info - | FileCheck %s + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Test case where imported entities are defined in inlined function scope. +;; The test checks the following: +;; 1. Inlined function "f2" is emitted only as abstract debug info entry and +;; inlined debug info entry. +;; 2. Both entries has two imported DIE children: +;; DW_TAG_imported_module - "NameSpace" +;; DW_TAG_imported_declaration - "TypeDef" +;; +;; Note: The optimal solution would be to emit the imported entries only in the +;; abstratc lexical scope, while debugger be able to correlate between it +;; and the inline lexical scope through DW_AT_abstract_origin attribute. +;; However, this can be implemented only after fixing debugger (gdb/lldb). +;; +;; This test was generated by running following command: +;; clang -cc1 -O0 -g -emit-llvm test.cpp -o - +;; Where test.cpp +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;namespace NameSpace { +;; typedef int TypeDef; +;;} +;; +;;void f1(); +;;inline void __attribute__((always_inline)) f2() { +;; using namespace NameSpace; +;; using NameSpace::TypeDef; +;; f1(); +;;} +;;void f3() { +;; f2(); +;;} +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; CHECK: debug_info contents + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; This part checks for imported entity entries in abstract function entry. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; CHECK: [[F2:.*]]: DW_TAG_subprogram +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_name{{.*}}= "f2" +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_inline + +; CHECK-NOT: NULL +; CHECK: DW_TAG_imported_module +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_import{{.*}}=> {[[NameSpace:0x[0-9a-f]*]]}) + +; CHECK-NOT: NULL +; CHECK: DW_TAG_imported_declaration +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_import{{.*}}=> {[[TypeDef:0x[0-9a-f]*]]}) + +; CHECK: NULL + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; This part checks for declaration entries, which are imported elsewhere. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; CHECK: [[NameSpace]]:{{ *}}DW_TAG_namespace +; CHECK-NEXT: DW_AT_name{{.*}} = "NameSpace" + +; CHECK-NOT: NULL +; CHECK: [[TypeDef]]:{{.*}}DW_TAG_typedef +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_name{{.*}}= "TypeDef" + +; CHECK: NULL + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; This part checks for imported entity entries in inlined function entry. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; CHECK: DW_TAG_subprogram +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_name{{.*}}= "f3" + +; CHECK-NOT: NULL +; CHECK: DW_TAG_inlined_subroutine +; CHECK-NEXT: DW_AT_abstract_origin{{.*}}{[[F2]]} + +; CHECK-NOT: NULL +; CHECK: DW_TAG_imported_module +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_import{{.*}}=> {[[NameSpace:0x[0-9a-f]*]]}) + +; CHECK-NOT: NULL +; CHECK: DW_TAG_imported_declaration +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_import{{.*}}=> {[[TypeDef:0x[0-9a-f]*]]}) + +; CHECK: NULL +; CHECK-NOT: DW_TAG_subprogram + +; Function Attrs: nounwind +define void @"\01?f3@@YAXXZ"() #0 { +entry: + call void @"\01?f1@@YAXXZ"() #2, !dbg !17 + ret void, !dbg !19 +} + +declare void @"\01?f1@@YAXXZ"() #1 + +attributes #0 = { nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!14, !15} +!llvm.ident = !{!16} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (trunk 246757)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, subprograms: !3, imports: !8) +!1 = !DIFile(filename: "test.cpp", directory: "/") +!2 = !{} +!3 = !{!4, !7} +!4 = distinct !DISubprogram(name: "f3", linkageName: "\01?f3@@YAXXZ", scope: !1, file: !1, line: 10, type: !5, isLocal: false, isDefinition: true, scopeLine: 10, flags: DIFlagPrototyped, isOptimized: false, function: void ()* @"\01?f3@@YAXXZ", variables: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{null} +!7 = distinct !DISubprogram(name: "f2", linkageName: "\01?f2@@YAXXZ", scope: !1, file: !1, line: 5, type: !5, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false, variables: !2) +!8 = !{!9, !11} +!9 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !7, entity: !10, line: 6) +!10 = !DINamespace(name: "NameSpace", scope: null, file: !1, line: 1) +!11 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !7, entity: !12, line: 7) +!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "TypeDef", scope: !10, file: !1, line: 2, baseType: !13) +!13 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!14 = !{i32 2, !"Dwarf Version", i32 4} +!15 = !{i32 2, !"Debug Info Version", i32 3} +!16 = !{!"clang version 3.8.0 (trunk 246757)"} +!17 = !DILocation(line: 8, scope: !7, inlinedAt: !18) +!18 = distinct !DILocation(line: 11, scope: !4) +!19 = !DILocation(line: 12, scope: !4) Index: test/DebugInfo/namespace.ll =================================================================== --- test/DebugInfo/namespace.ll +++ test/DebugInfo/namespace.ll @@ -23,6 +23,11 @@ ; CHECK-NOT: NULL ; CHECK: [[BAR:0x[0-9a-f]*]]:{{ *}}DW_TAG_structure_type ; CHECK-NEXT: DW_AT_name{{.*}}= "bar" +; CHECK: DW_TAG_subprogram +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_MIPS_linkage_name +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_name{{.*}}= "f1" ; CHECK: [[FUNC1:.*]]: DW_TAG_subprogram ; CHECK-NOT: DW_TAG ; CHECK: DW_AT_MIPS_linkage_name @@ -45,11 +50,6 @@ ; CHECK-NOT: DW_TAG ; CHECK: DW_AT_name{{.*}}= "func_fwd" ; CHECK-NOT: DW_AT_declaration -; CHECK: DW_TAG_subprogram -; CHECK-NOT: DW_TAG -; CHECK: DW_AT_MIPS_linkage_name -; CHECK-NOT: DW_TAG -; CHECK: DW_AT_name{{.*}}= "f1" ; CHECK: NULL ; CHECK-NOT: NULL @@ -70,6 +70,10 @@ ; CHECK-NOT: NULL ; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name{{.*}}= "__cxx_global_var_init" +; CHECK-NOT: DW_TAG + +; CHECK: DW_TAG_subprogram ; CHECK-NOT: DW_TAG ; CHECK: DW_AT_MIPS_linkage_name ; CHECK-NOT: DW_TAG