Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check ABI target compatibility for function pointers #128784

Merged
merged 2 commits into from
Oct 13, 2024
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
24 changes: 14 additions & 10 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ use rustc_hir::Node;
use rustc_hir::def::{CtorKind, DefKind};
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
use rustc_infer::traits::Obligation;
use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
use rustc_lint_defs::builtin::{
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS,
};
use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
use rustc_middle::middle::stability::EvalResult;
use rustc_middle::span_bug;
Expand Down Expand Up @@ -52,16 +54,18 @@ pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
});
}
}
}

// This ABI is only allowed on function pointers
if abi == Abi::CCmseNonSecureCall {
struct_span_code_err!(
tcx.dcx(),
span,
E0781,
"the `\"C-cmse-nonsecure-call\"` ABI is only allowed on function pointers"
)
.emit();
pub fn check_abi_fn_ptr(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
match tcx.sess.target.is_abi_supported(abi) {
Some(true) => (),
Some(false) | None => {
tcx.node_span_lint(UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, hir_id, span, |lint| {
lint.primary_message(
"use of calling convention not supported on this target on function pointer",
Copy link
Member

Choose a reason for hiding this comment

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

This diagnostic is a bit awkward. Perhaps change it to:

"the calling convention {} is not supported on this target"

I think mentioning fn ptrs is also unnecessary, since it's also a warning for items (and soon an error).

);
});
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ pub mod wfcheck;

use std::num::NonZero;

pub use check::check_abi;
pub use check::{check_abi, check_abi_fn_ptr};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err};
use rustc_hir::def_id::{DefId, LocalDefId};
Expand Down
19 changes: 15 additions & 4 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use rustc_errors::DiagCtxtHandle;
use rustc_hir as hir;
use rustc_hir::HirId;
use rustc_errors::{DiagCtxtHandle, E0781, struct_span_code_err};
use rustc_hir::{self as hir, HirId};
use rustc_middle::ty::layout::LayoutError;
use rustc_middle::ty::{self, ParamEnv, TyCtxt};
use rustc_span::Span;
Expand All @@ -26,7 +25,19 @@ pub(crate) fn validate_cmse_abi<'tcx>(
..
}) = hir_node
else {
// might happen when this ABI is used incorrectly. That will be handled elsewhere
let span = match tcx.parent_hir_node(hir_id) {
hir::Node::Item(hir::Item {
kind: hir::ItemKind::ForeignMod { .. }, span, ..
}) => *span,
_ => tcx.hir().span(hir_id),
};
struct_span_code_err!(
tcx.dcx(),
span,
E0781,
"the `\"C-cmse-nonsecure-call\"` ABI is only allowed on function pointers"
)
.emit();
return;
};

Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ use rustc_trait_selection::traits::{self, ObligationCtxt};
use tracing::{debug, debug_span, instrument};

use crate::bounds::Bounds;
use crate::check::check_abi_fn_ptr;
use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, WildPatTy};
use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint};
use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
Expand Down Expand Up @@ -2324,6 +2325,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, safety, abi);
let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars);

if let hir::Node::Ty(hir::Ty { kind: hir::TyKind::BareFn(bare_fn_ty), span, .. }) =
tcx.hir_node(hir_id)
{
check_abi_fn_ptr(tcx, hir_id, *span, bare_fn_ty.abi);
}

// reject function types that violate cmse ABI requirements
cmse::validate_cmse_abi(self.tcx(), self.dcx(), hir_id, abi, bare_fn_ty);

Expand Down
45 changes: 45 additions & 0 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ declare_lint_pass! {
UNSTABLE_NAME_COLLISIONS,
UNSTABLE_SYNTAX_PRE_EXPANSION,
UNSUPPORTED_CALLING_CONVENTIONS,
UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS,
UNUSED_ASSIGNMENTS,
UNUSED_ASSOCIATED_TYPE_BOUNDS,
UNUSED_ATTRIBUTES,
Expand Down Expand Up @@ -3874,6 +3875,50 @@ declare_lint! {
};
}

declare_lint! {
/// The `unsupported_fn_ptr_calling_conventions` lint is output whenever there is a use of
/// a target dependent calling convention on a target that does not support this calling
/// convention on a function pointer.
///
/// For example `stdcall` does not make much sense for a x86_64 or, more apparently, powerpc
/// code, because this calling convention was never specified for those targets.
///
/// ### Example
///
/// ```rust,ignore (needs specific targets)
/// fn stdcall_ptr(f: extern "stdcall" fn ()) {
/// f()
/// }
/// ```
///
/// This will produce:
///
/// ```text
/// warning: use of calling convention not supported on this target on function pointer
/// --> $DIR/unsupported.rs:34:15
/// |
/// LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
/// | ^^^^^^^^^^^^^^^^^^^^^^^^
/// |
/// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
/// = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>
/// = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
/// ```
///
/// ### Explanation
///
/// On most of the targets the behaviour of `stdcall` and similar calling conventions is not
/// defined at all, but was previously accepted due to a bug in the implementation of the
/// compiler.
pub UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS,
Warn,
"use of unsupported calling convention for function pointer",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
Copy link
Member

@RalfJung RalfJung Sep 10, 2024

Choose a reason for hiding this comment

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

Maybe make this "ReportInDeps" immediately? Seems unlikely that it is very widely used, since one can't actually create a value of this function pointer type...

Copy link
Contributor Author

@tdittr tdittr Sep 12, 2024

Choose a reason for hiding this comment

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

I can also update this to FutureReleaseErrorReportInDeps in two or three releases time. The docs on the enum indicate this first should use FutureReleaseErrorDontReportInDeps. It is used in very few places true, basically crater could only find 16 crates in total, not sure if that is acceptable annoyance.

reference: "issue #130260 <https://github.com/rust-lang/rust/issues/130260>",
};
}

declare_lint! {
/// The `break_with_label_and_loop` lint detects labeled `break` expressions with
/// an unlabeled loop as their value expression.
Expand Down
4 changes: 2 additions & 2 deletions tests/debuginfo/type-names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
// gdb-check:type = type_names::GenericStruct<type_names::mod1::Struct2, type_names::mod1::mod2::Struct3>

// gdb-command:whatis generic_struct2
// gdb-check:type = type_names::GenericStruct<type_names::Struct1, extern "fastcall" fn(isize) -> usize>
// gdb-check:type = type_names::GenericStruct<type_names::Struct1, extern "system" fn(isize) -> usize>

// gdb-command:whatis mod_struct
// gdb-check:type = type_names::mod1::Struct2
Expand Down Expand Up @@ -372,7 +372,7 @@ fn main() {
let simple_struct = Struct1;
let generic_struct1: GenericStruct<mod1::Struct2, mod1::mod2::Struct3> =
GenericStruct(PhantomData);
let generic_struct2: GenericStruct<Struct1, extern "fastcall" fn(isize) -> usize> =
let generic_struct2: GenericStruct<Struct1, extern "system" fn(isize) -> usize> =
GenericStruct(PhantomData);
let mod_struct = mod1::Struct2;

Expand Down
174 changes: 164 additions & 10 deletions tests/ui/abi/unsupported.aarch64.stderr
Original file line number Diff line number Diff line change
@@ -1,55 +1,209 @@
warning: use of calling convention not supported on this target on function pointer
--> $DIR/unsupported.rs:35:15
|
LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) {
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>
= note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default

error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
--> $DIR/unsupported.rs:28:1
--> $DIR/unsupported.rs:40:1
|
LL | extern "ptx-kernel" {}
| ^^^^^^^^^^^^^^^^^^^^^^

warning: use of calling convention not supported on this target on function pointer
--> $DIR/unsupported.rs:49:17
|
LL | fn aapcs_ptr(f: extern "aapcs" fn()) {
| ^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>

error[E0570]: `"aapcs"` is not a supported ABI for the current target
--> $DIR/unsupported.rs:62:1
|
LL | extern "aapcs" {}
| ^^^^^^^^^^^^^^^^^

warning: use of calling convention not supported on this target on function pointer
--> $DIR/unsupported.rs:71:18
|
LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>

error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
--> $DIR/unsupported.rs:76:1
|
LL | extern "msp430-interrupt" {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

warning: use of calling convention not supported on this target on function pointer
--> $DIR/unsupported.rs:81:15
|
LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>

error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
--> $DIR/unsupported.rs:86:1
|
LL | extern "avr-interrupt" {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^

warning: use of calling convention not supported on this target on function pointer
--> $DIR/unsupported.rs:94:17
|
LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>

error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target
--> $DIR/unsupported.rs:105:1
|
LL | extern "riscv-interrupt-m" {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

warning: use of calling convention not supported on this target on function pointer
--> $DIR/unsupported.rs:116:15
|
LL | fn x86_ptr(f: extern "x86-interrupt" fn()) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>

error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
--> $DIR/unsupported.rs:127:1
|
LL | extern "x86-interrupt" {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^

warning: use of calling convention not supported on this target on function pointer
--> $DIR/unsupported.rs:139:20
|
LL | fn thiscall_ptr(f: extern "thiscall" fn()) {
| ^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>

error[E0570]: `"thiscall"` is not a supported ABI for the current target
--> $DIR/unsupported.rs:152:1
|
LL | extern "thiscall" {}
| ^^^^^^^^^^^^^^^^^^^^

warning: use of calling convention not supported on this target on function pointer
--> $DIR/unsupported.rs:170:19
|
LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
| ^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>

warning: use of calling convention not supported on this target
--> $DIR/unsupported.rs:183:1
|
LL | extern "stdcall" {}
| ^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
= note: `#[warn(unsupported_calling_conventions)]` on by default

warning: use of calling convention not supported on this target on function pointer
--> $DIR/unsupported.rs:195:21
|
LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>

warning: use of calling convention not supported on this target on function pointer
--> $DIR/unsupported.rs:203:22
|
LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>

error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
--> $DIR/unsupported.rs:208:1
|
LL | extern "C-cmse-nonsecure-entry" {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
--> $DIR/unsupported.rs:33:1
|
LL | extern "ptx-kernel" fn ptx() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0570]: `"aapcs"` is not a supported ABI for the current target
--> $DIR/unsupported.rs:30:1
--> $DIR/unsupported.rs:43:1
|
LL | extern "aapcs" fn aapcs() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
--> $DIR/unsupported.rs:36:1
--> $DIR/unsupported.rs:69:1
|
LL | extern "msp430-interrupt" fn msp430() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
--> $DIR/unsupported.rs:38:1
--> $DIR/unsupported.rs:79:1
|
LL | extern "avr-interrupt" fn avr() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target
--> $DIR/unsupported.rs:40:1
--> $DIR/unsupported.rs:89:1
|
LL | extern "riscv-interrupt-m" fn riscv() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
--> $DIR/unsupported.rs:45:1
--> $DIR/unsupported.rs:111:1
|
LL | extern "x86-interrupt" fn x86() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0570]: `"thiscall"` is not a supported ABI for the current target
--> $DIR/unsupported.rs:50:1
--> $DIR/unsupported.rs:133:1
|
LL | extern "thiscall" fn thiscall() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

warning: use of calling convention not supported on this target
--> $DIR/unsupported.rs:56:1
--> $DIR/unsupported.rs:159:1
|
LL | extern "stdcall" fn stdcall() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
= note: `#[warn(unsupported_calling_conventions)]` on by default

error: aborting due to 7 previous errors; 1 warning emitted
error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
--> $DIR/unsupported.rs:201:1
|
LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 16 previous errors; 12 warnings emitted

For more information about this error, try `rustc --explain E0570`.
Loading
Loading