Index: llvm/trunk/test/tools/dsymutil/X86/odr-fwd-declaration.cpp =================================================================== --- llvm/trunk/test/tools/dsymutil/X86/odr-fwd-declaration.cpp +++ llvm/trunk/test/tools/dsymutil/X86/odr-fwd-declaration.cpp @@ -0,0 +1,127 @@ +/* Compile with: + for FILE in `seq 3`; do + clang -g -c X86/odr-fwd-declaration.cpp -DFILE$FILE -o Inputs/odr-fwd-declaration/$FILE.o + done + */ + +// RUN: llvm-dsymutil -f -oso-prepend-path=%p/../Inputs/odr-fwd-declaration -y %p/dummy-debug-map.map -o - | llvm-dwarfdump -debug-dump=info - | FileCheck %s + +#ifdef FILE1 +# 1 "Header.h" 1 +typedef struct S *Sptr; +typedef Sptr *Sptrptr; +# 3 "Source1.cpp" 2 +void foo() { + Sptrptr ptr1 = 0; +} + +// First we confirm that the typedefs reference the forward declaration of the +// struct S. +// +// CHECK: TAG_variable +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_name{{.*}} "ptr1" +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x{{0*}}[[TYPEDEF1:[a-f0-9]*]] +// +// CHECK: [[TYPEDEF1]]:{{.*}}TAG_typedef +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x{{0*}}[[PTR1:[a-f0-9]*]] +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_name{{.*}} "Sptrptr" +// +// CHECK: [[PTR1]]:{{.*}}TAG_pointer_type +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x{{0*}}[[TYPEDEF2:[a-f0-9]*]] +// +// CHECK: [[TYPEDEF2]]:{{.*}}TAG_typedef +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x{{0*}}[[PTR2:[a-f0-9]*]] +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_name{{.*}} "Sptr" +// +// CHECK: [[PTR2]]:{{.*}}TAG_pointer_type +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x{{0*}}[[FWDSTRUCT:[a-f0-9]*]] +// +// CHECK: [[FWDSTRUCT]]:{{.*}}TAG_structure_type +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_name{{.*}} "S" +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_declaration +// CHECK-NOT AT_byte_size + +#elif defined(FILE2) +# 1 "Header.h" 1 +typedef struct S *Sptr; +typedef Sptr *Sptrptr; +# 3 "Source2.cpp" 2 +struct S { + int field; +}; +void bar() { + Sptrptr ptr2 = 0; +} + +// Next we confirm that the typedefs reference the definition rather than the +// previous declaration of S. +// +// CHECK: TAG_variable +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_name{{.*}} "ptr2" +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x{{0*}}[[TYPEDEF3:[a-f0-9]*]] +// +// CHECK: [[TYPEDEF3]]:{{.*}}TAG_typedef +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x{{0*}}[[PTR3:[a-f0-9]*]] +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_name{{.*}} "Sptrptr" +// +// CHECK: [[PTR3]]:{{.*}}TAG_pointer_type +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x{{0*}}[[TYPEDEF4:[a-f0-9]*]] +// +// CHECK: [[TYPEDEF4]]:{{.*}}TAG_typedef +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x{{0*}}[[PTR4:[a-f0-9]*]] +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_name{{.*}} "Sptr" +// +// CHECK: [[PTR4]]:{{.*}}TAG_pointer_type +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x{{0*}}[[STRUCT:[a-f0-9]*]] +// +// CHECK: [[STRUCT]]:{{.*}}TAG_structure_type +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_name{{.*}} "S" +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK-NOT: AT_declaration +// CHECK: AT_byte_size +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: TAG_member + +#elif defined(FILE3) +# 1 "Header.h" 1 +typedef struct S *Sptr; +typedef Sptr *Sptrptr; +# 3 "Source1.cpp" 2 +void foo() { + Sptrptr ptr1 = 0; +} + +// Finally we confirm that uniquing is not broken and the same typedef is +// referenced by ptr1. +// +// CHECK: TAG_variable +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_name{{.*}} "ptr1" +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x{{0*}}[[TYPEDEF3]] +// CHECK-NOT: TAG_typedef +// CHECK-NOT: TAG_pointer +// CHECK-NOT: TAG_structure_type + +#else +#error "You must define which file you generate" +#endif Index: llvm/trunk/test/tools/dsymutil/X86/odr-fwd-declaration2.cpp =================================================================== --- llvm/trunk/test/tools/dsymutil/X86/odr-fwd-declaration2.cpp +++ llvm/trunk/test/tools/dsymutil/X86/odr-fwd-declaration2.cpp @@ -0,0 +1,151 @@ +/* Compile with: + for FILE in `seq 3`; do + clang -g -c X86/odr-fwd-declaration2.cpp -DFILE$FILE -o Inputs/odr-fwd-declaration2/$FILE.o + done + */ + +// RUN: llvm-dsymutil -f -oso-prepend-path=%p/../Inputs/odr-fwd-declaration2 -y %p/dummy-debug-map.map -o - | llvm-dwarfdump -debug-dump=info - | FileCheck %s + +#ifdef FILE1 +# 1 "Header.h" 1 +struct A { + struct B; + B *bPtr; + B &bRef; + int B::*bPtrToField; +}; +# 3 "Source1.cpp" 2 +void foo() { + A *ptr1 = 0; +} + +// First we confirm that bPtr, bRef and bPtrToField reference the forward +// declaration of the struct B. +// +// CHECK: DW_TAG_member +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_name{{.*}} "bPtr" +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x{{0*}}[[PTR1:[a-f0-9]*]] +// +// CHECK: [[STRUCT1:[a-f0-9]*]]:{{.*}}TAG_structure_type +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_name{{.*}} "B" +// CHECK-NOT: AT_byte_size +// CHECK: DW_AT_declaration +// +// CHECK: DW_TAG_member +// CHECK: AT_name{{.*}} "bRef" +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x{{0*}}[[REF1:[a-f0-9]*]] +// +// CHECK: TAG_member +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_name{{.*}} "bPtrToField" +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x{{0*}}[[PTRTOMEMBER1:[a-f0-9]*]] +// +// CHECK: [[PTR1]]:{{.*}}TAG_pointer_type +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x{{0*}}[[STRUCT1]] +// +// CHECK: [[REF1]]:{{.*}}TAG_reference_type +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x{{0*}}[[STRUCT1]] +// +// CHECK: [[PTRTOMEMBER1]]:{{.*}}TAG_ptr_to_member_type +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_containing_type{{.*}}0x{{0*}}[[STRUCT1]] + +#elif defined(FILE2) +# 1 "Header.h" 1 +struct A { + struct B; + B *bPtr; + B &bRef; + int B::*bPtrToField; +}; +# 3 "Source2.cpp" 2 +struct A::B { + int x; +}; +void bar() { + A *ptr2 = 0; +} + +// Next we confirm that bPtr, bRef and bPtrToField reference the definition of +// B, rather than its declaration. +// +// CHECK: [[STRUCTA:[a-f0-9]*]]:{{.*}}TAG_structure_type +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_name{{.*}} "A" +// CHECK-NOT: AT_byte_size +// CHECK: DW_AT_byte_size +// +// CHECK: DW_TAG_member +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_name{{.*}} "bPtr" +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x{{0*}}[[PTR2:[a-f0-9]*]] +// +// CHECK: [[STRUCT2:[a-f0-9]*]]:{{.*}}TAG_structure_type +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_name{{.*}} "B" +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: DW_AT_byte_size +// +// CHECK: DW_TAG_member +// CHECK: AT_name{{.*}} "bRef" +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x{{0*}}[[REF2:[a-f0-9]*]] +// +// CHECK: TAG_member +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_name{{.*}} "bPtrToField" +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x{{0*}}[[PTRTOMEMBER2:[a-f0-9]*]] +// +// CHECK: [[PTR2]]:{{.*}}TAG_pointer_type +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x{{0*}}[[STRUCT2]] +// +// CHECK: [[REF2]]:{{.*}}TAG_reference_type +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x{{0*}}[[STRUCT2]] +// +// CHECK: [[PTRTOMEMBER2]]:{{.*}}TAG_ptr_to_member_type +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_containing_type{{.*}}0x{{0*}}[[STRUCT2:[a-f0-9]*]] + +#elif defined(FILE3) +# 1 "Header.h" 1 +struct A { + struct B; + B *bPtr; + B &bRef; + int B::*bPtrToField; +}; +# 3 "Source2.cpp" 2 +struct A::B { + int x; +}; +void bar() { + A *ptr2 = 0; +} + +// Finally we confirm that uniquing isn't broken by checking that further +// references to 'struct A' point to its now complete definition. +// +// CHECK: TAG_variable +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_name{{.*}} "ptr2" +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x{{0*}}[[PTR3:[a-f0-9]*]] +// +// CHECK: [[PTR3]]:{{.*}}TAG_pointer_type +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x{{0*}}[[STRUCTA]] + +#else +#error "You must define which file you generate" +#endif Index: llvm/trunk/tools/dsymutil/DwarfLinker.cpp =================================================================== --- llvm/trunk/tools/dsymutil/DwarfLinker.cpp +++ llvm/trunk/tools/dsymutil/DwarfLinker.cpp @@ -185,13 +185,14 @@ public: /// Information gathered about a DIE in the object file. struct DIEInfo { - int64_t AddrAdjust; ///< Address offset to apply to the described entity. - DeclContext *Ctxt; ///< ODR Declaration context. - DIE *Clone; ///< Cloned version of that DIE. - uint32_t ParentIdx; ///< The index of this DIE's parent. - bool Keep : 1; ///< Is the DIE part of the linked output? - bool InDebugMap : 1;///< Was this DIE's entity found in the map? - bool Prune : 1; ///< Is this a pure forward declaration we can strip? + int64_t AddrAdjust; ///< Address offset to apply to the described entity. + DeclContext *Ctxt; ///< ODR Declaration context. + DIE *Clone; ///< Cloned version of that DIE. + uint32_t ParentIdx; ///< The index of this DIE's parent. + bool Keep : 1; ///< Is the DIE part of the linked output? + bool InDebugMap : 1; ///< Was this DIE's entity found in the map? + bool Prune : 1; ///< Is this a pure forward declaration we can strip? + bool Incomplete : 1; ///< Does DIE transitively refer an incomplete decl? }; CompileUnit(DWARFUnit &OrigUnit, unsigned ID, bool CanUseODR, @@ -1198,8 +1199,9 @@ /// @{ /// Recursively walk the \p DIE tree and look for DIEs to /// keep. Store that information in \p CU's DIEInfo. - void lookForDIEsToKeep(RelocationManager &RelocMgr, - const DWARFDie &DIE, + /// + /// The return value indicates whether the DIE is incomplete. + bool lookForDIEsToKeep(RelocationManager &RelocMgr, const DWARFDie &DIE, const DebugMapObject &DMO, CompileUnit &CU, unsigned Flags); @@ -2196,6 +2198,11 @@ DWARFUnit &Unit = CU.getOrigUnit(); MyInfo.Keep = true; + // We're looking for incomplete types. + MyInfo.Incomplete = Die.getTag() != dwarf::DW_TAG_subprogram && + Die.getTag() != dwarf::DW_TAG_member && + dwarf::toUnsigned(Die.find(dwarf::DW_AT_declaration), 0); + // First mark all the parent chain as kept. unsigned AncestorIdx = MyInfo.ParentIdx; while (!CU.getInfo(AncestorIdx).Keep) { @@ -2211,7 +2218,7 @@ const auto *Abbrev = Die.getAbbreviationDeclarationPtr(); uint32_t Offset = Die.getOffset() + getULEB128Size(Abbrev->getCode()); - // Mark all DIEs referenced through atttributes as kept. + // Mark all DIEs referenced through attributes as kept. for (const auto &AttrSpec : Abbrev->attributes()) { DWARFFormValue Val(AttrSpec.Form); @@ -2251,6 +2258,16 @@ unsigned ODRFlag = UseODR ? TF_ODR : 0; lookForDIEsToKeep(RelocMgr, RefDie, DMO, *ReferencedCU, TF_Keep | TF_DependencyWalk | ODRFlag); + + // The incomplete property is propagated if the current DIE is complete + // but references an incomplete DIE. + if (Info.Incomplete && !MyInfo.Incomplete && + (Die.getTag() == dwarf::DW_TAG_typedef || + Die.getTag() == dwarf::DW_TAG_member || + Die.getTag() == dwarf::DW_TAG_reference_type || + Die.getTag() == dwarf::DW_TAG_ptr_to_member_type || + Die.getTag() == dwarf::DW_TAG_pointer_type)) + MyInfo.Incomplete = true; } } } @@ -2267,7 +2284,9 @@ /// also called, but during these dependency walks the file order is /// not respected. The TF_DependencyWalk flag tells us which kind of /// traversal we are currently doing. -void DwarfLinker::lookForDIEsToKeep(RelocationManager &RelocMgr, +/// +/// The return value indicates whether the DIE is incomplete. +bool DwarfLinker::lookForDIEsToKeep(RelocationManager &RelocMgr, const DWARFDie &Die, const DebugMapObject &DMO, CompileUnit &CU, unsigned Flags) { @@ -2275,13 +2294,13 @@ CompileUnit::DIEInfo &MyInfo = CU.getInfo(Idx); bool AlreadyKept = MyInfo.Keep; if (MyInfo.Prune) - return; + return true; // If the Keep flag is set, we are marking a required DIE's // dependencies. If our target is already marked as kept, we're all // set. if ((Flags & TF_DependencyWalk) && AlreadyKept) - return; + return MyInfo.Incomplete; // We must not call shouldKeepDIE while called from keepDIEAndDependencies, // because it would screw up the relocation finding logic. @@ -2303,10 +2322,19 @@ Flags &= ~TF_ParentWalk; if (!Die.hasChildren() || (Flags & TF_ParentWalk)) - return; + return MyInfo.Incomplete; - for (auto Child: Die.children()) - lookForDIEsToKeep(RelocMgr, Child, DMO, CU, Flags); + bool Incomplete = false; + for (auto Child : Die.children()) { + Incomplete |= lookForDIEsToKeep(RelocMgr, Child, DMO, CU, Flags); + + // If any of the members are incomplete we propagate the incompleteness. + if (!MyInfo.Incomplete && Incomplete && + (Die.getTag() == dwarf::DW_TAG_structure_type || + Die.getTag() == dwarf::DW_TAG_class_type)) + MyInfo.Incomplete = true; + } + return MyInfo.Incomplete; } /// Assign an abbreviation numer to \p Abbrev. @@ -2716,7 +2744,7 @@ assert(Die->getTag() == InputDIE.getTag()); Die->setOffset(OutOffset); - if ((Unit.hasODR() || Unit.isClangModule()) && + if ((Unit.hasODR() || Unit.isClangModule()) && !Info.Incomplete && Die->getTag() != dwarf::DW_TAG_namespace && Info.Ctxt && Info.Ctxt != Unit.getInfo(Info.ParentIdx).Ctxt && !Info.Ctxt->getCanonicalDIEOffset()) {