about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJubilee Young <workingjubilee@gmail.com>2025-05-31 17:32:49 -0700
committerJubilee Young <workingjubilee@gmail.com>2025-06-23 09:39:23 -0700
commit2f4a55b41d437e5496a51cf7ba0e7a0b751bc6ad (patch)
treed3cd1cc3914371a4e715d932726abca7331e7a4a
parent42245d34d22ade32b3f276dcf74deb826841594c (diff)
downloadrust-2f4a55b41d437e5496a51cf7ba0e7a0b751bc6ad.tar.gz
rust-2f4a55b41d437e5496a51cf7ba0e7a0b751bc6ad.zip
compiler: plug unsupported ABI leakage from the AST
We modify rustc_ast_lowering to prevent all unsupported ABIs
from leaking through the HIR without being checked for target support.
Previously ad-hoc checking on various HIR items required making sure
we check every HIR item which could contain an `extern "{abi}"` string.
This is a losing proposition compared to gating the lowering itself.

As a consequence, unsupported ABI strings will now hard-error instead of
triggering the FCW `unsupported_fn_ptr_calling_conventions`.
This FCW was upgraded to warn in dependencies in Rust 1.87 which was
released on 2025 May 17, and it is now 2025 June, so it has become
active within a stable Rust version.

As we already had errored on these ABIs in most other positions, and
have warned for fn ptrs, this breakage has had reasonable foreshadowing.

However, this does cause errors for usages of `extern "{abi}"` that were
theoretically writeable within source but could not actually be applied
in any useful way by Rust programmers without either warning or error.
For instance, trait declarations without impls were never checked.
These are the exact kinds of leakages that this new approach prevents.

A deprecation cycle is not useful for these marginal cases as upon impl,
even default impls within traits, different HIR objects would be used.
Details of our HIR analysis meant that those objects did get checked.

We choose to error twice if an ABI is also barred by a feature gate
on the presumption that usage of a target-incorrect ABI is intentional.

Co-authored-by: Ralf Jung <post@ralfj.de>
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs28
1 files changed, 24 insertions, 4 deletions
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index ef27d0ef69b..8acb5105773 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -2,7 +2,7 @@ use rustc_abi::ExternAbi;
 use rustc_ast::ptr::P;
 use rustc_ast::visit::AssocCtxt;
 use rustc_ast::*;
-use rustc_errors::ErrorGuaranteed;
+use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err};
 use rustc_hir::def::{DefKind, PerNS, Res};
 use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
 use rustc_hir::{self as hir, HirId, LifetimeSource, PredicateOrigin};
@@ -1644,9 +1644,29 @@ impl<'hir> LoweringContext<'_, 'hir> {
             self.error_on_invalid_abi(abi_str);
             ExternAbi::Rust
         });
-        let sess = self.tcx.sess;
-        let features = self.tcx.features();
-        gate_unstable_abi(sess, features, span, extern_abi);
+        let tcx = self.tcx;
+
+        // we can't do codegen for unsupported ABIs, so error now so we won't get farther
+        if !tcx.sess.target.is_abi_supported(extern_abi) {
+            let mut err = struct_span_code_err!(
+                tcx.dcx(),
+                span,
+                E0570,
+                "{extern_abi} is not a supported ABI for the current target",
+            );
+
+            if let ExternAbi::Stdcall { unwind } = extern_abi {
+                let c_abi = ExternAbi::C { unwind };
+                let system_abi = ExternAbi::System { unwind };
+                err.help(format!("if you need `extern {extern_abi}` on win32 and `extern {c_abi}` everywhere else, \
+                    use `extern {system_abi}`"
+                ));
+            }
+            err.emit();
+        }
+        // Show required feature gate even if we already errored, as the user is likely to build the code
+        // for the actually intended target next and then they will need the feature gate.
+        gate_unstable_abi(tcx.sess, tcx.features(), span, extern_abi);
         extern_abi
     }