Skip to content

Commit b608343

Browse files
committed
implement debuginfo for unsafe binders
1 parent eeb94be commit b608343

File tree

5 files changed

+155
-4
lines changed

5 files changed

+155
-4
lines changed

compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -480,8 +480,7 @@ pub(crate) fn spanned_type_di_node<'ll, 'tcx>(
480480
},
481481
ty::Tuple(_) => build_tuple_type_di_node(cx, unique_type_id),
482482
ty::Pat(base, _) => return type_di_node(cx, base),
483-
// FIXME(unsafe_binders): impl debug info
484-
ty::UnsafeBinder(_) => unimplemented!(),
483+
ty::UnsafeBinder(_) => build_unsafe_binder_type_di_node(cx, t, unique_type_id),
485484
ty::Alias(..)
486485
| ty::Param(_)
487486
| ty::Bound(..)
@@ -1488,6 +1487,56 @@ fn build_vtable_type_di_node<'ll, 'tcx>(
14881487
.di_node
14891488
}
14901489

1490+
/// Creates the debuginfo node for `unsafe<'a> T` binder types.
1491+
///
1492+
/// We treat an unsafe binder like a struct with a single field named `inner`
1493+
/// rather than delegating to the inner type's DI node directly. This way the
1494+
/// debugger shows the binder's own type name, and the wrapped value is still
1495+
/// accessible through the `inner` field.
1496+
fn build_unsafe_binder_type_di_node<'ll, 'tcx>(
1497+
cx: &CodegenCx<'ll, 'tcx>,
1498+
binder_type: Ty<'tcx>,
1499+
unique_type_id: UniqueTypeId<'tcx>,
1500+
) -> DINodeCreationResult<'ll> {
1501+
let ty::UnsafeBinder(inner) = binder_type.kind() else {
1502+
bug!(
1503+
"Only ty::UnsafeBinder is valid for build_unsafe_binder_type_di_node. Found {:?} instead.",
1504+
binder_type
1505+
)
1506+
};
1507+
let inner_type = inner.skip_binder();
1508+
let inner_type_di_node = type_di_node(cx, inner_type);
1509+
1510+
let type_name = compute_debuginfo_type_name(cx.tcx, binder_type, true);
1511+
type_map::build_type_with_children(
1512+
cx,
1513+
type_map::stub(
1514+
cx,
1515+
Stub::Struct,
1516+
unique_type_id,
1517+
&type_name,
1518+
None,
1519+
cx.size_and_align_of(binder_type),
1520+
NO_SCOPE_METADATA,
1521+
DIFlags::FlagZero,
1522+
),
1523+
|cx, unsafe_binder_type_di_node| {
1524+
let inner_layout = cx.layout_of(inner_type);
1525+
smallvec![build_field_di_node(
1526+
cx,
1527+
unsafe_binder_type_di_node,
1528+
"inner",
1529+
inner_layout,
1530+
Size::ZERO,
1531+
DIFlags::FlagZero,
1532+
inner_type_di_node,
1533+
None,
1534+
)]
1535+
},
1536+
NO_GENERICS,
1537+
)
1538+
}
1539+
14911540
/// Get the global variable for the vtable.
14921541
///
14931542
/// When using global variables, we may have created an addrspacecast to get a pointer to the

compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,19 @@ fn push_debuginfo_type_name<'tcx>(
430430
push_closure_or_coroutine_name(tcx, def_id, args, qualified, output, visited);
431431
}
432432
}
433-
ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binders)"),
433+
ty::UnsafeBinder(inner) => {
434+
if cpp_like_debuginfo {
435+
output.push_str("unsafe$<");
436+
} else {
437+
output.push_str("unsafe ");
438+
}
439+
440+
push_debuginfo_type_name(tcx, inner.skip_binder(), qualified, output, visited);
441+
442+
if cpp_like_debuginfo {
443+
push_close_angle_bracket(cpp_like_debuginfo, output);
444+
}
445+
}
434446
ty::Param(_)
435447
| ty::Error(_)
436448
| ty::Infer(_)

