Rollup merge of #138028 - workingjubilee:is-rustic-abi, r=compiler-errors
compiler: add `ExternAbi::is_rustic_abi` Various parts of the compiler were hand-rolling this extremely simple check that is nonetheless easy to get wrong as the compiler evolves over time. Discourage them from being so "original" again by replacing it with a single implementation on the type that represents these ABIs. This simplifies a surprising amount of code as a result. Also fixes #132981, an ICE that emerged due to other checks being made stricter.
This commit is contained in:
commit
fe4c0850fe
7 changed files with 34 additions and 43 deletions
|
@ -191,6 +191,17 @@ impl StableOrd for ExternAbi {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExternAbi {
|
impl ExternAbi {
|
||||||
|
/// An ABI "like Rust"
|
||||||
|
///
|
||||||
|
/// These ABIs are fully controlled by the Rust compiler, which means they
|
||||||
|
/// - support unwinding with `-Cpanic=unwind`, unlike `extern "C"`
|
||||||
|
/// - often diverge from the C ABI
|
||||||
|
/// - are subject to change between compiler versions
|
||||||
|
pub fn is_rustic_abi(self) -> bool {
|
||||||
|
use ExternAbi::*;
|
||||||
|
matches!(self, Rust | RustCall | RustIntrinsic | RustCold)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn supports_varargs(self) -> bool {
|
pub fn supports_varargs(self) -> bool {
|
||||||
// * C and Cdecl obviously support varargs.
|
// * C and Cdecl obviously support varargs.
|
||||||
// * C can be based on Aapcs, SysV64 or Win64, so they must support varargs.
|
// * C can be based on Aapcs, SysV64 or Win64, so they must support varargs.
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
use rustc_abi::{BackendRepr, ExternAbi, TagEncoding, VariantIdx, Variants, WrappingRange};
|
use rustc_abi::{BackendRepr, TagEncoding, VariantIdx, Variants, WrappingRange};
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_errors::DiagMessage;
|
use rustc_errors::DiagMessage;
|
||||||
use rustc_hir::intravisit::VisitorExt;
|
use rustc_hir::intravisit::VisitorExt;
|
||||||
|
@ -1349,7 +1349,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
|
|
||||||
ty::FnPtr(sig_tys, hdr) => {
|
ty::FnPtr(sig_tys, hdr) => {
|
||||||
let sig = sig_tys.with(hdr);
|
let sig = sig_tys.with(hdr);
|
||||||
if self.is_internal_abi(sig.abi()) {
|
if sig.abi().is_rustic_abi() {
|
||||||
return FfiUnsafe {
|
return FfiUnsafe {
|
||||||
ty,
|
ty,
|
||||||
reason: fluent::lint_improper_ctypes_fnptr_reason,
|
reason: fluent::lint_improper_ctypes_fnptr_reason,
|
||||||
|
@ -1552,13 +1552,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
self.check_type_for_ffi_and_report_errors(span, ty, true, false);
|
self.check_type_for_ffi_and_report_errors(span, ty, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_internal_abi(&self, abi: ExternAbi) -> bool {
|
|
||||||
matches!(
|
|
||||||
abi,
|
|
||||||
ExternAbi::Rust | ExternAbi::RustCall | ExternAbi::RustCold | ExternAbi::RustIntrinsic
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Find any fn-ptr types with external ABIs in `ty`.
|
/// Find any fn-ptr types with external ABIs in `ty`.
|
||||||
///
|
///
|
||||||
/// For example, `Option<extern "C" fn()>` returns `extern "C" fn()`
|
/// For example, `Option<extern "C" fn()>` returns `extern "C" fn()`
|
||||||
|
@ -1567,17 +1560,16 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
hir_ty: &hir::Ty<'tcx>,
|
hir_ty: &hir::Ty<'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
) -> Vec<(Ty<'tcx>, Span)> {
|
) -> Vec<(Ty<'tcx>, Span)> {
|
||||||
struct FnPtrFinder<'a, 'b, 'tcx> {
|
struct FnPtrFinder<'tcx> {
|
||||||
visitor: &'a ImproperCTypesVisitor<'b, 'tcx>,
|
|
||||||
spans: Vec<Span>,
|
spans: Vec<Span>,
|
||||||
tys: Vec<Ty<'tcx>>,
|
tys: Vec<Ty<'tcx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, 'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'a, 'b, 'tcx> {
|
impl<'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'tcx> {
|
||||||
fn visit_ty(&mut self, ty: &'_ hir::Ty<'_, AmbigArg>) {
|
fn visit_ty(&mut self, ty: &'_ hir::Ty<'_, AmbigArg>) {
|
||||||
debug!(?ty);
|
debug!(?ty);
|
||||||
if let hir::TyKind::BareFn(hir::BareFnTy { abi, .. }) = ty.kind
|
if let hir::TyKind::BareFn(hir::BareFnTy { abi, .. }) = ty.kind
|
||||||
&& !self.visitor.is_internal_abi(*abi)
|
&& !abi.is_rustic_abi()
|
||||||
{
|
{
|
||||||
self.spans.push(ty.span);
|
self.spans.push(ty.span);
|
||||||
}
|
}
|
||||||
|
@ -1586,12 +1578,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, 'tcx> ty::visit::TypeVisitor<TyCtxt<'tcx>> for FnPtrFinder<'a, 'b, 'tcx> {
|
impl<'tcx> ty::visit::TypeVisitor<TyCtxt<'tcx>> for FnPtrFinder<'tcx> {
|
||||||
type Result = ();
|
type Result = ();
|
||||||
|
|
||||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
|
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
|
||||||
if let ty::FnPtr(_, hdr) = ty.kind()
|
if let ty::FnPtr(_, hdr) = ty.kind()
|
||||||
&& !self.visitor.is_internal_abi(hdr.abi)
|
&& !hdr.abi.is_rustic_abi()
|
||||||
{
|
{
|
||||||
self.tys.push(ty);
|
self.tys.push(ty);
|
||||||
}
|
}
|
||||||
|
@ -1600,7 +1592,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut visitor = FnPtrFinder { visitor: self, spans: Vec::new(), tys: Vec::new() };
|
let mut visitor = FnPtrFinder { spans: Vec::new(), tys: Vec::new() };
|
||||||
ty.visit_with(&mut visitor);
|
ty.visit_with(&mut visitor);
|
||||||
visitor.visit_ty_unambig(hir_ty);
|
visitor.visit_ty_unambig(hir_ty);
|
||||||
|
|
||||||
|
@ -1615,13 +1607,13 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations {
|
||||||
|
|
||||||
match it.kind {
|
match it.kind {
|
||||||
hir::ForeignItemKind::Fn(sig, _, _) => {
|
hir::ForeignItemKind::Fn(sig, _, _) => {
|
||||||
if vis.is_internal_abi(abi) {
|
if abi.is_rustic_abi() {
|
||||||
vis.check_fn(it.owner_id.def_id, sig.decl)
|
vis.check_fn(it.owner_id.def_id, sig.decl)
|
||||||
} else {
|
} else {
|
||||||
vis.check_foreign_fn(it.owner_id.def_id, sig.decl);
|
vis.check_foreign_fn(it.owner_id.def_id, sig.decl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::ForeignItemKind::Static(ty, _, _) if !vis.is_internal_abi(abi) => {
|
hir::ForeignItemKind::Static(ty, _, _) if !abi.is_rustic_abi() => {
|
||||||
vis.check_foreign_static(it.owner_id, ty.span);
|
vis.check_foreign_static(it.owner_id, ty.span);
|
||||||
}
|
}
|
||||||
hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => (),
|
hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => (),
|
||||||
|
@ -1775,7 +1767,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Definition };
|
let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Definition };
|
||||||
if vis.is_internal_abi(abi) {
|
if abi.is_rustic_abi() {
|
||||||
vis.check_fn(id, decl);
|
vis.check_fn(id, decl);
|
||||||
} else {
|
} else {
|
||||||
vis.check_foreign_fn(id, decl);
|
vis.check_foreign_fn(id, decl);
|
||||||
|
|
|
@ -53,11 +53,7 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
|
||||||
|
|
||||||
// Rust calls cannot themselves create foreign unwinds.
|
// Rust calls cannot themselves create foreign unwinds.
|
||||||
// We assume this is true for intrinsics as well.
|
// We assume this is true for intrinsics as well.
|
||||||
if let ExternAbi::RustIntrinsic
|
if sig.abi().is_rustic_abi() {
|
||||||
| ExternAbi::Rust
|
|
||||||
| ExternAbi::RustCall
|
|
||||||
| ExternAbi::RustCold = sig.abi()
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! This module ensures that if a function's ABI requires a particular target feature,
|
//! This module ensures that if a function's ABI requires a particular target feature,
|
||||||
//! that target feature is enabled both on the callee and all callers.
|
//! that target feature is enabled both on the callee and all callers.
|
||||||
use rustc_abi::{BackendRepr, ExternAbi, RegKind};
|
use rustc_abi::{BackendRepr, RegKind};
|
||||||
use rustc_hir::CRATE_HIR_ID;
|
use rustc_hir::CRATE_HIR_ID;
|
||||||
use rustc_middle::mir::{self, traversal};
|
use rustc_middle::mir::{self, traversal};
|
||||||
use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt};
|
||||||
|
@ -115,8 +115,8 @@ fn check_call_site_abi<'tcx>(
|
||||||
span: Span,
|
span: Span,
|
||||||
caller: InstanceKind<'tcx>,
|
caller: InstanceKind<'tcx>,
|
||||||
) {
|
) {
|
||||||
if callee.fn_sig(tcx).abi() == ExternAbi::Rust {
|
if callee.fn_sig(tcx).abi().is_rustic_abi() {
|
||||||
// "Rust" ABI never passes arguments in vector registers.
|
// we directly handle the soundness of Rust ABIs
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let typing_env = ty::TypingEnv::fully_monomorphized();
|
let typing_env = ty::TypingEnv::fully_monomorphized();
|
||||||
|
|
|
@ -436,10 +436,7 @@ fn fn_abi_sanity_check<'tcx>(
|
||||||
) {
|
) {
|
||||||
let tcx = cx.tcx();
|
let tcx = cx.tcx();
|
||||||
|
|
||||||
if spec_abi == ExternAbi::Rust
|
if spec_abi.is_rustic_abi() {
|
||||||
|| spec_abi == ExternAbi::RustCall
|
|
||||||
|| spec_abi == ExternAbi::RustCold
|
|
||||||
{
|
|
||||||
if arg.layout.is_zst() {
|
if arg.layout.is_zst() {
|
||||||
// Casting closures to function pointers depends on ZST closure types being
|
// Casting closures to function pointers depends on ZST closure types being
|
||||||
// omitted entirely in the calling convention.
|
// omitted entirely in the calling convention.
|
||||||
|
@ -687,7 +684,7 @@ fn fn_abi_adjust_for_abi<'tcx>(
|
||||||
|
|
||||||
let tcx = cx.tcx();
|
let tcx = cx.tcx();
|
||||||
|
|
||||||
if abi == ExternAbi::Rust || abi == ExternAbi::RustCall || abi == ExternAbi::RustIntrinsic {
|
if abi.is_rustic_abi() {
|
||||||
fn_abi.adjust_for_rust_abi(cx, abi);
|
fn_abi.adjust_for_rust_abi(cx, abi);
|
||||||
|
|
||||||
// Look up the deduced parameter attributes for this function, if we have its def ID and
|
// Look up the deduced parameter attributes for this function, if we have its def ID and
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
//@ known-bug: #132981
|
|
||||||
//@compile-flags: -Clink-dead-code=true --crate-type lib
|
|
||||||
//@ only-x86_64
|
|
||||||
//@ ignore-windows
|
|
||||||
// The set of targets this crashes on is really fiddly, because it is deep in our ABI logic. It
|
|
||||||
// crashes on x86_64-unknown-linux-gnu, and i686-pc-windows-msvc, but not on
|
|
||||||
// x86_64-pc-windows-msvc. If you are trying to fix this crash, don't pay too much attention to the
|
|
||||||
// directives.
|
|
||||||
|
|
||||||
#![feature(rust_cold_cc)]
|
|
||||||
pub extern "rust-cold" fn foo(_: [usize; 3]) {}
|
|
6
tests/ui/abi/rust-cold-works-with-rustic-args.rs
Normal file
6
tests/ui/abi/rust-cold-works-with-rustic-args.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
//@build-pass
|
||||||
|
//@compile-flags: -Clink-dead-code=true --crate-type lib
|
||||||
|
// We used to not handle all "rustic" ABIs in a (relatively) uniform way,
|
||||||
|
// so we failed to fix up arguments for actually passing through the ABI...
|
||||||
|
#![feature(rust_cold_cc)]
|
||||||
|
pub extern "rust-cold" fn foo(_: [usize; 3]) {}
|
Loading…
Add table
Add a link
Reference in a new issue