From d9063658c8ab84f970488020d1c0c26b1e488ce9 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Thu, 31 Aug 2017 20:22:31 +0000 Subject: [PATCH] [dsymutil] Don't mark forward declarations as canonical. This patch completes the work done by Frederic Riss to addresses dsymutil incorrectly considering forward declaration as canonical during uniquing. This resulted in references to the forward declaration even after the definition was encountered. In addition to the test provided by Alexander Shaposhnikov in D29609, I added another test to cover several scenarios that were mentioned in his conversation with Fred. We now also check that uniquing still occurs after the definition was encountered. For more context please refer to D29609 Differential revision: https://reviews.llvm.org/D37127 llvm-svn: 312274 --- .../dsymutil/Inputs/odr-fwd-declaration/1.o | Bin 0 -> 2148 bytes .../dsymutil/Inputs/odr-fwd-declaration/2.o | Bin 0 -> 2276 bytes .../dsymutil/Inputs/odr-fwd-declaration/3.o | Bin 0 -> 2148 bytes .../dsymutil/Inputs/odr-fwd-declaration2/1.o | Bin 0 -> 2252 bytes .../dsymutil/Inputs/odr-fwd-declaration2/2.o | Bin 0 -> 2292 bytes .../dsymutil/Inputs/odr-fwd-declaration2/3.o | Bin 0 -> 2292 bytes .../dsymutil/X86/odr-fwd-declaration.cpp | 127 +++++++++++++++ .../dsymutil/X86/odr-fwd-declaration2.cpp | 151 ++++++++++++++++++ llvm/tools/dsymutil/DwarfLinker.cpp | 62 +++++-- 9 files changed, 323 insertions(+), 17 deletions(-) create mode 100644 llvm/test/tools/dsymutil/Inputs/odr-fwd-declaration/1.o create mode 100644 llvm/test/tools/dsymutil/Inputs/odr-fwd-declaration/2.o create mode 100644 llvm/test/tools/dsymutil/Inputs/odr-fwd-declaration/3.o create mode 100644 llvm/test/tools/dsymutil/Inputs/odr-fwd-declaration2/1.o create mode 100644 llvm/test/tools/dsymutil/Inputs/odr-fwd-declaration2/2.o create mode 100644 llvm/test/tools/dsymutil/Inputs/odr-fwd-declaration2/3.o create mode 100644 llvm/test/tools/dsymutil/X86/odr-fwd-declaration.cpp create mode 100644 llvm/test/tools/dsymutil/X86/odr-fwd-declaration2.cpp diff --git a/llvm/test/tools/dsymutil/Inputs/odr-fwd-declaration/1.o b/llvm/test/tools/dsymutil/Inputs/odr-fwd-declaration/1.o new file mode 100644 index 0000000000000000000000000000000000000000..609a8a517be65198c954c0abf6a94888daad3ab7 GIT binary patch literal 2148 zcmb7F-D?wB6hAZhuo^qYR@{mrK@_Ueq{WX7t647CNtTYNsNn# zA0WEy!|H?j=8K4bfd7FHf)DDW`0T=hC_bvow*JnYd$Ua%v3tn*%sIa~_uM;oUVeGM zxQ0lJ5Ck|1e#IgM25kWs*#8D)xe)YG<|rSS#5~A-t$%zwVJ3~4Z4 z*JGn}Mdh$I&9Yr=&Y6DTiLhxNJv%jhypy7E9?8gJ7nlg@on#ma&ngx@yTyJt-V>QT zEA_+J@@irC#j83Mm;dd>Tg$@+wL?XpCEn-&kp$|C=UL92?XSeUD)A&7{Tf$RNB706 zTP4wAZ+{9;!G0glYBXxL=~#7cZ^e4ANuYvk$NO%7A)Z@YC~-+|e{Uq-PKoz?m3X4R zhE?jtTkOI6uu8n(Vx#YRcgSg1WPd~aGIUeVew5rg`U=dZbD`>#P4m>z<>@zNc1i}@ zz~fghi}NB|@4>U@&5DQJ2n$TJ`+a*XvnM6qeTgSsN)XK}o3(mBYE?%d_RjBbiFaBS zy_V~p{6>GgZ%NJ_Tqi2Hd<2}6`330p@X-e;Oqhary>iVmvU)X}yY*M@*|AStasFwk zhSw?8vOT}*I;n%{@$`6VH1L|vFR6VKpaZ*8qqSPAp6SH)9~j?Fh3vtMTlU5(7s_L0 z8z7z)03cmzG$=Fc11_`RI+mXiwR6>A%x^iN6WD%`30$}4XUhJ?dNZijsN%Y0p4$i2 zqDJ6NP#zLLp(#(=Ms1fd9E%vqAGR7BwILi$J&oW{d~(DwBF0aNLy04}s3ZGH9|_$P z!?->-(~05GC5ml;LlhsTh;f)Nb-s(kJ8?kFGD<)4OhEZi3CY)J=UlO)o%tQ|23wJc ze!G2#t>`o)MbAUr1M7OM$bKE-0sC5vFX{M02<&ivD#uS`SZ3a3rf^r|v;<=RmVYzx zZq!=H!p?!kGokl@nYa(GQNF?zt3kXU?*GYA{cQpkQ}~69L&q>UK9?kVef!{U{Ke%z zE=|Jc(eVVh2cF4hFo=i1A)bm1!4f3DQ>tkdCiPV9w`tPaNiDg4&A^|?;`e47IQuWp zX=zD)=V;1E-q3#@#MuyZ3R0&uq^A923_@!B46sIdx9OGa32|Hz%h^`h_R{k(L2G&4 lf;Pnx>rTeB>$;BWy$GQ=zFlh0VE>TR48DPdB2%4cqOa9)|62e6 literal 0 HcmV?d00001 diff --git a/llvm/test/tools/dsymutil/Inputs/odr-fwd-declaration/2.o b/llvm/test/tools/dsymutil/Inputs/odr-fwd-declaration/2.o new file mode 100644 index 0000000000000000000000000000000000000000..c5167109d6954544c955a0200e5e8118571c3c53 GIT binary patch literal 2276 zcmb7FOK%%h6h1S4#O>5mw?=I$5HeDbQc&#lNkn-xqD7AAf+j6kNM#t?lfD#QYzvOtOus)|^^3Rv<3V2Q*s0@Uz*Gk4N>NR)Eq^PF?OIrq%H z*FXRD$Gs5|EhP}(H24>a5*Ty;Duq!I`!)G?2GFuG0trjxi@VfP-21}Ct9Z;(o zQ+PYL*@h{x-VOcr>_!sr*#zFi1L6gjdz-G;R(Q8mPiMEqYjiv4E3o?RrIy>YtTU%J zE+?nXSxE&~fydAa_KO;AV!h6yHSghTLLeBQ3DgvJXsnKyuN#}bmS1|*um0xyFKVs)?-JHO&*lm z)bUEU=}pXEYECpAfOvKQfO4bPlgfD?aFwO5Yx|Y3cA*ta_yad`0>=+3LATrXD^34$ zrysQ1Qnx*^UONIckY3;&mN`iLLM?ML-*VbbX}N)Dd$h;RVkTu4_CIXy(e~mH>171> zW>1c~X3BipIAJ`GD?4>m^wG$jDdHmCCo{#!70K*|Ba$s@Dbp}mftxxnDRZVsX9{j^ z4DNG=!QsCTPIFq43um5|r$SHA*nQ%4yT1SEXs^5nd5u;!rQcZonAXTFq@*uEd~V+!ru1FsgIYRW`!6k-14o(WZ!Ql{L^eZ(KK? z`S$gtDLku!!&ac50F&4rYhpjf4Ht=c5|^0&Cxea7x z`R(Q>*~zQdji0W3@D?x1i{LBZ8{k`D_Qna}^N~11hB(!IU=XLo5XUwK263_sanvdc zR!r)Dk_kf;x2?T7E822FE9@G{eS|E6J_26(hfS}o#s9N1Z5FQSFXW>SAaVvdx|AU` z?Qb&=sqr0PP3F3Nui+dHj|*Z|$8I`ac@ZXP2R~{^`!mMQmonPhx{m565khhHQKgwd R|Af*6-%Syd6`v@Pe*p!i5_kXr literal 0 HcmV?d00001 diff --git a/llvm/test/tools/dsymutil/Inputs/odr-fwd-declaration/3.o b/llvm/test/tools/dsymutil/Inputs/odr-fwd-declaration/3.o new file mode 100644 index 0000000000000000000000000000000000000000..609a8a517be65198c954c0abf6a94888daad3ab7 GIT binary patch literal 2148 zcmb7F-D?wB6hAZhuo^qYR@{mrK@_Ueq{WX7t647CNtTYNsNn# zA0WEy!|H?j=8K4bfd7FHf)DDW`0T=hC_bvow*JnYd$Ua%v3tn*%sIa~_uM;oUVeGM zxQ0lJ5Ck|1e#IgM25kWs*#8D)xe)YG<|rSS#5~A-t$%zwVJ3~4Z4 z*JGn}Mdh$I&9Yr=&Y6DTiLhxNJv%jhypy7E9?8gJ7nlg@on#ma&ngx@yTyJt-V>QT zEA_+J@@irC#j83Mm;dd>Tg$@+wL?XpCEn-&kp$|C=UL92?XSeUD)A&7{Tf$RNB706 zTP4wAZ+{9;!G0glYBXxL=~#7cZ^e4ANuYvk$NO%7A)Z@YC~-+|e{Uq-PKoz?m3X4R zhE?jtTkOI6uu8n(Vx#YRcgSg1WPd~aGIUeVew5rg`U=dZbD`>#P4m>z<>@zNc1i}@ zz~fghi}NB|@4>U@&5DQJ2n$TJ`+a*XvnM6qeTgSsN)XK}o3(mBYE?%d_RjBbiFaBS zy_V~p{6>GgZ%NJ_Tqi2Hd<2}6`330p@X-e;Oqhary>iVmvU)X}yY*M@*|AStasFwk zhSw?8vOT}*I;n%{@$`6VH1L|vFR6VKpaZ*8qqSPAp6SH)9~j?Fh3vtMTlU5(7s_L0 z8z7z)03cmzG$=Fc11_`RI+mXiwR6>A%x^iN6WD%`30$}4XUhJ?dNZijsN%Y0p4$i2 zqDJ6NP#zLLp(#(=Ms1fd9E%vqAGR7BwILi$J&oW{d~(DwBF0aNLy04}s3ZGH9|_$P z!?->-(~05GC5ml;LlhsTh;f)Nb-s(kJ8?kFGD<)4OhEZi3CY)J=UlO)o%tQ|23wJc ze!G2#t>`o)MbAUr1M7OM$bKE-0sC5vFX{M02<&ivD#uS`SZ3a3rf^r|v;<=RmVYzx zZq!=H!p?!kGokl@nYa(GQNF?zt3kXU?*GYA{cQpkQ}~69L&q>UK9?kVef!{U{Ke%z zE=|Jc(eVVh2cF4hFo=i1A)bm1!4f3DQ>tkdCiPV9w`tPaNiDg4&A^|?;`e47IQuWp zX=zD)=V;1E-q3#@#MuyZ3R0&uq^A923_@!B46sIdx9OGa32|Hz%h^`h_R{k(L2G&4 lf;Pnx>rTeB>$;BWy$GQ=zFlh0VE>TR48DPdB2%4cqOa9)|62e6 literal 0 HcmV?d00001 diff --git a/llvm/test/tools/dsymutil/Inputs/odr-fwd-declaration2/1.o b/llvm/test/tools/dsymutil/Inputs/odr-fwd-declaration2/1.o new file mode 100644 index 0000000000000000000000000000000000000000..4597864bc971f8b0353d08042cabe2af79eba2f2 GIT binary patch literal 2252 zcmb7FTWB0*6h1SvGudRi(`~n4#M?epNR{kvOk0B$-Pj9T>_bRW8w43Uq#iie|D12mf1U6D z`s2<7k)jan4 z!FWTT&Cm^*!`il8uijg?qc}{$wteo(;_`(-ip2R!MD7fMB|&wN3`62M^?K;_*&oLH zRwTbB^cVX6>ck$4*YcYIkB;J<<;4bloGO|(QsZWpNC1t+3mt#mi|)qzRp1FY`a$4H zA9^fa$7v)jj`k<PPg0kY~Sf{dw0$EHvzOJ8v60T{!+Z4zS-cC(f+DpHpc~C zg%8^>jm&pne_f|Bisz2tt==bIe7!q%zS{z?DSFyE5U&w*&{u5t{A(@Wwe3si_D|=w zz$=R2Pr&1=w~O;4mUd*m-iF-_u^VZDZ4ckKytubjfk(g*p(J7wZO9?k@_w{ieu6l< zeoLZwNfcFq$Moqv`s01eb3$&4WpX&Dp+6J(Uqc^)k3L9Z!c2(gE6=3}-M6}2+xfZn z-T6Pc;FWJ0ZCs~f-wUHw;1^GqDy2$sCJuZ4)#Cgd=+uegOuOChln1esrz$6CZQ*n| zaKqW=HFwta01`Se0G=u}x?L(?j(}I*416alC&lZncsA<$sS|rqT#kdF9hKeadZ!n+ z+SCjJvR|Hu>Qgrk=V+1YOL*8`p!%}cOzhR*Ld$Er)be9ejwp{?1zof94?JWYQI6s& zsU-xD8r5mv(yV99Gv@PnxV4j{PN(k00-n>u#7ZwHnq``tL}cVhvo03cS%5oHfcq>; zv-u=<@-e7KP&9QM1J9WzZ^te;14dS|3mJMk@rd@n=llQOo_S(HIUM#1P}nM7hb)qaIK%CU`SySbuNk`^vT~S$xU+JMaDGeQ&<+ zn;-xF<5reP=mY`IfUmPCfkF3!7udfGUE@N~O_`&7U=nklAA%ew_WE&Zr~drmh56gQ zvTSKE-q33^bV22?cASP+>n=G_942AMIdpnv?#LiT;aruGTSH(;P#Yw}Pw7J5DQ zhw;9b$#|5|*M>B1t99|3{$ju>qj(2+*r2acMNgQiaWzLIf!4(fU4O}o?!>z(@gyAm zEb){Ny)ItcttTyx_NVX^?8bO*r_=Hr-)(bycdYkM3A7*^`enoZQoNwHQsfG*KzBkcx#XRQ6!bGW+oJ){*=cXk{X>K0;Uj0@eiEKVXa^Q7Ce6_V_+N1z@;8GQ*(uhCpG{tP|EV+5_e$ob|SY(;j&skb5DWXsgGOZ|7* z%FaPj<}`%y9z;%g}!txO|c1tH-fAs)00@tiosGvZ@7MDoAM&xc60C0>~$(JzR?=4|dAWHG>l;Lrc%=2lnLf0t(L z!W-HPd3DWmn;MlNh4{zLLkfNeSkQ@}8`iz_^dMIC+=dsHmtlg&2776{VQxBVh}Sd? b)sN#5ip__m=2Z6gOU>Y0SSWJT0VDbkw7e1N literal 0 HcmV?d00001 diff --git a/llvm/test/tools/dsymutil/Inputs/odr-fwd-declaration2/3.o b/llvm/test/tools/dsymutil/Inputs/odr-fwd-declaration2/3.o new file mode 100644 index 0000000000000000000000000000000000000000..e061c62db73aff48bac5796977c66824c63ec168 GIT binary patch literal 2292 zcmb7FPmB{~6o21LXWC`xP*@Xc{MQ2}i@NQ~KUX2jDv)mAK$ZnICOA&p+1)PfOfxer z#S_M;7%vhp>Oo_S(HIUM#1P}nM7hb)qaIK%CU`SySbuNk`^vT~S$xU+JMaDGeQ&<+ zn;-xF<5reP=mY`IfUmPCfkF3!7udfGUE@N~O_`&7U=nklAA%ew_WE&Zr~drmh56gQ zvTSKE-q33^bV22?cASP+>n=G_942AMIdpnv?#LiT;aruGTSH(;P#Yw}Pw7J5DQ zhw;9b$#|5|*M>B1t99|3{$ju>qj(2+*r2acMNgQiaWzLIf!4(fU4O}o?!>z(@gyAm zEb){Ny)ItcttTyx_NVX^?8bO*r_=Hr-)(bycdYkM3A7*^`enoZQoNwHQsfG*KzBkcx#XRQ6!bGW+oJ){*=cXk{X>K0;Uj0@eiEKVXa^Q7Ce6_V_+N1z@;8GQ*(uhCpG{tP|EV+5_e$ob|SY(;j&skb5DWXsgGOZ|7* z%FaPj<}`%y9z;%g}!txO|c1tH-fAs)00@tiosGvZ@7MDoAM&xc60C0>~$(JzR?=4|dAWHG>l;Lrc%=2lnLf0t(L z!W-HPd3DWmn;MlNh4{zLLkfNeSkQ@}8`iz_^dMIC+=dsHmtlg&2776{VQxBVh}Sd? b)sN#5ip__m=2Z6gOU>Y0SSWJT0VDbkw7e1N literal 0 HcmV?d00001 diff --git a/llvm/test/tools/dsymutil/X86/odr-fwd-declaration.cpp b/llvm/test/tools/dsymutil/X86/odr-fwd-declaration.cpp new file mode 100644 index 0000000000000..7aef0057d214b --- /dev/null +++ b/llvm/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 diff --git a/llvm/test/tools/dsymutil/X86/odr-fwd-declaration2.cpp b/llvm/test/tools/dsymutil/X86/odr-fwd-declaration2.cpp new file mode 100644 index 0000000000000..1b0d261b5bd4c --- /dev/null +++ b/llvm/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 diff --git a/llvm/tools/dsymutil/DwarfLinker.cpp b/llvm/tools/dsymutil/DwarfLinker.cpp index 6b5415a0795e9..7d2eba4864279 100644 --- a/llvm/tools/dsymutil/DwarfLinker.cpp +++ b/llvm/tools/dsymutil/DwarfLinker.cpp @@ -185,13 +185,14 @@ class CompileUnit { 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 @@ class DwarfLinker { /// @{ /// 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 @@ void DwarfLinker::keepDIEAndDependencies(RelocationManager &RelocMgr, 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 @@ void DwarfLinker::keepDIEAndDependencies(RelocationManager &RelocMgr, 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 @@ void DwarfLinker::keepDIEAndDependencies(RelocationManager &RelocMgr, 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 @@ void DwarfLinker::keepDIEAndDependencies(RelocationManager &RelocMgr, /// 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 @@ void DwarfLinker::lookForDIEsToKeep(RelocationManager &RelocMgr, 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 @@ void DwarfLinker::lookForDIEsToKeep(RelocationManager &RelocMgr, 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 @@ DIE *DwarfLinker::DIECloner::cloneDIE( 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()) {