tests/debuginfo/unsafe-binders.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//@ compile-flags: -g
2+
//@ disable-gdb-pretty-printers
3+
//@ ignore-backends: gcc
4+
5+
// Tests that debuginfo is correctly generated for `unsafe<'a> T` binder types.
6+
7+
// === GDB TESTS ===================================================================================
8+
9+
//@ gdb-command:run
10+
11+
//@ gdb-command:whatis binder_i32
12+
//@ gdb-check:type = unsafe &i32
13+
14+
//@ gdb-command:print unwrapped_i32
15+
//@ gdb-check:$1 = 67
16+
17+
//@ gdb-command:whatis no_lifetime
18+
//@ gdb-check:type = unsafe i32
19+
20+
//@ gdb-command:whatis unsafe_binder_tuple
21+
//@ gdb-check:type = unsafe (&i32, &i32)
22+
23+
//@ gdb-command:whatis binder_tuple_ref
24+
//@ gdb-check:type = (&i32, &i32)
25+
26+
//@ gdb-command:whatis binder.inner
27+
//@ gdb-check:type = unsafe &i32
28+
29+
//@ gdb-command:print wrapper.val
30+
//@ gdb-check:$2 = 99
31+
32+
//@ gdb-command:whatis binder_raw
33+
//@ gdb-check:type = unsafe *const i32
34+
35+
//@ gdb-command:print binder_raw_val
36+
//@ gdb-check:$3 = 7
37+
38+
#![feature(unsafe_binders)]
39+
#[expect(incomplete_features)]
40+
41+
use std::unsafe_binder::{unwrap_binder, wrap_binder};
42+
43+
struct Wrapper {
44+
val: i32,
45+
}
46+
47+
struct Binder {
48+
inner: unsafe<'a> &'a i32,
49+
}
50+
51+
fn main() {
52+
let x = 67i32;
53+
let binder_i32: unsafe<'a> &'a i32 = unsafe { wrap_binder!(&x) };
54+
let unwrapped_i32: i32 = unsafe { *unwrap_binder!(binder_i32) };
55+
56+
let y = 123i32;
57+
let no_lifetime: unsafe<> i32 = unsafe { wrap_binder!(y) };
58+
59+
let unsafe_binder_tuple: unsafe<'a> (&'a i32, &'a i32) = unsafe {
60+
wrap_binder!((&114i32, &514i32))
61+
};
62+
let binder_tuple_ref: (&i32, &i32) = unsafe { unwrap_binder!(unsafe_binder_tuple) };
63+
64+
let val = 99i32;
65+
let binder = Binder { inner: unsafe { wrap_binder!(&val) } };
66+
let wrapper = Wrapper { val: unsafe { *unwrap_binder!(binder.inner) } };
67+
68+
let z = 7i32;
69+
let raw: *const i32 = &z;
70+
let binder_raw: unsafe<'a> *const i32 = unsafe { wrap_binder!(raw) };
71+
let binder_raw_val: i32 = unsafe { *unwrap_binder!(binder_raw) };
72+
73+
gugugaga(); // #break
74+
}
75+
76+
fn gugugaga() { () }

tests/crashes/139462.rs renamed to tests/ui/unsafe-binders/unsafe-binders-debuginfo.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
//@ known-bug: #139462
1+
// This is a regression test for <https://github.com/rust-lang/rust/issues/139462>.
2+
//@ check-pass
23
//@ compile-flags: -Cdebuginfo=2
34
//@ ignore-backends: gcc
45
#![feature(unsafe_binders)]
6+
//~^ WARN the feature `unsafe_binders` is incomplete
7+
58
use std::unsafe_binder::wrap_binder;
69
fn main() {
710
let foo = 0;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/unsafe-binders-debuginfo.rs:5:12
3+
|
4+
LL | #![feature(unsafe_binders)]
5+
| ^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
warning: 1 warning emitted
11+

0 commit comments

Comments
 (0)