diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 57598cf8bcf01..aa7db3348d028 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -8,7 +8,7 @@ passes_abi = abi: {$abi} passes_abi_of = - fn_abi_of_instance({$fn_name}) = {$fn_abi} + fn_abi_of({$fn_name}) = {$fn_abi} passes_align = align: {$align} diff --git a/compiler/rustc_passes/src/abi_test.rs b/compiler/rustc_passes/src/abi_test.rs index 5c0438e78aebc..aeaa264216dac 100644 --- a/compiler/rustc_passes/src/abi_test.rs +++ b/compiler/rustc_passes/src/abi_test.rs @@ -2,9 +2,10 @@ use rustc_ast::Attribute; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_middle::ty::layout::{FnAbiError, LayoutError}; -use rustc_middle::ty::{self, GenericArgs, Instance, TyCtxt}; +use rustc_middle::ty::{self, GenericArgs, Instance, Ty, TyCtxt}; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; +use rustc_target::abi::call::FnAbi; use crate::errors::{AbiOf, UnrecognizedField}; @@ -17,7 +18,12 @@ pub fn test_abi(tcx: TyCtxt<'_>) { match tcx.def_kind(id.owner_id) { DefKind::Fn => { for attr in tcx.get_attrs(id.owner_id, sym::rustc_abi) { - dump_abi_of(tcx, id.owner_id.def_id.into(), attr); + dump_abi_of_fn_item(tcx, id.owner_id.def_id.into(), attr); + } + } + DefKind::TyAlias { .. } => { + for attr in tcx.get_attrs(id.owner_id, sym::rustc_abi) { + dump_abi_of_fn_type(tcx, id.owner_id.def_id.into(), attr); } } DefKind::Impl { .. } => { @@ -25,7 +31,7 @@ pub fn test_abi(tcx: TyCtxt<'_>) { for &id in tcx.associated_item_def_ids(id.owner_id) { if matches!(tcx.def_kind(id), DefKind::AssocFn) { for attr in tcx.get_attrs(id, sym::rustc_abi) { - dump_abi_of(tcx, id, attr); + dump_abi_of_fn_item(tcx, id, attr); } } } @@ -35,7 +41,32 @@ pub fn test_abi(tcx: TyCtxt<'_>) { } } -fn dump_abi_of(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) { +fn unwrap_fn_abi<'tcx>( + abi: Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>>, + tcx: TyCtxt<'tcx>, + item_def_id: DefId, +) -> &'tcx FnAbi<'tcx, Ty<'tcx>> { + match abi { + Ok(abi) => abi, + Err(FnAbiError::Layout(layout_error)) => { + tcx.sess.emit_fatal(Spanned { + node: layout_error.into_diagnostic(), + span: tcx.def_span(item_def_id), + }); + } + Err(FnAbiError::AdjustForForeignAbi(e)) => { + // Sadly there seems to be no `into_diagnostic` for this case... and I am not sure if + // this can even be reached. Anyway this is a perma-unstable debug attribute, an ICE + // isn't the worst thing. Also this matches what codegen does. + span_bug!( + tcx.def_span(item_def_id), + "error computing fn_abi_of_instance, cannot adjust for foreign ABI: {e:?}", + ) + } + } +} + +fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) { let param_env = tcx.param_env(item_def_id); let args = GenericArgs::identity_for_item(tcx, item_def_id); 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) { } Err(_guaranteed) => return, }; - match tcx.fn_abi_of_instance(param_env.and((instance, /* extra_args */ ty::List::empty()))) { - Ok(abi) => { - // Check out the `#[rustc_abi(..)]` attribute to tell what to dump. - // The `..` are the names of fields to dump. - let meta_items = attr.meta_item_list().unwrap_or_default(); - for meta_item in meta_items { - match meta_item.name_or_empty() { - sym::debug => { - let fn_name = tcx.item_name(item_def_id); - tcx.sess.emit_err(AbiOf { - span: tcx.def_span(item_def_id), - fn_name, - fn_abi: format!("{:#?}", abi), - }); - } + let abi = unwrap_fn_abi( + tcx.fn_abi_of_instance(param_env.and((instance, /* extra_args */ ty::List::empty()))), + tcx, + item_def_id, + ); - name => { - tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name }); - } - } + // Check out the `#[rustc_abi(..)]` attribute to tell what to dump. + // The `..` are the names of fields to dump. + let meta_items = attr.meta_item_list().unwrap_or_default(); + for meta_item in meta_items { + match meta_item.name_or_empty() { + sym::debug => { + let fn_name = tcx.item_name(item_def_id); + tcx.sess.emit_err(AbiOf { + span: tcx.def_span(item_def_id), + fn_name, + fn_abi: format!("{:#?}", abi), + }); } - } - Err(FnAbiError::Layout(layout_error)) => { - tcx.sess.emit_fatal(Spanned { - node: layout_error.into_diagnostic(), - span: tcx.def_span(item_def_id), - }); + name => { + tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name }); + } } - Err(FnAbiError::AdjustForForeignAbi(e)) => { - // Sadly there seems to be no `into_diagnostic` for this case... and I am not sure if - // this can even be reached. Anyway this is a perma-unstable debug attribute, an ICE - // isn't the worst thing. Also this matches what codegen does. - span_bug!( - tcx.def_span(item_def_id), - "error computing fn_abi_of_instance, cannot adjust for foreign ABI: {e:?}", - ) + } +} + +fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) { + let param_env = tcx.param_env(item_def_id); + let ty = tcx.type_of(item_def_id).instantiate_identity(); + let meta_items = attr.meta_item_list().unwrap_or_default(); + for meta_item in meta_items { + match meta_item.name_or_empty() { + sym::debug => { + let ty::FnPtr(sig) = ty.kind() else { + span_bug!( + meta_item.span(), + "`#[rustc_abi(debug)]` on a type alias requires function pointer type" + ); + }; + let abi = unwrap_fn_abi( + tcx.fn_abi_of_fn_ptr(param_env.and((*sig, /* extra_args */ ty::List::empty()))), + tcx, + item_def_id, + ); + + let fn_name = tcx.item_name(item_def_id); + tcx.sess.emit_err(AbiOf { + span: tcx.def_span(item_def_id), + fn_name, + fn_abi: format!("{:#?}", abi), + }); + } + name => { + tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name }); + } } } } diff --git a/tests/ui/abi/debug.rs b/tests/ui/abi/debug.rs index 13464be275e7c..84d08ead08df3 100644 --- a/tests/ui/abi/debug.rs +++ b/tests/ui/abi/debug.rs @@ -12,6 +12,8 @@ #[rustc_abi(debug)] fn test(_x: u8) -> bool { true } //~ ERROR: fn_abi +#[rustc_abi(debug)] +type TestFnPtr = fn(bool) -> u8; //~ ERROR: fn_abi #[rustc_abi(debug)] fn test_generic(_x: *const T) { } //~ ERROR: fn_abi diff --git a/tests/ui/abi/debug.stderr b/tests/ui/abi/debug.stderr index 4f4ee3de4b8a0..dd0cfea351faa 100644 --- a/tests/ui/abi/debug.stderr +++ b/tests/ui/abi/debug.stderr @@ -1,4 +1,4 @@ -error: fn_abi_of_instance(test) = FnAbi { +error: fn_abi_of(test) = FnAbi { args: [ ArgAbi { layout: TyAndLayout { @@ -92,7 +92,101 @@ error: fn_abi_of_instance(test) = FnAbi { LL | fn test(_x: u8) -> bool { true } | ^^^^^^^^^^^^^^^^^^^^^^^ -error: fn_abi_of_instance(test_generic) = FnAbi { +error: fn_abi_of(TestFnPtr) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: bool, + layout: Layout { + size: Size(1 bytes), + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + ), + fields: Primitive, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + ), + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Zext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: u8, + layout: Layout { + size: Size(1 bytes), + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=255, + }, + ), + fields: Primitive, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + --> $DIR/debug.rs:16:1 + | +LL | type TestFnPtr = fn(bool) -> u8; + | ^^^^^^^^^^^^^^ + +error: fn_abi_of(test_generic) = FnAbi { args: [ ArgAbi { layout: TyAndLayout { @@ -163,12 +257,12 @@ error: fn_abi_of_instance(test_generic) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:17:1 + --> $DIR/debug.rs:19:1 | LL | fn test_generic(_x: *const T) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: fn_abi_of_instance(assoc_test) = FnAbi { +error: fn_abi_of(assoc_test) = FnAbi { args: [ ArgAbi { layout: TyAndLayout { @@ -251,10 +345,10 @@ error: fn_abi_of_instance(assoc_test) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:22:5 + --> $DIR/debug.rs:24:5 | LL | fn assoc_test(&self) { } | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors