Skip to content

Commit d3b9d76

Browse files
committed
Auto merge of #54004 - tromey:enum-debuginfo, r=alexcrichton
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 f49f6e7 + 22223cf commit d3b9d76

File tree

7 files changed

+574
-148
lines changed

7 files changed

+574
-148
lines changed

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
@@ -1301,6 +1301,19 @@ extern "C" {
13011301
Ty: &'a DIType)
13021302
-> &'a DIDerivedType;
13031303

1304+
pub fn LLVMRustDIBuilderCreateVariantMemberType(Builder: &DIBuilder<'a>,
1305+
Scope: &'a DIScope,
1306+
Name: *const c_char,
1307+
File: &'a DIFile,
1308+
LineNumber: c_uint,
1309+
SizeInBits: u64,
1310+
AlignInBits: u32,
1311+
OffsetInBits: u64,
1312+
Discriminant: Option<&'a Value>,
1313+
Flags: DIFlags,
1314+
Ty: &'a DIType)
1315+
-> &'a DIType;
1316+
13041317
pub fn LLVMRustDIBuilderCreateLexicalBlock(Builder: &DIBuilder<'a>,
13051318
Scope: &'a DIScope,
13061319
File: &'a DIFile,
@@ -1378,7 +1391,8 @@ extern "C" {
13781391
SizeInBits: u64,
13791392
AlignInBits: u32,
13801393
Elements: &'a DIArray,
1381-
ClassType: &'a DIType)
1394+
ClassType: &'a DIType,
1395+
IsFixed: bool)
13821396
-> &'a DIType;
13831397

13841398
pub fn LLVMRustDIBuilderCreateUnionType(Builder: &DIBuilder<'a>,
@@ -1394,6 +1408,19 @@ extern "C" {
13941408
UniqueId: *const c_char)
13951409
-> &'a DIType;
13961410

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

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

src/rustllvm/RustWrapper.cpp

+47-2
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,21 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStructType(
682682
unwrapDI<DIType>(VTableHolder), UniqueId));
683683
}
684684

685+
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantPart(
686+
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
687+
LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits,
688+
uint32_t AlignInBits, LLVMRustDIFlags Flags, LLVMMetadataRef Discriminator,
689+
LLVMMetadataRef Elements, const char *UniqueId) {
690+
#if LLVM_VERSION_GE(7, 0)
691+
return wrap(Builder->createVariantPart(
692+
unwrapDI<DIDescriptor>(Scope), Name, unwrapDI<DIFile>(File), LineNumber,
693+
SizeInBits, AlignInBits, fromRust(Flags), unwrapDI<DIDerivedType>(Discriminator),
694+
DINodeArray(unwrapDI<MDTuple>(Elements)), UniqueId));
695+
#else
696+
abort();
697+
#endif
698+
}
699+
685700
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMemberType(
686701
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
687702
LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits,
@@ -693,6 +708,28 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMemberType(
693708
fromRust(Flags), unwrapDI<DIType>(Ty)));
694709
}
695710

711+
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantMemberType(
712+
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope,
713+
const char *Name, LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits,
714+
uint32_t AlignInBits, uint64_t OffsetInBits, LLVMValueRef Discriminant,
715+
LLVMRustDIFlags Flags, LLVMMetadataRef Ty) {
716+
#if LLVM_VERSION_GE(7, 0)
717+
llvm::ConstantInt* D = nullptr;
718+
if (Discriminant) {
719+
D = unwrap<llvm::ConstantInt>(Discriminant);
720+
}
721+
return wrap(Builder->createVariantMemberType(unwrapDI<DIDescriptor>(Scope), Name,
722+
unwrapDI<DIFile>(File), LineNo,
723+
SizeInBits, AlignInBits, OffsetInBits, D,
724+
fromRust(Flags), unwrapDI<DIType>(Ty)));
725+
#else
726+
return wrap(Builder->createMemberType(unwrapDI<DIDescriptor>(Scope), Name,
727+
unwrapDI<DIFile>(File), LineNo,
728+
SizeInBits, AlignInBits, OffsetInBits,
729+
fromRust(Flags), unwrapDI<DIType>(Ty)));
730+
#endif
731+
}
732+
696733
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateLexicalBlock(
697734
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope,
698735
LLVMMetadataRef File, unsigned Line, unsigned Col) {
@@ -795,11 +832,19 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerationType(
795832
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
796833
LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits,
797834
uint32_t AlignInBits, LLVMMetadataRef Elements,
798-
LLVMMetadataRef ClassTy) {
835+
LLVMMetadataRef ClassTy, bool IsFixed) {
836+
#if LLVM_VERSION_GE(7, 0)
799837
return wrap(Builder->createEnumerationType(
800838
unwrapDI<DIDescriptor>(Scope), Name, unwrapDI<DIFile>(File), LineNumber,
801839
SizeInBits, AlignInBits, DINodeArray(unwrapDI<MDTuple>(Elements)),
802-
unwrapDI<DIType>(ClassTy)));
840+
unwrapDI<DIType>(ClassTy), "", IsFixed));
841+
#else
842+
// Ignore IsFixed on older LLVM.
843+
return wrap(Builder->createEnumerationType(
844+
unwrapDI<DIDescriptor>(Scope), Name, unwrapDI<DIFile>(File), LineNumber,
845+
SizeInBits, AlignInBits, DINodeArray(unwrapDI<MDTuple>(Elements)),
846+
unwrapDI<DIType>(ClassTy), ""));
847+
#endif
803848
}
804849

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

0 commit comments

Comments
 (0)