Skip to content

Commit 09064a2

Browse files
committed
Auto merge of #96316 - michaelwoerister:debuginfo-fix-unit-msvc, r=wesleywiser
debuginfo: Emit ZST struct debuginfo for unit type when CPP-like debuginfo is enabled As already discovered in 24a728a, PDB does not play well with custom basic types. This PR extends to the fix to `()`: Instead of a custom basic type, we treat it like an empty tuple (i.e. it is described as a struct which happens to have no fields). Before this change anything with a `()` in it would cause trouble, which is especially bad for `*const ()` and `*mut ()` which are often used for opaque pointers. E.g. the test case added in this PR would look like: ``` 0:000> dx _ref Error: Unable to bind name '_ref' 0:000> dx _ptr Error: Unable to bind name '_ptr' 0:000> dx _local Error: Unable to bind name '_local' 0:000> dx _field,d _field,d [Type: unit_type::_TypeContainingUnitField] [+0x008] _a : 123 [Type: unsigned int] [+0x000] _unit : Unexpected failure to dereference object [+0x000] _b : 456 [Type: unsigned __int64] 0:000> dx ((__int64 *)_ptr),x Error: Unable to bind name '_ptr' ``` With the PR it produces the expected output: ``` 0:000> dx _ref _ref : 0x7ff6f2012230 : () [Type: tuple$<> *] 0:000> dx _ptr _ptr : 0x7e8ddffc20 : () [Type: tuple$<> *] 0:000> dx _local _local : () [Type: tuple$<>] 0:000> dx _field,d _field,d [Type: unit_type::_TypeContainingUnitField] [+0x008] _a : 123 [Type: unsigned int] [+0x000] _unit : () [Type: tuple$<>] [+0x000] _b : 456 [Type: unsigned __int64] 0:000> dx ((__int64 *)_ptr),x ((__int64 *)_ptr),x : 0x7e8ddffc20 : 0x1122334455667788 [Type: __int64 *] ``` r? `@wesleywiser`
2 parents 64c5deb + 8b23008 commit 09064a2

File tree

2 files changed

+87
-9
lines changed

2 files changed

+87
-9
lines changed

compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs

+16-9
Original file line numberDiff line numberDiff line change
@@ -437,11 +437,9 @@ pub fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll D
437437

438438
let DINodeCreationResult { di_node, already_stored_in_typemap } = match *t.kind() {
439439
ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
440-
DINodeCreationResult::new(build_basic_type_di_node(cx, t), false)
441-
}
442-
ty::Tuple(elements) if elements.is_empty() => {
443-
DINodeCreationResult::new(build_basic_type_di_node(cx, t), false)
440+
build_basic_type_di_node(cx, t)
444441
}
442+
ty::Tuple(elements) if elements.is_empty() => build_basic_type_di_node(cx, t),
445443
ty::Array(..) => build_fixed_size_array_di_node(cx, unique_type_id, t),
446444
ty::Slice(_) | ty::Str => build_slice_type_di_node(cx, t, unique_type_id),
447445
ty::Dynamic(..) => build_dyn_type_di_node(cx, t, unique_type_id),
@@ -640,7 +638,10 @@ impl MsvcBasicName for ty::FloatTy {
640638
}
641639
}
642640

643-
fn build_basic_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
641+
fn build_basic_type_di_node<'ll, 'tcx>(
642+
cx: &CodegenCx<'ll, 'tcx>,
643+
t: Ty<'tcx>,
644+
) -> DINodeCreationResult<'ll> {
644645
debug!("build_basic_type_di_node: {:?}", t);
645646

646647
// When targeting MSVC, emit MSVC style type names for compatibility with
@@ -649,7 +650,13 @@ fn build_basic_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -
649650

650651
let (name, encoding) = match t.kind() {
651652
ty::Never => ("!", DW_ATE_unsigned),
652-
ty::Tuple(elements) if elements.is_empty() => ("()", DW_ATE_unsigned),
653+
ty::Tuple(elements) if elements.is_empty() => {
654+
if cpp_like_debuginfo {
655+
return build_tuple_type_di_node(cx, UniqueTypeId::for_ty(cx.tcx, t));
656+
} else {
657+
("()", DW_ATE_unsigned)
658+
}
659+
}
653660
ty::Bool => ("bool", DW_ATE_boolean),
654661
ty::Char => ("char", DW_ATE_UTF),
655662
ty::Int(int_ty) if cpp_like_debuginfo => (int_ty.msvc_basic_name(), DW_ATE_signed),
@@ -672,14 +679,14 @@ fn build_basic_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -
672679
};
673680

