Skip to content

Commit eab652e

Browse files
committed
Auto merge of #54004 - tromey:enum-debuginfo, r=tromey
Fix DWARF generation for enums The DWARF generated for Rust enums was always somewhat unusual. Rather than using DWARF constructs directly, it would emit magic field names like "RUST$ENCODED$ENUM$0$Name" and "RUST$ENUM$DISR". Since PR #45225, though, even this has not worked -- the ad hoc scheme was not updated to handle the wider variety of niche-filling layout optimizations now available. This patch changes the generated DWARF to use the standard tags meant for this purpose; namely, DW_TAG_variant and DW_TAG_variant_part. The patch to implement this went in to LLVM 7. In order to work with older versions of LLVM, and because LLVM doesn't do anything here for PDB, the existing code is kept as a fallback mode. Support for this DWARF is in the Rust lldb and in gdb 8.2. Closes #32920 Closes #32924 Closes #52762 Closes #53153
2 parents 6188c58 + f18b572 commit eab652e

26 files changed

+1636
-219
lines changed

src/ci/docker/x86_64-gnu/Dockerfile

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM ubuntu:16.04
1+
FROM ubuntu:18.04
22

33
RUN apt-get update && apt-get install -y --no-install-recommends \
44
g++ \
@@ -9,10 +9,14 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
99
python2.7 \
1010
git \
1111
cmake \
12+
software-properties-common \
1213
sudo \
13-
gdb \
1414
xz-utils
1515

16+
RUN add-apt-repository ppa:ubuntu-toolchain-r/test && \
17+
apt-get update && \
18+
apt-get install -y --no-install-recommends gdb
19+
1620
COPY scripts/sccache.sh /scripts/
1721
RUN sh /scripts/sccache.sh
1822

src/librustc_codegen_llvm/debuginfo/metadata.rs

+381-144
Large diffs are not rendered by default.

src/librustc_codegen_llvm/llvm/ffi.rs

