diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index c759d46b7d2ff..04c0b6953290c 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -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 diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 1c88a8da5ea94..d3b2caca4742d 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -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(_) diff --git a/tests/debuginfo/unsafe-binders.rs b/tests/debuginfo/unsafe-binders.rs new file mode 100644 index 0000000000000..cd6c87052f2d8 --- /dev/null +++ b/tests/debuginfo/unsafe-binders.rs @@ -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() { () } diff --git a/tests/crashes/139462.rs b/tests/ui/unsafe-binders/unsafe-binders-debuginfo.rs similarity index 58% rename from tests/crashes/139462.rs rename to tests/ui/unsafe-binders/unsafe-binders-debuginfo.rs index d3be14b2be2a3..15245d9ba4f23 100644 --- a/tests/crashes/139462.rs +++ b/tests/ui/unsafe-binders/unsafe-binders-debuginfo.rs @@ -1,7 +1,10 @@ -//@ known-bug: #139462 +// This is a regression test for . +//@ 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; diff --git a/tests/ui/unsafe-binders/unsafe-binders-debuginfo.stderr b/tests/ui/unsafe-binders/unsafe-binders-debuginfo.stderr new file mode 100644 index 0000000000000..283b8b9c04f6f --- /dev/null +++ b/tests/ui/unsafe-binders/unsafe-binders-debuginfo.stderr @@ -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 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted +