Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 9570cac

Browse files
committed
rustc_abi: also support debugging function pointers
1 parent ab45885 commit 9570cac

File tree

4 files changed

+190
-44
lines changed

4 files changed

+190
-44
lines changed

compiler/rustc_passes/messages.ftl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ passes_abi =
88
abi: {$abi}
99
1010
passes_abi_of =
11-
fn_abi_of_instance({$fn_name}) = {$fn_abi}
11+
fn_abi_of({$fn_name}) = {$fn_abi}
1212
1313
passes_align =
1414
align: {$align}

compiler/rustc_passes/src/abi_test.rs

Lines changed: 87 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ use rustc_ast::Attribute;
22
use rustc_hir::def::DefKind;
33
use rustc_hir::def_id::DefId;
44
use rustc_middle::ty::layout::{FnAbiError, LayoutError};
5-
use rustc_middle::ty::{self, GenericArgs, Instance, TyCtxt};
5+
use rustc_middle::ty::{self, GenericArgs, Instance, Ty, TyCtxt};
66
use rustc_span::source_map::Spanned;
77
use rustc_span::symbol::sym;
8+
use rustc_target::abi::call::FnAbi;
89

910
use crate::errors::{AbiOf, UnrecognizedField};
1011

@@ -17,15 +18,20 @@ pub fn test_abi(tcx: TyCtxt<'_>) {
1718
match tcx.def_kind(id.owner_id) {
1819
DefKind::Fn => {
1920
for attr in tcx.get_attrs(id.owner_id, sym::rustc_abi) {
20-
dump_abi_of(tcx, id.owner_id.def_id.into(), attr);
21+
dump_abi_of_fn_item(tcx, id.owner_id.def_id.into(), attr);
22+
}
23+
}
24+
DefKind::TyAlias { .. } => {
25+
for attr in tcx.get_attrs(id.owner_id, sym::rustc_abi) {
26+
dump_abi_of_fn_type(tcx, id.owner_id.def_id.into(), attr);
2127
}
2228
}
2329
DefKind::Impl { .. } => {
2430
// To find associated functions we need to go into the child items here.
2531
for &id in tcx.associated_item_def_ids(id.owner_id) {
2632
if matches!(tcx.def_kind(id), DefKind::AssocFn) {
2733
for attr in tcx.get_attrs(id, sym::rustc_abi) {
28-
dump_abi_of(tcx, id, attr);
34+
dump_abi_of_fn_item(tcx, id, attr);
2935
}
3036
}
3137
}
@@ -35,7 +41,32 @@ pub fn test_abi(tcx: TyCtxt<'_>) {
3541
}
3642
}
3743

38-
fn dump_abi_of(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) {
44+
fn unwrap_fn_abi<'tcx>(
45+
abi: Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>>,
46+
tcx: TyCtxt<'tcx>,
47+
item_def_id: DefId,
48+
) -> &'tcx FnAbi<'tcx, Ty<'tcx>> {
49+
match abi {
50+
Ok(abi) => abi,
51+
Err(FnAbiError::Layout(layout_error)) => {
52+
tcx.sess.emit_fatal(Spanned {
53+
node: layout_error.into_diagnostic(),
54+
span: tcx.def_span(item_def_id),
55+
});
56+
}
57+
Err(FnAbiError::AdjustForForeignAbi(e)) => {
58+
// Sadly there seems to be no `into_diagnostic` for this case... and I am not sure if
59+
// this can even be reached. Anyway this is a perma-unstable debug attribute, an ICE
60+
// isn't the worst thing. Also this matches what codegen does.
61+
span_bug!(
62+
tcx.def_span(item_def_id),
63+
"error computing fn_abi_of_instance, cannot adjust for foreign ABI: {e:?}",
64+
)
65+
}
66+
}
67+
}
68+
69+
fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) {
3970
let param_env = tcx.param_env(item_def_id);
4071
let args = GenericArgs::identity_for_item(tcx, item_def_id);
4172
let instance = match Instance::resolve(tcx, param_env, item_def_id, args) {
@@ -51,43 +82,62 @@ fn dump_abi_of(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) {
5182
}
5283
Err(_guaranteed) => return,
5384
};
54-
match tcx.fn_abi_of_instance(param_env.and((instance, /* extra_args */ ty::List::empty()))) {
55-
Ok(abi) => {
56-
// Check out the `#[rustc_abi(..)]` attribute to tell what to dump.
57-
// The `..` are the names of fields to dump.
58-
let meta_items = attr.meta_item_list().unwrap_or_default();
59-
for meta_item in meta_items {
60-
match meta_item.name_or_empty() {
61-
sym::debug => {
62-
let fn_name = tcx.item_name(item_def_id);
63-
tcx.sess.emit_err(AbiOf {
64-
span: tcx.def_span(item_def_id),
65-
fn_name,
66-
fn_abi: format!("{:#?}", abi),
67-
});
68-
}
85+
let abi = unwrap_fn_abi(
86+
tcx.fn_abi_of_instance(param_env.and((instance, /* extra_args */ ty::List::empty()))),
87+
tcx,
88+
item_def_id,
89+
);
6990

70-
name => {
71-
tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name });
72-
}
73-
}
91+
// Check out the `#[rustc_abi(..)]` attribute to tell what to dump.
92+
// The `..` are the names of fields to dump.
93+
let meta_items = attr.meta_item_list().unwrap_or_default();
94+
for meta_item in meta_items {
95+
match meta_item.name_or_empty() {
96+
sym::debug => {
97+
let fn_name = tcx.item_name(item_def_id);
98+
tcx.sess.emit_err(AbiOf {
99+
span: tcx.def_span(item_def_id),
100+
fn_name,
101+
fn_abi: format!("{:#?}", abi),
102+
});
74103
}
75-
}
76104

77-
Err(FnAbiError::Layout(layout_error)) => {
78-
tcx.sess.emit_fatal(Spanned {
79-
node: layout_error.into_diagnostic(),
80-
span: tcx.def_span(item_def_id),
81-
});
105+
name => {
106+
tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name });
107+
}
82108
}
83-
Err(FnAbiError::AdjustForForeignAbi(e)) => {
84-
// Sadly there seems to be no `into_diagnostic` for this case... and I am not sure if
85-
// this can even be reached. Anyway this is a perma-unstable debug attribute, an ICE
86-
// isn't the worst thing. Also this matches what codegen does.
87-
span_bug!(
88-
tcx.def_span(item_def_id),
89-
"error computing fn_abi_of_instance, cannot adjust for foreign ABI: {e:?}",
90-
)
109+
}
110+
}
111+
112+
fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) {
113+
let param_env = tcx.param_env(item_def_id);
114+
let ty = tcx.type_of(item_def_id).instantiate_identity();
115+
let meta_items = attr.meta_item_list().unwrap_or_default();
116+
for meta_item in meta_items {
117+
match meta_item.name_or_empty() {
118+
sym::debug => {
119+
let ty::FnPtr(sig) = ty.kind() else {
120+
span_bug!(
121+
meta_item.span(),
122+
"`#[rustc_abi(debug)]` on a type alias requires function pointer type"
123+
);
124+
};
125+
let abi = unwrap_fn_abi(
126+
tcx.fn_abi_of_fn_ptr(param_env.and((*sig, /* extra_args */ ty::List::empty()))),
127+
tcx,
128+
item_def_id,
129+
);
130+
131+
let fn_name = tcx.item_name(item_def_id);
132+
tcx.sess.emit_err(AbiOf {
133+
span: tcx.def_span(item_def_id),
134+
fn_name,
135+
fn_abi: format!("{:#?}", abi),
136+
});
137+
}
138+
name => {
139+
tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name });
140+
}
91141
}
92142
}
93143
}

