Skip to content

Commit 1e9ed31

Browse files
committed
add (back) unsupported_calling_conventions lint to reject more invalid calling conventions
1 parent e7f4317 commit 1e9ed31

File tree

16 files changed

+1223
-284
lines changed

16 files changed

+1223
-284
lines changed

compiler/rustc_hir_analysis/src/check/check.rs

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ use rustc_hir::{LangItem, Node, intravisit};
1111
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
1212
use rustc_infer::traits::{Obligation, ObligationCauseCode};
1313
use rustc_lint_defs::builtin::{
14-
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS,
14+
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, UNSUPPORTED_CALLING_CONVENTIONS,
15+
UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS,
1516
};
1617
use rustc_middle::hir::nested_filter;
1718
use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
@@ -35,25 +36,38 @@ use {rustc_attr_data_structures as attrs, rustc_hir as hir};
3536
use super::compare_impl_item::check_type_bounds;
3637
use super::*;
3738

38-
pub fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: ExternAbi) {
39-
if !tcx.sess.target.is_abi_supported(abi) {
40-
struct_span_code_err!(
41-
tcx.dcx(),
42-
span,
43-
E0570,
44-
"`{abi}` is not a supported ABI for the current target",
45-
)
46-
.emit();
39+
pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi) {
40+
match tcx.sess.target.is_abi_supported(abi) {
41+
Some(true) => (),
42+
Some(false) => {
43+
struct_span_code_err!(
44+
tcx.dcx(),
45+
span,
46+
E0570,
47+
"`{abi}` is not a supported ABI for the current target",
48+
)
49+
.emit();
50+
}
51+
None => {
52+
tcx.node_span_lint(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| {
53+
lint.primary_message("use of calling convention not supported on this target");
54+
});
55+
}
4756
}
4857
}
4958

5059
pub fn check_abi_fn_ptr(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi) {
51-
if !tcx.sess.target.is_abi_supported(abi) {
52-
tcx.node_span_lint(UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, hir_id, span, |lint| {
53-
lint.primary_message(format!(
54-
"the calling convention {abi} is not supported on this target"
55-
));
56-
});
60+
// This is always an FCW, even for `Some(false)`, since we started linting later than
61+
// in `check_abi` above.
62+
match tcx.sess.target.is_abi_supported(abi) {
63+
Some(true) => (),
64+
Some(false) | None => {
65+
tcx.node_span_lint(UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, hir_id, span, |lint| {
66+
lint.primary_message(format!(
67+
"the calling convention {abi} is not supported on this target"
68+
));
69+
});
70+
}
5771
}
5872
}
5973

@@ -779,7 +793,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
779793
let hir::ItemKind::ForeignMod { abi, items } = it.kind else {
780794
return;
781795
};
782-
check_abi(tcx, it.span, abi);
796+
check_abi(tcx, it.hir_id(), it.span, abi);
783797

784798
for item in items {
785799
let def_id = item.id.owner_id.def_id;

compiler/rustc_hir_typeck/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ fn typeck_with_inspect<'tcx>(
149149
tcx.fn_sig(def_id).instantiate_identity()
150150
};
151151

152-
check_abi(tcx, span, fn_sig.abi());
152+
check_abi(tcx, id, span, fn_sig.abi());
153153

154154
// Compute the function signature from point of view of inside the fn.
155155
let mut fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);

compiler/rustc_lint/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,6 @@ fn register_builtins(store: &mut LintStore) {
594594
"converted into hard error, see PR #125380 \
595595
<https://github.com/rust-lang/rust/pull/125380> for more information",
596596
);
597-
store.register_removed("unsupported_calling_conventions", "converted into hard error");
598597
store.register_removed(
599598
"cenum_impl_drop_cast",
600599
"converted into hard error, \

compiler/rustc_lint_defs/src/builtin.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3647,6 +3647,53 @@ declare_lint! {
36473647
crate_level_only
36483648
}
36493649

3650+
declare_lint! {
3651+
/// The `unsupported_calling_conventions` lint is output whenever there is a use of the
3652+
/// `stdcall`, `fastcall`, and `cdecl` calling conventions (or their unwind
3653+
/// variants) on targets that cannot meaningfully be supported for the requested target.
3654+
///
3655+
/// For example `stdcall` does not make much sense for a x86_64 or, more apparently, powerpc
3656+
/// code, because this calling convention was never specified for those targets.
3657+
///
3658+
/// Historically MSVC toolchains have fallen back to the regular C calling convention for
3659+
/// targets other than x86, but Rust doesn't really see a similar need to introduce a similar
3660+
/// hack across many more targets.
3661+
///
3662+
/// ### Example
3663+
///
3664+
/// ```rust,ignore (needs specific targets)
3665+
/// extern "stdcall" fn stdcall() {}
3666+
/// ```
3667+
///
3668+
/// This will produce:
3669+
///
3670+
/// ```text
3671+
/// warning: use of calling convention not supported on this target
3672+
/// --> $DIR/unsupported.rs:39:1
3673+
/// |
3674+
/// LL | extern "stdcall" fn stdcall() {}
3675+
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3676+
/// |
3677+
/// = note: `#[warn(unsupported_calling_conventions)]` on by default
3678+
/// = warning: this was previously accepted by the compiler but is being phased out;
3679+
/// it will become a hard error in a future release!
3680+
/// = note: for more information, see issue ...
3681+
/// ```
3682+
///
3683+
/// ### Explanation
3684+
///
3685+
/// On most of the targets the behaviour of `stdcall` and similar calling conventions is not
3686+
/// defined at all, but was previously accepted due to a bug in the implementation of the
3687+
/// compiler.
3688+
pub UNSUPPORTED_CALLING_CONVENTIONS,
3689+
Warn,
3690+
"use of unsupported calling convention",
3691+
@future_incompatible = FutureIncompatibleInfo {
3692+
reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
3693+
reference: "issue #137018 <https://github.com/rust-lang/rust/issues/137018>",
3694+
};
3695+
}
3696+
36503697
declare_lint! {
36513698
/// The `unsupported_fn_ptr_calling_conventions` lint is output whenever there is a use of
36523699
/// a target dependent calling convention on a target that does not support this calling

compiler/rustc_target/src/spec/mod.rs

Lines changed: 29 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2962,12 +2962,12 @@ impl Target {
29622962
}
29632963
}
29642964

2965-
pub fn is_abi_supported(&self, abi: ExternAbi) -> bool {
2965+
/// Returns `None` if the ABI was accidentally allowed and the UNSUPPORTED_CALLING_CONVENTIONS
2966+
/// lint should be emitted.
2967+
pub fn is_abi_supported(&self, abi: ExternAbi) -> Option<bool> {
29662968
use ExternAbi::*;
2967-
match abi {
2968-
Rust | C { .. } | System { .. } | RustCall | Unadjusted | Cdecl { .. } | RustCold => {
2969-
true
2970-
}
2969+
Some(match abi {
2970+
Rust | C { .. } | System { .. } | RustCall | Unadjusted | RustCold => true,
29712971
EfiApi => {
29722972
["arm", "aarch64", "riscv32", "riscv64", "x86", "x86_64"].contains(&&self.arch[..])
29732973
}
@@ -2984,44 +2984,30 @@ impl Target {
29842984
RiscvInterruptM | RiscvInterruptS => ["riscv32", "riscv64"].contains(&&self.arch[..]),
29852985
AvrInterrupt | AvrNonBlockingInterrupt => self.arch == "avr",
29862986
Thiscall { .. } => self.arch == "x86",
2987-
// On windows these fall-back to platform native calling convention (C) when the
2988-
// architecture is not supported.
2989-
//
2990-
// This is I believe a historical accident that has occurred as part of Microsoft
2991-
// striving to allow most of the code to "just" compile when support for 64-bit x86
2992-
// was added and then later again, when support for ARM architectures was added.
2993-
//
2994-
// This is well documented across MSDN. Support for this in Rust has been added in
2995-
// #54576. This makes much more sense in context of Microsoft's C++ than it does in
2996-
// Rust, but there isn't much leeway remaining here to change it back at the time this
2997-
// comment has been written.
2998-
//
2999-
// Following are the relevant excerpts from the MSDN documentation.
3000-
//
3001-
// > The __vectorcall calling convention is only supported in native code on x86 and
3002-
// x64 processors that include Streaming SIMD Extensions 2 (SSE2) and above.
3003-
// > ...
3004-
// > On ARM machines, __vectorcall is accepted and ignored by the compiler.
3005-
//
3006-
// -- https://docs.microsoft.com/en-us/cpp/cpp/vectorcall?view=msvc-160
3007-
//
3008-
// > On ARM and x64 processors, __stdcall is accepted and ignored by the compiler;
3009-
//
3010-
// -- https://docs.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-160
3011-
//
3012-
// > In most cases, keywords or compiler switches that specify an unsupported
3013-
// > convention on a particular platform are ignored, and the platform default
3014-
// > convention is used.
3015-
//
3016-
// -- https://docs.microsoft.com/en-us/cpp/cpp/argument-passing-and-naming-conventions
3017-
Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } if self.is_like_windows => true,
3018-
// Outside of Windows we want to only support these calling conventions for the
3019-
// architectures for which these calling conventions are actually well defined.
3020-
Stdcall { .. } | Fastcall { .. } if self.arch == "x86" => true,
3021-
Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => true,
3022-
// Reject these calling conventions everywhere else.
3023-
Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } => false,
3024-
}
2987+
Stdcall { .. } | Fastcall { .. } => {
2988+
if self.arch == "x86" {
2989+
true
2990+
} else {
2991+
// This *should* be false, but we emit an FCW on Windows since ABIs were not
2992+
// properly validated in the past. Also see
2993+
// <https://github.com/rust-lang/rust/issues/137018>.
2994+
if self.is_like_windows {
2995+
return None;
2996+
} else {
2997+
false
2998+
}
2999+
}
3000+
}
3001+
Cdecl { .. } => {
3002+
if self.arch == "x86" {
3003+
true
3004+
} else {
3005+
// Similar to above, we emit an FCW for backwards compatibility.
3006+
return None;
3007+
}
3008+
}
3009+
Vectorcall { .. } => ["x86", "x86_64"].contains(&&self.arch[..]),
3010+
})
30253011
}
30263012

30273013
/// Minimum integer size in bits that this target can perform atomic

0 commit comments

Comments
 (0)