674681
if !cpp_like_debuginfo {
675-
return ty_di_node;
682+
return DINodeCreationResult::new(ty_di_node, false);
676683
}
677684

678685
let typedef_name = match t.kind() {
679686
ty::Int(int_ty) => int_ty.name_str(),
680687
ty::Uint(uint_ty) => uint_ty.name_str(),
681688
ty::Float(float_ty) => float_ty.name_str(),
682-
_ => return ty_di_node,
689+
_ => return DINodeCreationResult::new(ty_di_node, false),
683690
};
684691

685692
let typedef_di_node = unsafe {
@@ -694,7 +701,7 @@ fn build_basic_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -
694701
)
695702
};
696703

697-
typedef_di_node
704+
DINodeCreationResult::new(typedef_di_node, false)
698705
}
699706

700707
fn build_foreign_type_di_node<'ll, 'tcx>(

src/test/debuginfo/unit-type.rs

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// compile-flags:-g
2+
3+
// We only test Rust-aware versions of GDB:
4+
// min-gdb-version: 8.2
5+
6+
// === GDB TESTS ===================================================================================
7+
8+
// gdb-command: run
9+
10+
// gdb-command: print _ref
11+
// gdb-check: $1 = (*mut ()) 0x[...]
12+
13+
// gdb-command: print _ptr
14+
// gdb-check: $2 = (*mut ()) 0x[...]
15+
16+
// gdb-command: print _local
17+
// gdb-check: $3 = ()
18+
19+
// gdb-command: print _field
20+
// gdb-check: $4 = unit_type::_TypeContainingUnitField {_a: 123, _unit: (), _b: 456}
21+
22+
// Check that we can cast "void pointers" to their actual type in the debugger
23+
// gdb-command: print /x *(_ptr as *const u64)
24+
// gdb-check: $5 = 0x1122334455667788
25+
26+
// === CDB TESTS ===================================================================================
27+
28+
// cdb-command: g
29+
// cdb-check: Breakpoint 0 hit
30+
31+
// cdb-command: dx _ref
32+
// cdb-check: _ref : 0x[...] : () [Type: tuple$<> *]
33+
34+
// cdb-command: dx _ptr
35+
// cdb-check: _ptr : 0x[...] : () [Type: tuple$<> *]
36+
37+
// cdb-command: dx _local
38+
// cdb-check: _local : () [Type: tuple$<>]
39+
40+
// cdb-command: dx _field,d
41+
// cdb-check: _field,d [Type: unit_type::_TypeContainingUnitField]
42+
// cdb-check: [+0x[...]] _a : 123 [Type: unsigned int]
43+
// cdb-check: [+0x[...]] _unit : () [Type: tuple$<>]
44+
// cdb-check: [+0x[...]] _b : 456 [Type: unsigned __int64]
45+
46+
// Check that we can cast "void pointers" to their actual type in the debugger
47+
// cdb-command: dx ((__int64 *)_ptr),x
48+
// cdb-check: ((__int64 *)_ptr),x : 0x[...] : 0x1122334455667788 [Type: __int64 *]
49+
// cdb-check: 0x1122334455667788 [Type: __int64]
50+
51+
struct _TypeContainingUnitField {
52+
_a: u32,
53+
_unit: (),
54+
_b: u64,
55+
}
56+
57+
fn foo(_ref: &(), _ptr: *const ()) {
58+
let _local = ();
59+
let _field = _TypeContainingUnitField { _a: 123, _unit: (), _b: 456 };
60+
61+
zzz(); // #break
62+
}
63+
64+
fn main() {
65+
let pointee = 0x1122_3344_5566_7788i64;
66+
67+
foo(&(), &pointee as *const i64 as *const ());
68+
}
69+
70+
#[inline(never)]
71+
fn zzz() {}

0 commit comments

Comments
 (0)