tests/ui/abi/debug.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#[rustc_abi(debug)]
1313
fn test(_x: u8) -> bool { true } //~ ERROR: fn_abi
1414

15+
#[rustc_abi(debug)]
16+
type TestFnPtr = fn(bool) -> u8; //~ ERROR: fn_abi
1517

1618
#[rustc_abi(debug)]
1719
fn test_generic<T>(_x: *const T) { } //~ ERROR: fn_abi

tests/ui/abi/debug.stderr

Lines changed: 100 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: fn_abi_of_instance(test) = FnAbi {
1+
error: fn_abi_of(test) = FnAbi {
22
args: [
33
ArgAbi {
44
layout: TyAndLayout {
@@ -92,7 +92,101 @@ error: fn_abi_of_instance(test) = FnAbi {
9292
LL | fn test(_x: u8) -> bool { true }
9393
| ^^^^^^^^^^^^^^^^^^^^^^^
9494

95-
error: fn_abi_of_instance(test_generic) = FnAbi {
95+
error: fn_abi_of(TestFnPtr) = FnAbi {
96+
args: [
97+
ArgAbi {
98+
layout: TyAndLayout {
99+
ty: bool,
100+
layout: Layout {
101+
size: Size(1 bytes),
102+
align: AbiAndPrefAlign {
103+
abi: $SOME_ALIGN,
104+
pref: $SOME_ALIGN,
105+
},
106+
abi: Scalar(
107+
Initialized {
108+
value: Int(
109+
I8,
110+
false,
111+
),
112+
valid_range: 0..=1,
113+
},
114+
),
115+
fields: Primitive,
116+
largest_niche: Some(
117+
Niche {
118+
offset: Size(0 bytes),
119+
value: Int(
120+
I8,
121+
false,
122+
),
123+
valid_range: 0..=1,
124+
},
125+
),
126+
variants: Single {
127+
index: 0,
128+
},
129+
max_repr_align: None,
130+
unadjusted_abi_align: $SOME_ALIGN,
131+
},
132+
},
133+
mode: Direct(
134+
ArgAttributes {
135+
regular: NoUndef,
136+
arg_ext: Zext,
137+
pointee_size: Size(0 bytes),
138+
pointee_align: None,
139+
},
140+
),
141+
},
142+
],
143+
ret: ArgAbi {
144+
layout: TyAndLayout {
145+
ty: u8,
146+
layout: Layout {
147+
size: Size(1 bytes),
148+
align: AbiAndPrefAlign {
149+
abi: $SOME_ALIGN,
150+
pref: $SOME_ALIGN,
151+
},
152+
abi: Scalar(
153+
Initialized {
154+
value: Int(
155+
I8,
156+
false,
157+
),
158+
valid_range: 0..=255,
159+
},
160+
),
161+
fields: Primitive,
162+
largest_niche: None,
163+
variants: Single {
164+
index: 0,
165+
},
166+
max_repr_align: None,
167+
unadjusted_abi_align: $SOME_ALIGN,
168+
},
169+
},
170+
mode: Direct(
171+
ArgAttributes {
172+
regular: NoUndef,
173+
arg_ext: None,
174+
pointee_size: Size(0 bytes),
175+
pointee_align: None,
176+
},
177+
),
178+
},
179+
c_variadic: false,
180+
fixed_count: 1,
181+
conv: Rust,
182+
can_unwind: $SOME_BOOL,
183+
}
184+
--> $DIR/debug.rs:16:1
185+
|
186+
LL | type TestFnPtr = fn(bool) -> u8;
187+
| ^^^^^^^^^^^^^^
188+
189+
error: fn_abi_of(test_generic) = FnAbi {
96190
args: [
97191
ArgAbi {
98192
layout: TyAndLayout {
@@ -163,12 +257,12 @@ error: fn_abi_of_instance(test_generic) = FnAbi {
163257
conv: Rust,
164258
can_unwind: $SOME_BOOL,
165259
}
166-
--> $DIR/debug.rs:17:1
260+
--> $DIR/debug.rs:19:1
167261
|
168262
LL | fn test_generic<T>(_x: *const T) { }
169263
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
170264

171-
error: fn_abi_of_instance(assoc_test) = FnAbi {
265+
error: fn_abi_of(assoc_test) = FnAbi {
172266
args: [
173267
ArgAbi {
174268
layout: TyAndLayout {
@@ -251,10 +345,10 @@ error: fn_abi_of_instance(assoc_test) = FnAbi {
251345
conv: Rust,
252346
can_unwind: $SOME_BOOL,
253347
}
254-
--> $DIR/debug.rs:22:5
348+
--> $DIR/debug.rs:24:5
255349
|
256350
LL | fn assoc_test(&self) { }
257351
| ^^^^^^^^^^^^^^^^^^^^
258352

259-
error: aborting due to 3 previous errors
353+
error: aborting due to 4 previous errors
260354

0 commit comments

Comments
 (0)