implement debuginfo for unsafe binders

This commit is contained in:
Makai
2026-02-23 22:19:51 +08:00
parent eeb94be79a
commit b6083435d8
5 changed files with 155 additions and 4 deletions
@@ -480,8 +480,7 @@ pub(crate) fn spanned_type_di_node<'ll, 'tcx>(
},
ty::Tuple(_) => build_tuple_type_di_node(cx, unique_type_id),
ty::Pat(base, _) => return type_di_node(cx, base),
// FIXME(unsafe_binders): impl debug info
ty::UnsafeBinder(_) => unimplemented!(),
ty::UnsafeBinder(_) => build_unsafe_binder_type_di_node(cx, t, unique_type_id),
ty::Alias(..)
| ty::Param(_)
| ty::Bound(..)
@@ -1488,6 +1487,56 @@ fn build_vtable_type_di_node<'ll, 'tcx>(
.di_node
}
/// Creates the debuginfo node for `unsafe<'a> T` binder types.
///
/// We treat an unsafe binder like a struct with a single field named `inner`
/// rather than delegating to the inner type's DI node directly. This way the
/// debugger shows the binder's own type name, and the wrapped value is still
/// accessible through the `inner` field.
fn build_unsafe_binder_type_di_node<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
binder_type: Ty<'tcx>,
unique_type_id: UniqueTypeId<'tcx>,
) -> DINodeCreationResult<'ll> {
let ty::UnsafeBinder(inner) = binder_type.kind() else {
bug!(
"Only ty::UnsafeBinder is valid for build_unsafe_binder_type_di_node. Found {:?} instead.",
binder_type
)
};
let inner_type = inner.skip_binder();
let inner_type_di_node = type_di_node(cx, inner_type);
let type_name = compute_debuginfo_type_name(cx.tcx, binder_type, true);
type_map::build_type_with_children(
cx,
type_map::stub(
cx,
Stub::Struct,
unique_type_id,
&type_name,
None,
cx.size_and_align_of(binder_type),
NO_SCOPE_METADATA,
DIFlags::FlagZero,
),
|cx, unsafe_binder_type_di_node| {
let inner_layout = cx.layout_of(inner_type);
smallvec![build_field_di_node(
cx,
unsafe_binder_type_di_node,
"inner",
inner_layout,
Size::ZERO,
DIFlags::FlagZero,
inner_type_di_node,
None,
)]
},
NO_GENERICS,
)
}
/// Get the global variable for the vtable.
///
/// When using global variables, we may have created an addrspacecast to get a pointer to the
@@ -430,7 +430,19 @@ fn push_debuginfo_type_name<'tcx>(
push_closure_or_coroutine_name(tcx, def_id, args, qualified, output, visited);
}
}
ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binders)"),
ty::UnsafeBinder(inner) => {
if cpp_like_debuginfo {
output.push_str("unsafe$<");
} else {
output.push_str("unsafe ");
}
push_debuginfo_type_name(tcx, inner.skip_binder(), qualified, output, visited);
if cpp_like_debuginfo {
push_close_angle_bracket(cpp_like_debuginfo, output);
}
}
ty::Param(_)
| ty::Error(_)
| ty::Infer(_)
+76
View File
@@ -0,0 +1,76 @@
//@ compile-flags: -g
//@ disable-gdb-pretty-printers
//@ ignore-backends: gcc
// Tests that debuginfo is correctly generated for `unsafe<'a> T` binder types.
// === GDB TESTS ===================================================================================
//@ gdb-command:run
//@ gdb-command:whatis binder_i32
//@ gdb-check:type = unsafe &i32
//@ gdb-command:print unwrapped_i32
//@ gdb-check:$1 = 67
//@ gdb-command:whatis no_lifetime
//@ gdb-check:type = unsafe i32
//@ gdb-command:whatis unsafe_binder_tuple
//@ gdb-check:type = unsafe (&i32, &i32)
//@ gdb-command:whatis binder_tuple_ref
//@ gdb-check:type = (&i32, &i32)
//@ gdb-command:whatis binder.inner
//@ gdb-check:type = unsafe &i32
//@ gdb-command:print wrapper.val
//@ gdb-check:$2 = 99
//@ gdb-command:whatis binder_raw
//@ gdb-check:type = unsafe *const i32
//@ gdb-command:print binder_raw_val
//@ gdb-check:$3 = 7
#![feature(unsafe_binders)]
#[expect(incomplete_features)]
use std::unsafe_binder::{unwrap_binder, wrap_binder};
struct Wrapper {
val: i32,
}
struct Binder {
inner: unsafe<'a> &'a i32,
}
fn main() {
let x = 67i32;
let binder_i32: unsafe<'a> &'a i32 = unsafe { wrap_binder!(&x) };
let unwrapped_i32: i32 = unsafe { *unwrap_binder!(binder_i32) };
let y = 123i32;
let no_lifetime: unsafe<> i32 = unsafe { wrap_binder!(y) };
let unsafe_binder_tuple: unsafe<'a> (&'a i32, &'a i32) = unsafe {
wrap_binder!((&114i32, &514i32))
};
let binder_tuple_ref: (&i32, &i32) = unsafe { unwrap_binder!(unsafe_binder_tuple) };
let val = 99i32;
let binder = Binder { inner: unsafe { wrap_binder!(&val) } };
let wrapper = Wrapper { val: unsafe { *unwrap_binder!(binder.inner) } };
let z = 7i32;
let raw: *const i32 = &z;
let binder_raw: unsafe<'a> *const i32 = unsafe { wrap_binder!(raw) };
let binder_raw_val: i32 = unsafe { *unwrap_binder!(binder_raw) };
gugugaga(); // #break
}
fn gugugaga() { () }
@@ -1,7 +1,10 @@
//@ known-bug: #139462
// This is a regression test for <https://github.com/rust-lang/rust/issues/139462>.
//@ check-pass
//@ compile-flags: -Cdebuginfo=2
//@ ignore-backends: gcc
#![feature(unsafe_binders)]
//~^ WARN the feature `unsafe_binders` is incomplete
use std::unsafe_binder::wrap_binder;
fn main() {
let foo = 0;
@@ -0,0 +1,11 @@
warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/unsafe-binders-debuginfo.rs:5:12
|
LL | #![feature(unsafe_binders)]
| ^^^^^^^^^^^^^^
|
= note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: 1 warning emitted