Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 51 additions & 2 deletions compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(..)
Expand Down Expand Up @@ -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
Expand Down
14 changes: 13 additions & 1 deletion compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 ");
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what the type name should be here...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is fine! 👍

}

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(_)
Expand Down
76 changes: 76 additions & 0 deletions tests/debuginfo/unsafe-binders.rs
Original file line number Diff line number Diff line change
@@ -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() { () }
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
11 changes: 11 additions & 0 deletions tests/ui/unsafe-binders/unsafe-binders-debuginfo.stderr
Original file line number Diff line number Diff line change
@@ -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

Loading