Skip to content

Commit 0db7abe

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 1cf82fd + 98b2688 commit 0db7abe

32 files changed

+1691
-261
lines changed

src/ci/docker/x86_64-gnu/Dockerfile

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

33
RUN apt-get update && apt-get install -y --no-install-recommends \
44
g++ \

src/librustc_codegen_llvm/debuginfo/metadata.rs

+382-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
@@ -1307,6 +1307,19 @@ extern "C" {
13071307
Ty: &'a DIType)
13081308
-> &'a DIDerivedType;
13091309

1310+
pub fn LLVMRustDIBuilderCreateVariantMemberType(Builder: &DIBuilder<'a>,
1311+
Scope: &'a DIScope,
1312+
Name: *const c_char,
1313+
File: &'a DIFile,
1314+
LineNumber: c_uint,
1315+
SizeInBits: u64,
1316+
AlignInBits: u32,
1317+
OffsetInBits: u64,
1318+
Discriminant: Option<&'a Value>,
1319+
Flags: DIFlags,
1320+
Ty: &'a DIType)
1321+
-> &'a DIType;
1322+
13101323
pub fn LLVMRustDIBuilderCreateLexicalBlock(Builder: &DIBuilder<'a>,
13111324
Scope: &'a DIScope,
13121325
File: &'a DIFile,
@@ -1384,7 +1397,8 @@ extern "C" {
13841397
SizeInBits: u64,
13851398
AlignInBits: u32,
13861399
Elements: &'a DIArray,
1387-
ClassType: &'a DIType)
1400+
ClassType: &'a DIType,
1401+
IsFixed: bool)
13881402
-> &'a DIType;
13891403

13901404
pub fn LLVMRustDIBuilderCreateUnionType(Builder: &DIBuilder<'a>,
@@ -1400,6 +1414,19 @@ extern "C" {
14001414
UniqueId: *const c_char)
14011415
-> &'a DIType;
14021416

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

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

src/rustllvm/RustWrapper.cpp

+47-2
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,21 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStructType(
713713
unwrapDI<DIType>(VTableHolder), UniqueId));
714714
}
715715

716+
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantPart(
717+
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
718+
LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits,
719+
uint32_t AlignInBits, LLVMRustDIFlags Flags, LLVMMetadataRef Discriminator,
720+
LLVMMetadataRef Elements, const char *UniqueId) {
721+
#if LLVM_VERSION_GE(7, 0)
722+
return wrap(Builder->createVariantPart(
723+
unwrapDI<DIDescriptor>(Scope), Name, unwrapDI<DIFile>(File), LineNumber,
724+
SizeInBits, AlignInBits, fromRust(Flags), unwrapDI<DIDerivedType>(Discriminator),
725+
DINodeArray(unwrapDI<MDTuple>(Elements)), UniqueId));
726+
#else
727+
abort();
728+
#endif
729+
}
730+
716731
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMemberType(
717732
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
718733
LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits,
@@ -724,6 +739,28 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMemberType(
724739
fromRust(Flags), unwrapDI<DIType>(Ty)));
725740
}
726741

742+
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantMemberType(
743+
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope,
744+
const char *Name, LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits,
745+
uint32_t AlignInBits, uint64_t OffsetInBits, LLVMValueRef Discriminant,
746+
LLVMRustDIFlags Flags, LLVMMetadataRef Ty) {
747+
#if LLVM_VERSION_GE(7, 0)
748+
llvm::ConstantInt* D = nullptr;
749+
if (Discriminant) {
750+
D = unwrap<llvm::ConstantInt>(Discriminant);
751+
}
752+
return wrap(Builder->createVariantMemberType(unwrapDI<DIDescriptor>(Scope), Name,
753+
unwrapDI<DIFile>(File), LineNo,
754+
SizeInBits, AlignInBits, OffsetInBits, D,
755+
fromRust(Flags), unwrapDI<DIType>(Ty)));
756+
#else
757+
return wrap(Builder->createMemberType(unwrapDI<DIDescriptor>(Scope), Name,
758+
unwrapDI<DIFile>(File), LineNo,
759+
SizeInBits, AlignInBits, OffsetInBits,
760+
fromRust(Flags), unwrapDI<DIType>(Ty)));
761+
#endif
762+
}
763+
727764
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateLexicalBlock(
728765
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope,
729766
LLVMMetadataRef File, unsigned Line, unsigned Col) {
@@ -826,11 +863,19 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerationType(
826863
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
827864
LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits,
828865
uint32_t AlignInBits, LLVMMetadataRef Elements,
829-
LLVMMetadataRef ClassTy) {
866+
LLVMMetadataRef ClassTy, bool IsFixed) {
867+
#if LLVM_VERSION_GE(7, 0)
830868
return wrap(Builder->createEnumerationType(
831869
unwrapDI<DIDescriptor>(Scope), Name, unwrapDI<DIFile>(File), LineNumber,
832870
SizeInBits, AlignInBits, DINodeArray(unwrapDI<MDTuple>(Elements)),
833-
unwrapDI<DIType>(ClassTy)));
871+
unwrapDI<DIType>(ClassTy), "", IsFixed));
872+
#else
873+
// Ignore IsFixed on older LLVM.
874+
return wrap(Builder->createEnumerationType(
875+
unwrapDI<DIDescriptor>(Scope), Name, unwrapDI<DIFile>(File), LineNumber,
876+
SizeInBits, AlignInBits, DINodeArray(unwrapDI<MDTuple>(Elements)),
877+
unwrapDI<DIType>(ClassTy), ""));
878+
#endif
834879
}
835880

836881
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+
}

src/test/debuginfo/basic-types.rs

+4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616

1717
// min-lldb-version: 310
1818

19+
// This fails on lldb 6.0.1 on x86-64 Fedora 28; so mark it macOS-only
20+
// for now.
21+
// only-macos
22+
1923
// compile-flags:-g
2024

2125
// === GDB TESTS ===================================================================================
+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
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+
// lldbg-check:[...]$0 = TheA { x: 0, y: 8970181431921507452 }
47+
// lldbr-check:(borrowed_enum_legacy::ABC::TheA) *the_a_ref = TheA { borrowed_enum_legacy::ABC::TheA: 0, borrowed_enum_legacy::ABC::TheB: 8970181431921507452 }
48+
// lldb-command:print *the_b_ref
49+
// lldbg-check:[...]$1 = TheB(0, 286331153, 286331153)
50+
// lldbr-check:(borrowed_enum_legacy::ABC::TheB) *the_b_ref = { = 0 = 286331153 = 286331153 }
51+
// lldb-command:print *univariant_ref
52+
// lldbg-check:[...]$2 = TheOnlyCase(4820353753753434)
53+
// lldbr-check:(borrowed_enum_legacy::Univariant) *univariant_ref = { borrowed_enum_legacy::TheOnlyCase = { = 4820353753753434 } }
54+
55+
#![allow(unused_variables)]
56+
#![feature(omit_gdb_pretty_printer_section)]
57+
#![omit_gdb_pretty_printer_section]
58+
59+
// The first element is to ensure proper alignment, irrespective of the machines word size. Since
60+
// the size of the discriminant value is machine dependent, this has be taken into account when
61+
// datatype layout should be predictable as in this case.
62+
enum ABC {
63+
TheA { x: i64, y: i64 },
64+
TheB (i64, i32, i32),
65+
}
66+
67+
// This is a special case since it does not have the implicit discriminant field.
68+
enum Univariant {
69+
TheOnlyCase(i64)
70+
}
71+
72+
fn main() {
73+
74+
// 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452
75+
// 0b01111100011111000111110001111100 = 2088533116
76+
// 0b0111110001111100 = 31868
77+
// 0b01111100 = 124
78+
let the_a = ABC::TheA { x: 0, y: 8970181431921507452 };
79+
let the_a_ref: &ABC = &the_a;
80+
81+
// 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
82+
// 0b00010001000100010001000100010001 = 286331153
83+
// 0b0001000100010001 = 4369
84+
// 0b00010001 = 17
85+
let the_b = ABC::TheB (0, 286331153, 286331153);
86+
let the_b_ref: &ABC = &the_b;
87+
88+
let univariant = Univariant::TheOnlyCase(4820353753753434);
89+
let univariant_ref: &Univariant = &univariant;
90+
91+
zzz(); // #break
92+
}
93+
94+
fn zzz() {()}

0 commit comments

Comments
 (0)