Skip to content

Commit

Permalink
Rollup merge of #128784 - tdittr:check-abi-on-fn-ptr, r=compiler-errors
Browse files Browse the repository at this point in the history
Check ABI target compatibility for function pointers

Tracking issue: #130260
Related tracking issue: #87678

Compatibility of an ABI for a target was previously only performed on function definitions and `extern` blocks. This PR adds it also to function pointers to be consistent.

This might have broken some of the `tests/ui/` depending on the platform, so a try run seems like a good idea.

Also this might break existing code, because we now emit extra errors. Does this require a crater run?

# Example
```rust
// build with: --target=x86_64-unknown-linux-gnu

// These raise E0570
extern "thiscall" fn foo() {}
extern "thiscall" { fn bar() }

// This did not raise any error
fn baz(f: extern "thiscall" fn()) { f() }
```

# Open Questions
* [x] Should this report a future incompatibility warning like #87678 ?
* [ ] Is this the best place to perform the check?
  • Loading branch information
matthiaskrgr authored Oct 12, 2024
2 parents 6b9676b + 867e776 commit 57be141
Show file tree
Hide file tree
Showing 20 changed files with 1,128 additions and 82 deletions.
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",
);
});
}
}
}

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 @@ -2337,6 +2338,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 @@ -124,6 +124,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 @@ -3839,6 +3840,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,
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

0 comments on commit 57be141

Please sign in to comment.