about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2023-08-30 09:57:48 +0200
committerRalf Jung <post@ralfj.de>2023-09-06 11:11:06 +0200
commit9570cac0199c4da6d4c493a4946d6b715eb437d9 (patch)
tree634c08ec83d2c6cd9e00376421ad285619ab9036
parentab45885dec2a6552cb060a5b7183653baaecd580 (diff)
downloadrust-9570cac0199c4da6d4c493a4946d6b715eb437d9.tar.gz
rust-9570cac0199c4da6d4c493a4946d6b715eb437d9.zip
rustc_abi: also support debugging function pointers
-rw-r--r--compiler/rustc_passes/messages.ftl2
-rw-r--r--compiler/rustc_passes/src/abi_test.rs124
-rw-r--r--tests/ui/abi/debug.rs2
-rw-r--r--tests/ui/abi/debug.stderr106
4 files changed, 190 insertions, 44 deletions
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 57598cf8bcf..aa7db3348d0 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 5c0438e78ae..aeaa264216d 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 13464be275e..84d08ead08d 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<T>(_x: *const T) { } //~ ERROR: fn_abi
diff --git a/tests/ui/abi/debug.stderr b/tests/ui/abi/debug.stderr
index 4f4ee3de4b8..dd0cfea351f 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<T>(_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