--- /dev/null
+/* 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
--- /dev/null
+/* 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
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,
/// @{
/// 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);
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) {
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);
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;
}
}
}
/// 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) {
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.
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.
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()) {