+28-1
Original file line numberDiff line numberDiff line change
@@ -1304,6 +1304,19 @@ extern "C" {
13041304
Ty: &'a DIType)
13051305
-> &'a DIDerivedType;
13061306

1307+
pub fn LLVMRustDIBuilderCreateVariantMemberType(Builder: &DIBuilder<'a>,
1308+
Scope: &'a DIScope,
1309+
Name: *const c_char,
1310+
File: &'a DIFile,
1311+
LineNumber: c_uint,
1312+
SizeInBits: u64,
1313+
AlignInBits: u32,
1314+
OffsetInBits: u64,
1315+
Discriminant: Option<&'a Value>,
1316+
Flags: DIFlags,
1317+
Ty: &'a DIType)
1318+
-> &'a DIType;
1319+
13071320
pub fn LLVMRustDIBuilderCreateLexicalBlock(Builder: &DIBuilder<'a>,
13081321
Scope: &'a DIScope,
13091322
File: &'a DIFile,
@@ -1381,7 +1394,8 @@ extern "C" {
13811394
SizeInBits: u64,
13821395
AlignInBits: u32,
13831396
Elements: &'a DIArray,
1384-
ClassType: &'a DIType)
1397+
ClassType: &'a DIType,
1398+
IsFixed: bool)
13851399
-> &'a DIType;
13861400

13871401
pub fn LLVMRustDIBuilderCreateUnionType(Builder: &DIBuilder<'a>,
@@ -1397,6 +1411,19 @@ extern "C" {
13971411
UniqueId: *const c_char)
13981412
-> &'a DIType;
13991413

1414+
pub fn LLVMRustDIBuilderCreateVariantPart(Builder: &DIBuilder<'a>,
1415+
Scope: &'a DIScope,
1416+
Name: *const c_char,
1417+
File: &'a DIFile,
1418+
LineNo: c_uint,
1419+
SizeInBits: u64,
1420+
AlignInBits: u32,
1421+
Flags: DIFlags,
1422+
Discriminator: Option<&'a DIDerivedType>,
1423+
Elements: &'a DIArray,
1424+
UniqueId: *const c_char)
1425+
-> &'a DIDerivedType;
1426+
14001427
pub fn LLVMSetUnnamedAddr(GlobalVar: &Value, UnnamedAddr: Bool);
14011428

14021429
pub fn LLVMRustDIBuilderCreateTemplateTypeParameter(Builder: &DIBuilder<'a>,

src/rustllvm/RustWrapper.cpp

+47-2
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,21 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStructType(
687687
unwrapDI<DIType>(VTableHolder), UniqueId));
688688
}
689689

690+
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantPart(
691+
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
692+
LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits,
693+
uint32_t AlignInBits, LLVMRustDIFlags Flags, LLVMMetadataRef Discriminator,
694+
LLVMMetadataRef Elements, const char *UniqueId) {
695+
#if LLVM_VERSION_GE(7, 0)
696+
return wrap(Builder->createVariantPart(
697+
unwrapDI<DIDescriptor>(Scope), Name, unwrapDI<DIFile>(File), LineNumber,
698+
SizeInBits, AlignInBits, fromRust(Flags), unwrapDI<DIDerivedType>(Discriminator),
699+
DINodeArray(unwrapDI<MDTuple>(Elements)), UniqueId));
700+
#else
701+
abort();
702+
#endif
703+
}
704+
690705
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMemberType(
691706
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
692707
LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits,
@@ -698,6 +713,28 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMemberType(
698713
fromRust(Flags), unwrapDI<DIType>(Ty)));
699714
}
700715

716+
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantMemberType(
717+
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope,
718+
const char *Name, LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits,
719+
uint32_t AlignInBits, uint64_t OffsetInBits, LLVMValueRef Discriminant,
720+
LLVMRustDIFlags Flags, LLVMMetadataRef Ty) {
721+
#if LLVM_VERSION_GE(7, 0)
722+
llvm::ConstantInt* D = nullptr;
723+
if (Discriminant) {
724+
D = unwrap<llvm::ConstantInt>(Discriminant);
725+
}
726+
return wrap(Builder->createVariantMemberType(unwrapDI<DIDescriptor>(Scope), Name,
727+
unwrapDI<DIFile>(File), LineNo,
728+
SizeInBits, AlignInBits, OffsetInBits, D,
729+
fromRust(Flags), unwrapDI<DIType>(Ty)));
730+
#else
731+
return wrap(Builder->createMemberType(unwrapDI<DIDescriptor>(Scope), Name,
732+
unwrapDI<DIFile>(File), LineNo,
733+
SizeInBits, AlignInBits, OffsetInBits,
734+
fromRust(Flags), unwrapDI<DIType>(Ty)));
735+
#endif
736+
}
737+
701738
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateLexicalBlock(
702739
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope,
703740
LLVMMetadataRef File, unsigned Line, unsigned Col) {
@@ -800,11 +837,19 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerationType(
800837
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
801838
LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits,
802839
uint32_t AlignInBits, LLVMMetadataRef Elements,
803-
LLVMMetadataRef ClassTy) {
840+
LLVMMetadataRef ClassTy, bool IsFixed) {
841+
#if LLVM_VERSION_GE(7, 0)
804842
return wrap(Builder->createEnumerationType(
805843
unwrapDI<DIDescriptor>(Scope), Name, unwrapDI<DIFile>(File), LineNumber,
806844
SizeInBits, AlignInBits, DINodeArray(unwrapDI<MDTuple>(Elements)),
807-
unwrapDI<DIType>(ClassTy)));
845+
unwrapDI<DIType>(ClassTy), "", IsFixed));
846+
#else
847+
// Ignore IsFixed on older LLVM.
848+
return wrap(Builder->createEnumerationType(
849+
unwrapDI<DIDescriptor>(Scope), Name, unwrapDI<DIFile>(File), LineNumber,
850+
SizeInBits, AlignInBits, DINodeArray(unwrapDI<MDTuple>(Elements)),
851+
unwrapDI<DIType>(ClassTy), ""));
852+
#endif
808853
}
809854

810855
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateUnionType(

src/test/codegen/enum-debug-clike.rs

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// This test depends on a patch that was committed to upstream LLVM
12+
// before 7.0, then backported to the Rust LLVM fork. It tests that
13+
// debug info for "c-like" enums is properly emitted.
14+
15+
// ignore-tidy-linelength
16+
// ignore-windows
17+
// min-system-llvm-version 7.0
18+
19+
// compile-flags: -g -C no-prepopulate-passes
20+
21+
// CHECK-LABEL: @main
22+
// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_enumeration_type,{{.*}}name: "E",{{.*}}flags: DIFlagFixedEnum,{{.*}}
23+
// CHECK: {{.*}}DIEnumerator{{.*}}name: "A",{{.*}}value: {{[0-9].*}}
24+
// CHECK: {{.*}}DIEnumerator{{.*}}name: "B",{{.*}}value: {{[0-9].*}}
25+
// CHECK: {{.*}}DIEnumerator{{.*}}name: "C",{{.*}}value: {{[0-9].*}}
26+
27+
#![allow(dead_code)]
28+
#![allow(unused_variables)]
29+
#![allow(unused_assignments)]
30+
31+
enum E { A, B, C }
32+
33+
pub fn main() {
34+
let e = E::C;
35+
}

src/test/codegen/enum-debug-niche.rs

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// This test depends on a patch that was committed to upstream LLVM
12+
// before 7.0, then backported to the Rust LLVM fork. It tests that
13+
// optimized enum debug info accurately reflects the enum layout.
14+
15+
// ignore-tidy-linelength
16+
// ignore-windows
17+
// min-system-llvm-version 7.0
18+
19+
// compile-flags: -g -C no-prepopulate-passes
20+
21+
// CHECK-LABEL: @main
22+
// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_variant_part,{{.*}}discriminator:{{.*}}
23+
// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "A",{{.*}}extraData:{{.*}}
24+
// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "A",{{.*}}
25+
// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "B",{{.*}}extraData:{{.*}}
26+
// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "B",{{.*}}
27+
// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "C",{{.*}}extraData:{{.*}}
28+
// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "C",{{.*}}
29+
// CHECK-NOT: {{.*}}DIDerivedType{{.*}}name: "D",{{.*}}extraData:{{.*}}
30+
// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "D",{{.*}}
31+
// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "D",{{.*}}
32+
// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}flags: DIFlagArtificial{{.*}}
33+
34+
#![allow(dead_code)]
35+
#![allow(unused_variables)]
36+
#![allow(unused_assignments)]
37+
38+
enum E { A, B, C, D(bool) }
39+
40+
pub fn main() {
41+
let e = E::D(true);
42+
}

src/test/codegen/enum-debug-tagged.rs

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// This test depends on a patch that was committed to upstream LLVM
12+
// before 7.0, then backported to the Rust LLVM fork. It tests that
13+
// debug info for tagged (ordinary) enums is properly emitted.
14+
15+
// ignore-tidy-linelength
16+
// ignore-windows
17+
// min-system-llvm-version 7.0
18+
19+
// compile-flags: -g -C no-prepopulate-passes
20+
21+
// CHECK-LABEL: @main
22+
// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "E",{{.*}}
23+
// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_variant_part,{{.*}}discriminator:{{.*}}
24+
// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "A",{{.*}}extraData:{{.*}}
25+
// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "A",{{.*}}
26+
// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "__0",{{.*}}
27+
// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "B",{{.*}}extraData:{{.*}}
28+
// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "B",{{.*}}
29+
// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "__0",{{.*}}
30+
// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}flags: DIFlagArtificial{{.*}}
31+
32+
#![allow(dead_code)]
33+
#![allow(unused_variables)]
34+
#![allow(unused_assignments)]
35+
36+
enum E { A(u32), B(u32) }
37+
38+
pub fn main() {
39+
let e = E::A(23);
40+
}
+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// ignore-tidy-linelength
12+
// min-lldb-version: 310
13+
14+
// As long as LLVM 5 and LLVM 6 are supported, we want to test the
15+
// enum debuginfo fallback mode. Once those are desupported, this
16+
// test can be removed, as there is another (non-"legacy") test that
17+
// tests the new mode.
18+
// ignore-llvm-version: 7.0 - 9.9.9
19+
// ignore-gdb-version: 7.11.90 - 7.12.9
20+
// ignore-gdb-version: 8.2 - 9.9
21+
22+
// compile-flags:-g
23+
24+
// === GDB TESTS ===================================================================================
25+
26+
// gdb-command:run
27+
28+
// gdb-command:print *the_a_ref
29+
// gdbg-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, [...]}}
30+
// gdbr-check:$1 = borrowed_enum_legacy::ABC::TheA{x: 0, y: 8970181431921507452}
31+
32+
// gdb-command:print *the_b_ref
33+
// gdbg-check:$2 = {{RUST$ENUM$DISR = TheB, [...]}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}}
34+
// gdbr-check:$2 = borrowed_enum_legacy::ABC::TheB(0, 286331153, 286331153)
35+
36+
// gdb-command:print *univariant_ref
37+
// gdbg-check:$3 = {{__0 = 4820353753753434}}
38+
// gdbr-check:$3 = borrowed_enum_legacy::Univariant::TheOnlyCase(4820353753753434)
39+
40+
41+
// === LLDB TESTS ==================================================================================
42+
43+
// lldb-command:run
44+
45+
// lldb-command:print *the_a_ref
46+
// lldb-check:[...]$0 = TheA { x: 0, y: 8970181431921507452 }
47+
// lldb-command:print *the_b_ref
48+
// lldb-check:[...]$1 = TheB(0, 286331153, 286331153)
49+
// lldb-command:print *univariant_ref
50+
// lldb-check:[...]$2 = TheOnlyCase(4820353753753434)
51+
52+
#![allow(unused_variables)]
53+
#![feature(omit_gdb_pretty_printer_section)]
54+
#![omit_gdb_pretty_printer_section]
55+
56+
// The first element is to ensure proper alignment, irrespective of the machines word size. Since
57+
// the size of the discriminant value is machine dependent, this has be taken into account when
58+
// datatype layout should be predictable as in this case.
59+
enum ABC {
60+
TheA { x: i64, y: i64 },
61+
TheB (i64, i32, i32),
62+
}
63+
64+
// This is a special case since it does not have the implicit discriminant field.
65+
enum Univariant {
66+
TheOnlyCase(i64)
67+
}
68+
69+
fn main() {
70+
71+
// 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452
72+
// 0b01111100011111000111110001111100 = 2088533116
73+
// 0b0111110001111100 = 31868
74+
// 0b01111100 = 124
75+
let the_a = ABC::TheA { x: 0, y: 8970181431921507452 };
76+
let the_a_ref: &ABC = &the_a;
77+
78+
// 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
79+
// 0b00010001000100010001000100010001 = 286331153
80+
// 0b0001000100010001 = 4369
81+
// 0b00010001 = 17
82+
let the_b = ABC::TheB (0, 286331153, 286331153);
83+
let the_b_ref: &ABC = &the_b;
84+
85+
let univariant = Univariant::TheOnlyCase(4820353753753434);
86+
let univariant_ref: &Univariant = &univariant;
87+
88+
zzz(); // #break
89+
}
90+
91+
fn zzz() {()}

src/test/debuginfo/borrowed-enum.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010

1111
// ignore-tidy-linelength
1212
// min-lldb-version: 310
13-
// ignore-gdb-version: 7.11.90 - 7.12.9
13+
14+
// Require LLVM with DW_TAG_variant_part and a gdb that can read it.
15+
// min-system-llvm-version: 7.0
16+
// min-gdb-version: 8.2
1417

1518
// compile-flags:-g
1619

@@ -19,15 +22,12 @@
1922
// gdb-command:run
2023

2124
// gdb-command:print *the_a_ref
22-
// gdbg-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, [...]}}
2325
// gdbr-check:$1 = borrowed_enum::ABC::TheA{x: 0, y: 8970181431921507452}
2426

2527
// gdb-command:print *the_b_ref
26-
// gdbg-check:$2 = {{RUST$ENUM$DISR = TheB, [...]}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}}
2728
// gdbr-check:$2 = borrowed_enum::ABC::TheB(0, 286331153, 286331153)
2829

2930
// gdb-command:print *univariant_ref
30-
// gdbg-check:$3 = {{__0 = 4820353753753434}}
3131
// gdbr-check:$3 = borrowed_enum::Univariant::TheOnlyCase(4820353753753434)
3232

3333

0 commit comments

Comments
 (0)