From 136463158460cac8c7dbb6dcbce669fa941e33b4 Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Mon, 14 Oct 2024 20:24:30 +0200 Subject: [PATCH 1/9] `rt::Argument`: elide lifetimes --- library/core/src/fmt/rt.rs | 26 +++++++++---------- tests/ui/closures/issue-111932.stderr | 2 +- .../const-generics/infer/issue-77092.stderr | 2 +- tests/ui/fmt/ifmt-unimpl.stderr | 2 +- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index eee4a9e4c6c89..af6f0da88de67 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -94,11 +94,11 @@ pub struct Argument<'a> { } #[rustc_diagnostic_item = "ArgumentMethods"] -impl<'a> Argument<'a> { +impl Argument<'_> { #[inline(always)] - fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'b> { + fn new<'a, T>(x: &'a T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'a> { Argument { - // INVARIANT: this creates an `ArgumentType<'b>` from a `&'b T` and + // INVARIANT: this creates an `ArgumentType<'a>` from a `&'a T` and // a `fn(&T, ...)`, so the invariant is maintained. ty: ArgumentType::Placeholder { value: NonNull::from(x).cast(), @@ -110,43 +110,43 @@ impl<'a> Argument<'a> { } #[inline(always)] - pub fn new_display<'b, T: Display>(x: &'b T) -> Argument<'b> { + pub fn new_display(x: &T) -> Argument<'_> { Self::new(x, Display::fmt) } #[inline(always)] - pub fn new_debug<'b, T: Debug>(x: &'b T) -> Argument<'b> { + pub fn new_debug(x: &T) -> Argument<'_> { Self::new(x, Debug::fmt) } #[inline(always)] - pub fn new_debug_noop<'b, T: Debug>(x: &'b T) -> Argument<'b> { + pub fn new_debug_noop(x: &T) -> Argument<'_> { Self::new(x, |_, _| Ok(())) } #[inline(always)] - pub fn new_octal<'b, T: Octal>(x: &'b T) -> Argument<'b> { + pub fn new_octal(x: &T) -> Argument<'_> { Self::new(x, Octal::fmt) } #[inline(always)] - pub fn new_lower_hex<'b, T: LowerHex>(x: &'b T) -> Argument<'b> { + pub fn new_lower_hex(x: &T) -> Argument<'_> { Self::new(x, LowerHex::fmt) } #[inline(always)] - pub fn new_upper_hex<'b, T: UpperHex>(x: &'b T) -> Argument<'b> { + pub fn new_upper_hex(x: &T) -> Argument<'_> { Self::new(x, UpperHex::fmt) } #[inline(always)] - pub fn new_pointer<'b, T: Pointer>(x: &'b T) -> Argument<'b> { + pub fn new_pointer(x: &T) -> Argument<'_> { Self::new(x, Pointer::fmt) } #[inline(always)] - pub fn new_binary<'b, T: Binary>(x: &'b T) -> Argument<'b> { + pub fn new_binary(x: &T) -> Argument<'_> { Self::new(x, Binary::fmt) } #[inline(always)] - pub fn new_lower_exp<'b, T: LowerExp>(x: &'b T) -> Argument<'b> { + pub fn new_lower_exp(x: &T) -> Argument<'_> { Self::new(x, LowerExp::fmt) } #[inline(always)] - pub fn new_upper_exp<'b, T: UpperExp>(x: &'b T) -> Argument<'b> { + pub fn new_upper_exp(x: &T) -> Argument<'_> { Self::new(x, UpperExp::fmt) } #[inline(always)] diff --git a/tests/ui/closures/issue-111932.stderr b/tests/ui/closures/issue-111932.stderr index ff46b10d005dc..93488ad2011e4 100644 --- a/tests/ui/closures/issue-111932.stderr +++ b/tests/ui/closures/issue-111932.stderr @@ -17,7 +17,7 @@ LL | println!("{:?}", foo); | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `dyn Foo` -note: required by an implicit `Sized` bound in `core::fmt::rt::Argument::<'a>::new_debug` +note: required by an implicit `Sized` bound in `core::fmt::rt::Argument::<'_>::new_debug` --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/const-generics/infer/issue-77092.stderr b/tests/ui/const-generics/infer/issue-77092.stderr index 9a6374a2adcbe..4ab80cec58d8d 100644 --- a/tests/ui/const-generics/infer/issue-77092.stderr +++ b/tests/ui/const-generics/infer/issue-77092.stderr @@ -25,7 +25,7 @@ LL | println!("{:?}", take_array_from_mut(&mut arr, i)); = note: required for `[i32; _]` to implement `Debug` = note: 1 redundant requirement hidden = note: required for `&mut [i32; _]` to implement `Debug` -note: required by a bound in `core::fmt::rt::Argument::<'a>::new_debug` +note: required by a bound in `core::fmt::rt::Argument::<'_>::new_debug` --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL help: consider specifying the generic arguments | diff --git a/tests/ui/fmt/ifmt-unimpl.stderr b/tests/ui/fmt/ifmt-unimpl.stderr index a22bba07c0275..f83e7c8772886 100644 --- a/tests/ui/fmt/ifmt-unimpl.stderr +++ b/tests/ui/fmt/ifmt-unimpl.stderr @@ -17,7 +17,7 @@ LL | format!("{:X}", "3"); i32 and 9 others = note: required for `&str` to implement `UpperHex` -note: required by a bound in `core::fmt::rt::Argument::<'a>::new_upper_hex` +note: required by a bound in `core::fmt::rt::Argument::<'_>::new_upper_hex` --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) From b3ae64d24fc323365bd09fe6ac8b7438f5713078 Mon Sep 17 00:00:00 2001 From: Andrew Zhogin Date: Mon, 16 Sep 2024 22:14:35 +0700 Subject: [PATCH 2/9] rust_for_linux: -Zregparm= commandline flag for X86 (#116972) --- compiler/rustc_codegen_gcc/src/builder.rs | 8 +- compiler/rustc_codegen_gcc/src/context.rs | 10 +- compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_middle/src/ty/layout.rs | 16 ++- compiler/rustc_session/messages.ftl | 3 + compiler/rustc_session/src/errors.rs | 10 ++ compiler/rustc_session/src/options.rs | 4 + compiler/rustc_session/src/session.rs | 9 ++ compiler/rustc_target/src/callconv/mod.rs | 44 ++++-- compiler/rustc_target/src/callconv/x86.rs | 104 ++++++++------ compiler/rustc_target/src/spec/mod.rs | 12 ++ compiler/rustc_ty_utils/src/abi.rs | 3 + .../src/compiler-flags/regparm.md | 20 +++ tests/codegen/regparm-inreg-rust-cc.rs | 53 +++++++ tests/codegen/regparm-inreg.rs | 133 ++++++++++++++++++ .../regparm-valid-values.regparm4.stderr | 4 + .../regparm/regparm-valid-values.rs | 24 ++++ .../regparm/requires-x86.aarch64.stderr | 4 + .../regparm/requires-x86.rs | 21 +++ .../regparm/requires-x86.x86_64.stderr | 4 + 20 files changed, 435 insertions(+), 52 deletions(-) create mode 100644 src/doc/unstable-book/src/compiler-flags/regparm.md create mode 100644 tests/codegen/regparm-inreg-rust-cc.rs create mode 100644 tests/codegen/regparm-inreg.rs create mode 100644 tests/ui/invalid-compile-flags/regparm/regparm-valid-values.regparm4.stderr create mode 100644 tests/ui/invalid-compile-flags/regparm/regparm-valid-values.rs create mode 100644 tests/ui/invalid-compile-flags/regparm/requires-x86.aarch64.stderr create mode 100644 tests/ui/invalid-compile-flags/regparm/requires-x86.rs create mode 100644 tests/ui/invalid-compile-flags/regparm/requires-x86.x86_64.stderr diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index b611f9ba8bcb3..457380685093f 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -30,7 +30,7 @@ use rustc_middle::ty::{Instance, ParamEnv, Ty, TyCtxt}; use rustc_span::Span; use rustc_span::def_id::DefId; use rustc_target::abi::call::FnAbi; -use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, Target, WasmCAbi}; +use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, WasmCAbi, X86Abi}; use crate::common::{SignType, TypeReflection, type_is_pointer}; use crate::context::CodegenCx; @@ -2347,6 +2347,12 @@ impl<'tcx> HasWasmCAbiOpt for Builder<'_, '_, 'tcx> { } } +impl<'tcx> HasX86AbiOpt for Builder<'_, '_, 'tcx> { + fn x86_abi_opt(&self) -> X86Abi { + self.cx.x86_abi_opt() + } +} + pub trait ToGccComp { fn to_gcc_comparison(&self) -> ComparisonOp; } diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 7cb49bf799135..707b35967a6d8 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -19,7 +19,9 @@ use rustc_session::Session; use rustc_span::source_map::respan; use rustc_span::{DUMMY_SP, Span}; use rustc_target::abi::{HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx}; -use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, Target, TlsModel, WasmCAbi}; +use rustc_target::spec::{ + HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, TlsModel, WasmCAbi, X86Abi, +}; use crate::callee::get_fn; use crate::common::SignType; @@ -538,6 +540,12 @@ impl<'gcc, 'tcx> HasWasmCAbiOpt for CodegenCx<'gcc, 'tcx> { } } +impl<'gcc, 'tcx> HasX86AbiOpt for CodegenCx<'gcc, 'tcx> { + fn x86_abi_opt(&self) -> X86Abi { + X86Abi { regparm: self.tcx.sess.opts.unstable_opts.regparm } + } +} + impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 3189620e969da..d3762e739db80 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -836,6 +836,7 @@ fn test_unstable_options_tracking_hash() { tracked!(profile_emit, Some(PathBuf::from("abc"))); tracked!(profile_sample_use, Some(PathBuf::from("abc"))); tracked!(profiler_runtime, "abc".to_string()); + tracked!(regparm, Some(3)); tracked!(relax_elf_relocations, Some(true)); tracked!(remap_cwd_prefix, Some(PathBuf::from("abc"))); tracked!(sanitizer, SanitizerSet::ADDRESS); diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 6c12b691c26c0..99a4cb56dd361 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -21,7 +21,9 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; use rustc_target::abi::call::FnAbi; use rustc_target::abi::{FieldIdx, TyAbiInterface, VariantIdx, call}; use rustc_target::spec::abi::Abi as SpecAbi; -use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, PanicStrategy, Target, WasmCAbi}; +use rustc_target::spec::{ + HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, PanicStrategy, Target, WasmCAbi, X86Abi, +}; use tracing::debug; use {rustc_abi as abi, rustc_hir as hir}; @@ -544,6 +546,12 @@ impl<'tcx> HasWasmCAbiOpt for TyCtxt<'tcx> { } } +impl<'tcx> HasX86AbiOpt for TyCtxt<'tcx> { + fn x86_abi_opt(&self) -> X86Abi { + X86Abi { regparm: self.sess.opts.unstable_opts.regparm } + } +} + impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> { #[inline] fn tcx(&self) -> TyCtxt<'tcx> { @@ -595,6 +603,12 @@ impl<'tcx> HasWasmCAbiOpt for LayoutCx<'tcx> { } } +impl<'tcx> HasX86AbiOpt for LayoutCx<'tcx> { + fn x86_abi_opt(&self) -> X86Abi { + self.calc.cx.x86_abi_opt() + } +} + impl<'tcx> HasTyCtxt<'tcx> for LayoutCx<'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.calc.cx diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index 1816d1278fe27..893c532f1fbb1 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -136,3 +136,6 @@ session_unsupported_crate_type_for_target = dropping unsupported crate type `{$crate_type}` for target `{$target_triple}` session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is greater than 5 + +session_unsupported_regparm = `-Zregparm={$regparm}` is unsupported (valid values 0-3) +session_unsupported_regparm_arch = `-Zregparm=N` is only supported on x86 diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index dbb74d1e2446e..20e8fb38b88ce 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -485,6 +485,16 @@ pub(crate) struct FunctionReturnRequiresX86OrX8664; #[diag(session_function_return_thunk_extern_requires_non_large_code_model)] pub(crate) struct FunctionReturnThunkExternRequiresNonLargeCodeModel; +#[derive(Diagnostic)] +#[diag(session_unsupported_regparm)] +pub(crate) struct UnsupportedRegparm { + pub(crate) regparm: u32, +} + +#[derive(Diagnostic)] +#[diag(session_unsupported_regparm_arch)] +pub(crate) struct UnsupportedRegparmArch; + #[derive(Diagnostic)] #[diag(session_failed_to_create_profiler)] pub(crate) struct FailedToCreateProfiler { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index f9964b59a9415..f4a9d4bf92cbc 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2000,6 +2000,10 @@ options! { "enable queries of the dependency graph for regression testing (default: no)"), randomize_layout: bool = (false, parse_bool, [TRACKED], "randomize the layout of types (default: no)"), + regparm: Option = (None, parse_opt_number, [TRACKED], + "On x86-32 targets, setting this to N causes the compiler to pass N arguments \ + in registers EAX, EDX, and ECX instead of on the stack.\ + It is UNSOUND to link together crates that use different values for this flag!"), relax_elf_relocations: Option = (None, parse_opt_bool, [TRACKED], "whether ELF relocations can be relaxed"), remap_cwd_prefix: Option = (None, parse_opt_pathbuf, [TRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 27879d817b208..1963cf4eb7c06 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1337,6 +1337,15 @@ fn validate_commandline_args_with_session_available(sess: &Session) { } } + if let Some(regparm) = sess.opts.unstable_opts.regparm { + if regparm > 3 { + sess.dcx().emit_err(errors::UnsupportedRegparm { regparm }); + } + if sess.target.arch != "x86" { + sess.dcx().emit_err(errors::UnsupportedRegparmArch); + } + } + // The code model check applies to `thunk` and `thunk-extern`, but not `thunk-inline`, so it is // kept as a `match` to force a change if new ones are added, even if we currently only support // `thunk-extern` like Clang. diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 832246495bc99..07ee3f892b702 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -6,7 +6,7 @@ use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use crate::abi::{self, Abi, Align, HasDataLayout, Size, TyAbiInterface, TyAndLayout}; -use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, WasmCAbi}; +use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, WasmCAbi}; mod aarch64; mod amdgpu; @@ -631,7 +631,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { ) -> Result<(), AdjustForForeignAbiError> where Ty: TyAbiInterface<'a, C> + Copy, - C: HasDataLayout + HasTargetSpec + HasWasmCAbiOpt, + C: HasDataLayout + HasTargetSpec + HasWasmCAbiOpt + HasX86AbiOpt, { if abi == spec::abi::Abi::X86Interrupt { if let Some(arg) = self.args.first_mut() { @@ -643,14 +643,18 @@ impl<'a, Ty> FnAbi<'a, Ty> { let spec = cx.target_spec(); match &spec.arch[..] { "x86" => { - let flavor = if let spec::abi::Abi::Fastcall { .. } - | spec::abi::Abi::Vectorcall { .. } = abi - { - x86::Flavor::FastcallOrVectorcall - } else { - x86::Flavor::General + let (flavor, regparm) = match abi { + spec::abi::Abi::Fastcall { .. } | spec::abi::Abi::Vectorcall { .. } => { + (x86::Flavor::FastcallOrVectorcall, None) + } + spec::abi::Abi::C { .. } + | spec::abi::Abi::Cdecl { .. } + | spec::abi::Abi::Stdcall { .. } => { + (x86::Flavor::General, cx.x86_abi_opt().regparm) + } + _ => (x86::Flavor::General, None), }; - x86::compute_abi_info(cx, self, flavor); + x86::compute_abi_info(cx, self, x86::X86Options { flavor, regparm }); } "x86_64" => match abi { spec::abi::Abi::SysV64 { .. } => x86_64::compute_abi_info(cx, self), @@ -716,6 +720,28 @@ impl<'a, Ty> FnAbi<'a, Ty> { Ok(()) } + + pub fn fill_inregs_for_rust_abi(&mut self, cx: &C) + where + Ty: TyAbiInterface<'a, C> + Copy, + C: HasTargetSpec + HasX86AbiOpt, + { + let spec = cx.target_spec(); + match &spec.arch[..] { + "x86" => { + x86::fill_inregs( + cx, + self, + x86::X86Options { + flavor: x86::Flavor::General, + regparm: cx.x86_abi_opt().regparm, + }, + true, + ); + } + _ => {} + } + } } impl FromStr for Conv { diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index d9af83d3205bc..40c3e7a891a0c 100644 --- a/compiler/rustc_target/src/callconv/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs @@ -8,7 +8,12 @@ pub(crate) enum Flavor { FastcallOrVectorcall, } -pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, flavor: Flavor) +pub(crate) struct X86Options { + pub flavor: Flavor, + pub regparm: Option, +} + +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, opts: X86Options) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout + HasTargetSpec, @@ -128,58 +133,77 @@ where } } - if flavor == Flavor::FastcallOrVectorcall { - // Mark arguments as InReg like clang does it, - // so our fastcall/vectorcall is compatible with C/C++ fastcall/vectorcall. + fill_inregs(cx, fn_abi, opts, false); +} - // Clang reference: lib/CodeGen/TargetInfo.cpp - // See X86_32ABIInfo::shouldPrimitiveUseInReg(), X86_32ABIInfo::updateFreeRegs() +pub(crate) fn fill_inregs<'a, Ty, C>( + cx: &C, + fn_abi: &mut FnAbi<'a, Ty>, + opts: X86Options, + rust_abi: bool, +) where + Ty: TyAbiInterface<'a, C> + Copy, +{ + if opts.flavor != Flavor::FastcallOrVectorcall && opts.regparm.is_none_or(|x| x == 0) { + return; + } + // Mark arguments as InReg like clang does it, + // so our fastcall/vectorcall is compatible with C/C++ fastcall/vectorcall. - // IsSoftFloatABI is only set to true on ARM platforms, - // which in turn can't be x86? + // Clang reference: lib/CodeGen/TargetInfo.cpp + // See X86_32ABIInfo::shouldPrimitiveUseInReg(), X86_32ABIInfo::updateFreeRegs() - let mut free_regs = 2; + // IsSoftFloatABI is only set to true on ARM platforms, + // which in turn can't be x86? - for arg in fn_abi.args.iter_mut() { - let attrs = match arg.mode { - PassMode::Ignore - | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => { - continue; - } - PassMode::Direct(ref mut attrs) => attrs, - PassMode::Pair(..) - | PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } - | PassMode::Cast { .. } => { - unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode) - } - }; + // 2 for fastcall/vectorcall, regparm limited by 3 otherwise + let mut free_regs = opts.regparm.unwrap_or(2).into(); + + // For types generating PassMode::Cast, InRegs will not be set. + // Maybe, this is a FIXME + let has_casts = fn_abi.args.iter().any(|arg| matches!(arg.mode, PassMode::Cast { .. })); + if has_casts && rust_abi { + return; + } - // At this point we know this must be a primitive of sorts. - let unit = arg.layout.homogeneous_aggregate(cx).unwrap().unit().unwrap(); - assert_eq!(unit.size, arg.layout.size); - if unit.kind == RegKind::Float { + for arg in fn_abi.args.iter_mut() { + let attrs = match arg.mode { + PassMode::Ignore | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => { continue; } + PassMode::Direct(ref mut attrs) => attrs, + PassMode::Pair(..) + | PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } + | PassMode::Cast { .. } => { + unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode) + } + }; - let size_in_regs = (arg.layout.size.bits() + 31) / 32; + // At this point we know this must be a primitive of sorts. + let unit = arg.layout.homogeneous_aggregate(cx).unwrap().unit().unwrap(); + assert_eq!(unit.size, arg.layout.size); + if matches!(unit.kind, RegKind::Float | RegKind::Vector) { + continue; + } - if size_in_regs == 0 { - continue; - } + let size_in_regs = (arg.layout.size.bits() + 31) / 32; - if size_in_regs > free_regs { - break; - } + if size_in_regs == 0 { + continue; + } - free_regs -= size_in_regs; + if size_in_regs > free_regs { + break; + } - if arg.layout.size.bits() <= 32 && unit.kind == RegKind::Integer { - attrs.set(ArgAttribute::InReg); - } + free_regs -= size_in_regs; - if free_regs == 0 { - break; - } + if arg.layout.size.bits() <= 32 && unit.kind == RegKind::Integer { + attrs.set(ArgAttribute::InReg); + } + + if free_regs == 0 { + break; } } } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 82e11a3afce32..812edf14070bc 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2096,6 +2096,18 @@ pub trait HasWasmCAbiOpt { fn wasm_c_abi_opt(&self) -> WasmCAbi; } +/// x86 (32-bit) abi options. +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct X86Abi { + /// On x86-32 targets, the regparm N causes the compiler to pass arguments + /// in registers EAX, EDX, and ECX instead of on the stack. + pub regparm: Option, +} + +pub trait HasX86AbiOpt { + fn x86_abi_opt(&self) -> X86Abi; +} + type StaticCow = Cow<'static, T>; /// Optional aspects of a target specification. diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index deda16b76b587..661f140e69700 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -797,6 +797,9 @@ fn fn_abi_adjust_for_abi<'tcx>( for (arg_idx, arg) in fn_abi.args.iter_mut().enumerate() { fixup(arg, Some(arg_idx)); } + if tcx.sess.target.arch == "x86" { + fn_abi.fill_inregs_for_rust_abi(cx); + } } else { fn_abi .adjust_for_foreign_abi(cx, abi) diff --git a/src/doc/unstable-book/src/compiler-flags/regparm.md b/src/doc/unstable-book/src/compiler-flags/regparm.md new file mode 100644 index 0000000000000..a054d55cd8b6d --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/regparm.md @@ -0,0 +1,20 @@ +# `regparm` + +The tracking issue for this feature is: https://github.com/rust-lang/rust/issues/131749. + +------------------------ + +Option -Zregparm=N causes the compiler to pass N arguments +in registers EAX, EDX, and ECX instead of on the stack. +It is UNSOUND to link together crates that use different values for this flag. +It is only supported on `x86`. + +It is equivalent to [Clang]'s and [GCC]'s `-mregparm`. + +Supported values for this option are 0-3. + +[Clang]: https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mregparm +[GCC]: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-regparm-function-attribute_002c-x86 + +Implementation details: +For eligible arguments, llvm `inreg` attribute is set. diff --git a/tests/codegen/regparm-inreg-rust-cc.rs b/tests/codegen/regparm-inreg-rust-cc.rs new file mode 100644 index 0000000000000..a2d8d5349ea03 --- /dev/null +++ b/tests/codegen/regparm-inreg-rust-cc.rs @@ -0,0 +1,53 @@ +// Checks how `regparm` flag works with Rust calling convention with array types. +// When there is a small array type in signature (casted to combined int type), +// inregs will not be set. PassMode::Cast is unsupported. +// x86 only. + +//@ compile-flags: --target i686-unknown-linux-gnu -O -C no-prepopulate-passes +//@ needs-llvm-components: x86 + +//@ revisions:regparm0 regparm1 regparm2 regparm3 +//@[regparm0] compile-flags: -Zregparm=0 +//@[regparm1] compile-flags: -Zregparm=1 +//@[regparm2] compile-flags: -Zregparm=2 +//@[regparm3] compile-flags: -Zregparm=3 + +#![crate_type = "lib"] +#![no_core] +#![feature(no_core, lang_items)] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +pub mod tests { + // CHECK: @f1(i16 %0, i32 noundef %_2, i32 noundef %_3) + #[no_mangle] + pub extern "Rust" fn f1(_: [u8; 2], _: i32, _: i32) {} + + // CHECK: @f2(i24 %0, i32 noundef %_2, i32 noundef %_3) + #[no_mangle] + pub extern "Rust" fn f2(_: [u8; 3], _: i32, _: i32) {} + + // regparm0: @f3(ptr {{.*}} %_1, i32 noundef %_2, i32 noundef %_3) + // regparm1: @f3(ptr {{.*}} %_1, i32 inreg noundef %_2, i32 noundef %_3) + // regparm2: @f3(ptr {{.*}} %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) + // regparm3: @f3(ptr {{.*}} %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) + #[no_mangle] + pub extern "Rust" fn f3(_: [u8; 7], _: i32, _: i32) {} + + // regparm0: @f4(ptr {{.*}} %_1, i32 noundef %_2, i32 noundef %_3) + // regparm1: @f4(ptr {{.*}} %_1, i32 inreg noundef %_2, i32 noundef %_3) + // regparm2: @f4(ptr {{.*}} %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) + // regparm3: @f4(ptr {{.*}} %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) + #[no_mangle] + pub extern "Rust" fn f4(_: [u8; 11], _: i32, _: i32) {} + + // regparm0: @f5(ptr {{.*}} %_1, i32 noundef %_2, i32 noundef %_3) + // regparm1: @f5(ptr {{.*}} %_1, i32 inreg noundef %_2, i32 noundef %_3) + // regparm2: @f5(ptr {{.*}} %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) + // regparm3: @f5(ptr {{.*}} %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) + #[no_mangle] + pub extern "Rust" fn f5(_: [u8; 33], _: i32, _: i32) {} +} diff --git a/tests/codegen/regparm-inreg.rs b/tests/codegen/regparm-inreg.rs new file mode 100644 index 0000000000000..ce87a66d0e917 --- /dev/null +++ b/tests/codegen/regparm-inreg.rs @@ -0,0 +1,133 @@ +// Checks how `regparm` flag works with different calling conventions: +// marks function arguments as "inreg" like the C/C++ compilers for the platforms. +// x86 only. + +//@ compile-flags: --target i686-unknown-linux-gnu -O -C no-prepopulate-passes +//@ needs-llvm-components: x86 +//@ only-x86 + +//@ revisions:regparm0 regparm1 regparm2 regparm3 +//@[regparm0] compile-flags: -Zregparm=0 +//@[regparm1] compile-flags: -Zregparm=1 +//@[regparm2] compile-flags: -Zregparm=2 +//@[regparm3] compile-flags: -Zregparm=3 + +#![crate_type = "lib"] +#![no_core] +#![feature(no_core, lang_items, repr_simd)] +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +pub mod tests { + // regparm doesn't work for "fastcall" calling conv (only 2 inregs) + // CHECK: @f1(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3) + #[no_mangle] + pub extern "fastcall" fn f1(_: i32, _: i32, _: i32) {} + + // regparm0: @f2(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3) + // regparm1: @f2(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3) + // regparm2: @f2(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3) + // regparm3: @f2(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) + #[no_mangle] + pub extern "Rust" fn f2(_: i32, _: i32, _: i32) {} + + // regparm0: @f3(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3) + // regparm1: @f3(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3) + // regparm2: @f3(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3) + // regparm3: @f3(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) + #[no_mangle] + pub extern "C" fn f3(_: i32, _: i32, _: i32) {} + + // regparm0: @f4(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3) + // regparm1: @f4(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3) + // regparm2: @f4(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3) + // regparm3: @f4(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) + #[no_mangle] + pub extern "cdecl" fn f4(_: i32, _: i32, _: i32) {} + + // regparm0: @f5(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3) + // regparm1: @f5(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3) + // regparm2: @f5(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3) + // regparm3: @f5(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) + #[no_mangle] + pub extern "stdcall" fn f5(_: i32, _: i32, _: i32) {} + + // regparm doesn't work for thiscall + // CHECK: @f6(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3) + #[no_mangle] + pub extern "thiscall" fn f6(_: i32, _: i32, _: i32) {} + + struct S1 { + x1: i32, + } + // regparm0: @f7(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3, i32 noundef %_4) + // regparm1: @f7(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3, i32 noundef %_4) + // regparm2: @f7(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3, i32 noundef %_4) + // regparm3: @f7(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3, + // regparm3-SAME: i32 noundef %_4) + #[no_mangle] + pub extern "C" fn f7(_: i32, _: i32, _: S1, _: i32) {} + + #[repr(C)] + struct S2 { + x1: i32, + x2: i32, + } + // regparm0: @f8(i32 noundef %_1, i32 noundef %_2, ptr {{.*}} %_3, i32 noundef %_4) + // regparm1: @f8(i32 inreg noundef %_1, i32 noundef %_2, ptr {{.*}} %_3, i32 noundef %_4) + // regparm2: @f8(i32 inreg noundef %_1, i32 inreg noundef %_2, ptr {{.*}} %_3, i32 noundef %_4) + // regparm3: @f8(i32 inreg noundef %_1, i32 inreg noundef %_2, ptr {{.*}} %_3, + // regparm3-SAME: i32 inreg noundef %_4) + #[no_mangle] + pub extern "C" fn f8(_: i32, _: i32, _: S2, _: i32) {} + + // regparm0: @f9(i1 noundef zeroext %_1, i16 noundef signext %_2, i64 noundef %_3, + // regparm0-SAME: i128 noundef %_4) + // regparm1: @f9(i1 inreg noundef zeroext %_1, i16 noundef signext %_2, i64 noundef %_3, + // regparm1-SAME: i128 noundef %_4) + // regparm2: @f9(i1 inreg noundef zeroext %_1, i16 inreg noundef signext %_2, i64 noundef %_3, + // regparm2-SAME: i128 noundef %_4) + // regparm3: @f9(i1 inreg noundef zeroext %_1, i16 inreg noundef signext %_2, i64 noundef %_3, + // regparm3-SAME: i128 noundef %_4) + #[no_mangle] + pub extern "C" fn f9(_: bool, _: i16, _: i64, _: u128) {} + + // regparm0: @f10(float noundef %_1, double noundef %_2, i1 noundef zeroext %_3, + // regparm0-SAME: i16 noundef signext %_4) + // regparm1: @f10(float noundef %_1, double noundef %_2, i1 inreg noundef zeroext %_3, + // regparm1-SAME: i16 noundef signext %_4) + // regparm2: @f10(float noundef %_1, double noundef %_2, i1 inreg noundef zeroext %_3, + // regparm2-SAME: i16 inreg noundef signext %_4) + // regparm3: @f10(float noundef %_1, double noundef %_2, i1 inreg noundef zeroext %_3, + // regparm3-SAME: i16 inreg noundef signext %_4) + #[no_mangle] + pub extern "C" fn f10(_: f32, _: f64, _: bool, _: i16) {} + + #[allow(non_camel_case_types)] + #[repr(simd)] + pub struct __m128([f32; 4]); + + // regparm0: @f11(i32 noundef %_1, <4 x float> %_2, i32 noundef %_3, i32 noundef %_4) + // regparm1: @f11(i32 inreg noundef %_1, <4 x float> %_2, i32 noundef %_3, i32 noundef %_4) + // regparm2: @f11(i32 inreg noundef %_1, <4 x float> %_2, i32 inreg noundef %_3, + // regparm2-SAME: i32 noundef %_4) + // regparm3: @f11(i32 inreg noundef %_1, <4 x float> %_2, i32 inreg noundef %_3, + // regparm3-SAME: i32 inreg noundef %_4) + #[no_mangle] + pub extern "C" fn f11(_: i32, _: __m128, _: i32, _: i32) {} + + #[allow(non_camel_case_types)] + #[repr(simd)] + pub struct __m256([f32; 8]); + + // regparm0: @f12(i32 noundef %_1, <8 x float> %_2, i32 noundef %_3, i32 noundef %_4) + // regparm1: @f12(i32 inreg noundef %_1, <8 x float> %_2, i32 noundef %_3, i32 noundef %_4) + // regparm2: @f12(i32 inreg noundef %_1, <8 x float> %_2, i32 inreg noundef %_3, + // regparm2-SAME: i32 noundef %_4) + // regparm3: @f12(i32 inreg noundef %_1, <8 x float> %_2, i32 inreg noundef %_3, + // regparm3-SAME: i32 inreg noundef %_4) + #[no_mangle] + pub extern "C" fn f12(_: i32, _: __m256, _: i32, _: i32) {} +} diff --git a/tests/ui/invalid-compile-flags/regparm/regparm-valid-values.regparm4.stderr b/tests/ui/invalid-compile-flags/regparm/regparm-valid-values.regparm4.stderr new file mode 100644 index 0000000000000..8fc04adf57f56 --- /dev/null +++ b/tests/ui/invalid-compile-flags/regparm/regparm-valid-values.regparm4.stderr @@ -0,0 +1,4 @@ +error: `-Zregparm=4` is unsupported (valid values 0-3) + +error: aborting due to 1 previous error + diff --git a/tests/ui/invalid-compile-flags/regparm/regparm-valid-values.rs b/tests/ui/invalid-compile-flags/regparm/regparm-valid-values.rs new file mode 100644 index 0000000000000..b548d678520b6 --- /dev/null +++ b/tests/ui/invalid-compile-flags/regparm/regparm-valid-values.rs @@ -0,0 +1,24 @@ +//@ revisions: regparm0 regparm1 regparm2 regparm3 regparm4 + +//@ needs-llvm-components: x86 +//@ compile-flags: --target i686-unknown-linux-gnu + +//@[regparm0] check-pass +//@[regparm0] compile-flags: -Zregparm=0 + +//@[regparm1] check-pass +//@[regparm1] compile-flags: -Zregparm=1 + +//@[regparm2] check-pass +//@[regparm2] compile-flags: -Zregparm=2 + +//@[regparm3] check-pass +//@[regparm3] compile-flags: -Zregparm=3 + +//@[regparm4] check-fail +//@[regparm4] compile-flags: -Zregparm=4 +//@[regparm4] error-pattern: `-Zregparm=4` is unsupported (valid values 0-3) + +#![feature(no_core)] +#![no_core] +#![no_main] diff --git a/tests/ui/invalid-compile-flags/regparm/requires-x86.aarch64.stderr b/tests/ui/invalid-compile-flags/regparm/requires-x86.aarch64.stderr new file mode 100644 index 0000000000000..2433519f803c8 --- /dev/null +++ b/tests/ui/invalid-compile-flags/regparm/requires-x86.aarch64.stderr @@ -0,0 +1,4 @@ +error: `-Zregparm=N` is only supported on x86 + +error: aborting due to 1 previous error + diff --git a/tests/ui/invalid-compile-flags/regparm/requires-x86.rs b/tests/ui/invalid-compile-flags/regparm/requires-x86.rs new file mode 100644 index 0000000000000..ce6e437fb476d --- /dev/null +++ b/tests/ui/invalid-compile-flags/regparm/requires-x86.rs @@ -0,0 +1,21 @@ +//@ revisions: x86 x86_64 aarch64 + +//@ compile-flags: -Zregparm=3 + +//@[x86] check-pass +//@[x86] needs-llvm-components: x86 +//@[x86] compile-flags: --target i686-unknown-linux-gnu + +//@[x86_64] check-fail +//@[x86_64] needs-llvm-components: x86 +//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86_64] error-pattern: `-Zregparm=N` is only supported on x86 + +//@[aarch64] check-fail +//@[aarch64] needs-llvm-components: aarch64 +//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu +//@[aarch64] error-pattern: `-Zregparm=N` is only supported on x86 + +#![feature(no_core)] +#![no_core] +#![no_main] diff --git a/tests/ui/invalid-compile-flags/regparm/requires-x86.x86_64.stderr b/tests/ui/invalid-compile-flags/regparm/requires-x86.x86_64.stderr new file mode 100644 index 0000000000000..2433519f803c8 --- /dev/null +++ b/tests/ui/invalid-compile-flags/regparm/requires-x86.x86_64.stderr @@ -0,0 +1,4 @@ +error: `-Zregparm=N` is only supported on x86 + +error: aborting due to 1 previous error + From 67081dbb14dece75707722c28e778ddd7f442a6c Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Thu, 17 Oct 2024 18:18:01 -0700 Subject: [PATCH 3/9] Update triagebot.toml Update the list of reviewers after updating the team. --- triagebot.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 33dcbfa55a4f2..a23fc97253960 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1072,7 +1072,7 @@ project-const-traits = [ project-stable-mir = [ "@celinval", "@oli-obk", - "@ouz-a", + "@scottmcm", ] project-exploit-mitigations = [ From d6f5b437e598074a612fc72c053b00f70c38e607 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 18 Oct 2024 11:57:12 -0700 Subject: [PATCH 4/9] compiler: Enable test for regparm on different hosts --- tests/codegen/regparm-inreg.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/codegen/regparm-inreg.rs b/tests/codegen/regparm-inreg.rs index ce87a66d0e917..188cad9271efe 100644 --- a/tests/codegen/regparm-inreg.rs +++ b/tests/codegen/regparm-inreg.rs @@ -4,7 +4,6 @@ //@ compile-flags: --target i686-unknown-linux-gnu -O -C no-prepopulate-passes //@ needs-llvm-components: x86 -//@ only-x86 //@ revisions:regparm0 regparm1 regparm2 regparm3 //@[regparm0] compile-flags: -Zregparm=0 From b9c96780b47b0ac3710202df884dfb3580fc4b76 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 18 Oct 2024 11:54:07 -0700 Subject: [PATCH 5/9] compiler: Revert -Zregparm handling for extern Rust --- compiler/rustc_target/src/callconv/mod.rs | 22 ---------- compiler/rustc_ty_utils/src/abi.rs | 3 -- tests/codegen/regparm-inreg-rust-cc.rs | 53 ----------------------- tests/codegen/regparm-inreg.rs | 7 --- 4 files changed, 85 deletions(-) delete mode 100644 tests/codegen/regparm-inreg-rust-cc.rs diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 07ee3f892b702..5d120a68059a8 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -720,28 +720,6 @@ impl<'a, Ty> FnAbi<'a, Ty> { Ok(()) } - - pub fn fill_inregs_for_rust_abi(&mut self, cx: &C) - where - Ty: TyAbiInterface<'a, C> + Copy, - C: HasTargetSpec + HasX86AbiOpt, - { - let spec = cx.target_spec(); - match &spec.arch[..] { - "x86" => { - x86::fill_inregs( - cx, - self, - x86::X86Options { - flavor: x86::Flavor::General, - regparm: cx.x86_abi_opt().regparm, - }, - true, - ); - } - _ => {} - } - } } impl FromStr for Conv { diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 661f140e69700..deda16b76b587 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -797,9 +797,6 @@ fn fn_abi_adjust_for_abi<'tcx>( for (arg_idx, arg) in fn_abi.args.iter_mut().enumerate() { fixup(arg, Some(arg_idx)); } - if tcx.sess.target.arch == "x86" { - fn_abi.fill_inregs_for_rust_abi(cx); - } } else { fn_abi .adjust_for_foreign_abi(cx, abi) diff --git a/tests/codegen/regparm-inreg-rust-cc.rs b/tests/codegen/regparm-inreg-rust-cc.rs deleted file mode 100644 index a2d8d5349ea03..0000000000000 --- a/tests/codegen/regparm-inreg-rust-cc.rs +++ /dev/null @@ -1,53 +0,0 @@ -// Checks how `regparm` flag works with Rust calling convention with array types. -// When there is a small array type in signature (casted to combined int type), -// inregs will not be set. PassMode::Cast is unsupported. -// x86 only. - -//@ compile-flags: --target i686-unknown-linux-gnu -O -C no-prepopulate-passes -//@ needs-llvm-components: x86 - -//@ revisions:regparm0 regparm1 regparm2 regparm3 -//@[regparm0] compile-flags: -Zregparm=0 -//@[regparm1] compile-flags: -Zregparm=1 -//@[regparm2] compile-flags: -Zregparm=2 -//@[regparm3] compile-flags: -Zregparm=3 - -#![crate_type = "lib"] -#![no_core] -#![feature(no_core, lang_items)] - -#[lang = "sized"] -trait Sized {} -#[lang = "copy"] -trait Copy {} - -pub mod tests { - // CHECK: @f1(i16 %0, i32 noundef %_2, i32 noundef %_3) - #[no_mangle] - pub extern "Rust" fn f1(_: [u8; 2], _: i32, _: i32) {} - - // CHECK: @f2(i24 %0, i32 noundef %_2, i32 noundef %_3) - #[no_mangle] - pub extern "Rust" fn f2(_: [u8; 3], _: i32, _: i32) {} - - // regparm0: @f3(ptr {{.*}} %_1, i32 noundef %_2, i32 noundef %_3) - // regparm1: @f3(ptr {{.*}} %_1, i32 inreg noundef %_2, i32 noundef %_3) - // regparm2: @f3(ptr {{.*}} %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) - // regparm3: @f3(ptr {{.*}} %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) - #[no_mangle] - pub extern "Rust" fn f3(_: [u8; 7], _: i32, _: i32) {} - - // regparm0: @f4(ptr {{.*}} %_1, i32 noundef %_2, i32 noundef %_3) - // regparm1: @f4(ptr {{.*}} %_1, i32 inreg noundef %_2, i32 noundef %_3) - // regparm2: @f4(ptr {{.*}} %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) - // regparm3: @f4(ptr {{.*}} %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) - #[no_mangle] - pub extern "Rust" fn f4(_: [u8; 11], _: i32, _: i32) {} - - // regparm0: @f5(ptr {{.*}} %_1, i32 noundef %_2, i32 noundef %_3) - // regparm1: @f5(ptr {{.*}} %_1, i32 inreg noundef %_2, i32 noundef %_3) - // regparm2: @f5(ptr {{.*}} %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) - // regparm3: @f5(ptr {{.*}} %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) - #[no_mangle] - pub extern "Rust" fn f5(_: [u8; 33], _: i32, _: i32) {} -} diff --git a/tests/codegen/regparm-inreg.rs b/tests/codegen/regparm-inreg.rs index 188cad9271efe..c8c647bcc87c0 100644 --- a/tests/codegen/regparm-inreg.rs +++ b/tests/codegen/regparm-inreg.rs @@ -25,13 +25,6 @@ pub mod tests { #[no_mangle] pub extern "fastcall" fn f1(_: i32, _: i32, _: i32) {} - // regparm0: @f2(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3) - // regparm1: @f2(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3) - // regparm2: @f2(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3) - // regparm3: @f2(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) - #[no_mangle] - pub extern "Rust" fn f2(_: i32, _: i32, _: i32) {} - // regparm0: @f3(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3) // regparm1: @f3(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3) // regparm2: @f3(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3) From 37dc4ec8d6519d7ba1ed8a11fb57ff4d1eb995dd Mon Sep 17 00:00:00 2001 From: Andrew Zhogin <44302620+azhogin@users.noreply.github.com> Date: Sun, 20 Oct 2024 18:18:01 +0700 Subject: [PATCH 6/9] Limited -Zregparm support (no Rust calling conv) descriptions Co-authored-by: Jubilee --- compiler/rustc_session/src/options.rs | 3 ++- src/doc/unstable-book/src/compiler-flags/regparm.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index f4a9d4bf92cbc..54a4621db2462 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2002,7 +2002,8 @@ options! { "randomize the layout of types (default: no)"), regparm: Option = (None, parse_opt_number, [TRACKED], "On x86-32 targets, setting this to N causes the compiler to pass N arguments \ - in registers EAX, EDX, and ECX instead of on the stack.\ + in registers EAX, EDX, and ECX instead of on the stack for\ + \"C\", \"cdecl\", and \"stdcall\" fn.\ It is UNSOUND to link together crates that use different values for this flag!"), relax_elf_relocations: Option = (None, parse_opt_bool, [TRACKED], "whether ELF relocations can be relaxed"), diff --git a/src/doc/unstable-book/src/compiler-flags/regparm.md b/src/doc/unstable-book/src/compiler-flags/regparm.md index a054d55cd8b6d..8f311f091c0a2 100644 --- a/src/doc/unstable-book/src/compiler-flags/regparm.md +++ b/src/doc/unstable-book/src/compiler-flags/regparm.md @@ -5,7 +5,7 @@ The tracking issue for this feature is: https://github.com/rust-lang/rust/issues ------------------------ Option -Zregparm=N causes the compiler to pass N arguments -in registers EAX, EDX, and ECX instead of on the stack. +in registers EAX, EDX, and ECX instead of on the stack for "C", "cdecl", and "stdcall" fn. It is UNSOUND to link together crates that use different values for this flag. It is only supported on `x86`. From a269e4da72ed1e2dc71eca2871acab6b9f1423c5 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sun, 20 Oct 2024 02:10:19 +0200 Subject: [PATCH 7/9] run git commands in bootstrap in parallel this saves about 150ms on many ./x invocations --- src/bootstrap/src/lib.rs | 19 ++++++++++++------- src/bootstrap/src/utils/channel.rs | 14 +++++++------- src/bootstrap/src/utils/helpers.rs | 27 +++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 3924a6d714e3b..a9db0377a507b 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -545,23 +545,28 @@ impl Build { .args(["--get-regexp", "path"]) .run_capture(self) .stdout(); - for line in output.lines() { + std::thread::scope(|s| { // Look for `submodule.$name.path = $path` // Sample output: `submodule.src/rust-installer.path src/tools/rust-installer` - let submodule = line.split_once(' ').unwrap().1; - self.update_existing_submodule(submodule); - } + for line in output.lines() { + let submodule = line.split_once(' ').unwrap().1; + let config = self.config.clone(); + s.spawn(move || { + Self::update_existing_submodule(&config, submodule); + }); + } + }); } /// Updates the given submodule only if it's initialized already; nothing happens otherwise. - pub fn update_existing_submodule(&self, submodule: &str) { + pub fn update_existing_submodule(config: &Config, submodule: &str) { // Avoid running git when there isn't a git checkout. - if !self.config.submodules() { + if !config.submodules() { return; } if GitInfo::new(false, Path::new(submodule)).is_managed_git_subrepository() { - self.config.update_submodule(submodule); + config.update_submodule(submodule); } } diff --git a/src/bootstrap/src/utils/channel.rs b/src/bootstrap/src/utils/channel.rs index c361abb9c9e13..4a9ecc7a4f8a1 100644 --- a/src/bootstrap/src/utils/channel.rs +++ b/src/bootstrap/src/utils/channel.rs @@ -10,7 +10,7 @@ use std::path::Path; use super::helpers; use crate::Build; -use crate::utils::helpers::{output, t}; +use crate::utils::helpers::{start_process, t}; #[derive(Clone, Default)] pub enum GitInfo { @@ -56,7 +56,7 @@ impl GitInfo { } // Ok, let's scrape some info - let ver_date = output( + let ver_date = start_process( helpers::git(Some(dir)) .arg("log") .arg("-1") @@ -65,14 +65,14 @@ impl GitInfo { .as_command_mut(), ); let ver_hash = - output(helpers::git(Some(dir)).arg("rev-parse").arg("HEAD").as_command_mut()); - let short_ver_hash = output( + start_process(helpers::git(Some(dir)).arg("rev-parse").arg("HEAD").as_command_mut()); + let short_ver_hash = start_process( helpers::git(Some(dir)).arg("rev-parse").arg("--short=9").arg("HEAD").as_command_mut(), ); GitInfo::Present(Some(Info { - commit_date: ver_date.trim().to_string(), - sha: ver_hash.trim().to_string(), - short_sha: short_ver_hash.trim().to_string(), + commit_date: ver_date().trim().to_string(), + sha: ver_hash().trim().to_string(), + short_sha: short_ver_hash().trim().to_string(), })) } diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 2519ace92b9e0..7162007e9f0f7 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -288,6 +288,33 @@ pub fn output(cmd: &mut Command) -> String { String::from_utf8(output.stdout).unwrap() } +/// Spawn a process and return a closure that will wait for the process +/// to finish and then return its output. This allows the spawned process +/// to do work without immediately blocking bootstrap. +#[track_caller] +pub fn start_process(cmd: &mut Command) -> impl FnOnce() -> String { + let child = match cmd.stderr(Stdio::inherit()).stdout(Stdio::piped()).spawn() { + Ok(child) => child, + Err(e) => fail(&format!("failed to execute command: {cmd:?}\nERROR: {e}")), + }; + + let command = format!("{:?}", cmd); + + move || { + let output = child.wait_with_output().unwrap(); + + if !output.status.success() { + panic!( + "command did not execute successfully: {}\n\ + expected success, got: {}", + command, output.status + ); + } + + String::from_utf8(output.stdout).unwrap() + } +} + /// Returns the last-modified time for `path`, or zero if it doesn't exist. pub fn mtime(path: &Path) -> SystemTime { fs::metadata(path).and_then(|f| f.modified()).unwrap_or(UNIX_EPOCH) From de3cbf3c567e6d81e6ead5c0f646add33df457d1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 3 Sep 2024 18:48:15 +0200 Subject: [PATCH 8/9] make unsupported_calling_conventions a hard error --- .../rustc_hir_analysis/src/check/check.rs | 45 +++++++---------- compiler/rustc_hir_typeck/src/lib.rs | 2 +- compiler/rustc_lint/src/lib.rs | 1 + compiler/rustc_lint_defs/src/builtin.rs | 48 ------------------- compiler/rustc_target/src/spec/mod.rs | 11 ++--- .../missing_const_for_fn/could_be_const.fixed | 8 ++-- .../ui/missing_const_for_fn/could_be_const.rs | 8 ++-- .../could_be_const.stderr | 12 ++--- tests/ui/abi/unsupported.aarch64.stderr | 25 ++++------ tests/ui/abi/unsupported.arm.stderr | 25 ++++------ tests/ui/abi/unsupported.i686.stderr | 8 ++-- tests/ui/abi/unsupported.riscv32.stderr | 25 ++++------ tests/ui/abi/unsupported.riscv64.stderr | 25 ++++------ tests/ui/abi/unsupported.rs | 30 ++++-------- tests/ui/abi/unsupported.x64.stderr | 25 ++++------ 15 files changed, 97 insertions(+), 201 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 94da3d4ea8406..4c383233941d8 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -22,7 +22,7 @@ use rustc_middle::ty::{ AdtDef, GenericArgKind, ParamEnv, RegionKind, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, }; -use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS}; +use rustc_session::lint::builtin::UNINHABITED_STATIC; use rustc_target::abi::FieldIdx; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedDirective; @@ -36,36 +36,25 @@ use super::compare_impl_item::{check_type_bounds, compare_impl_method, compare_i use super::*; use crate::check::intrinsicck::InlineAsmCtxt; -pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) { - match tcx.sess.target.is_abi_supported(abi) { - Some(true) => (), - Some(false) => { - struct_span_code_err!( - tcx.dcx(), - span, - E0570, - "`{abi}` is not a supported ABI for the current target", - ) - .emit(); - } - None => { - tcx.node_span_lint(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| { - lint.primary_message("use of calling convention not supported on this target"); - }); - } +pub fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: Abi) { + if !tcx.sess.target.is_abi_supported(abi) { + struct_span_code_err!( + tcx.dcx(), + span, + E0570, + "`{abi}` is not a supported ABI for the current target", + ) + .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(format!( - "the calling convention {abi} is not supported on this target" - )); - }); - } + if !tcx.sess.target.is_abi_supported(abi) { + tcx.node_span_lint(UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, hir_id, span, |lint| { + lint.primary_message(format!( + "the calling convention {abi} is not supported on this target" + )); + }); } } @@ -705,7 +694,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { let hir::ItemKind::ForeignMod { abi, items } = it.kind else { return; }; - check_abi(tcx, it.hir_id(), it.span, abi); + check_abi(tcx, it.span, abi); match abi { Abi::RustIntrinsic => { diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 9e36f7a9aea8c..85ee0a5cf7dab 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -155,7 +155,7 @@ fn typeck_with_fallback<'tcx>( tcx.fn_sig(def_id).instantiate_identity() }; - check_abi(tcx, id, span, fn_sig.abi()); + check_abi(tcx, span, fn_sig.abi()); // Compute the function signature from point of view of inside the fn. let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig); diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 81352af3d48fa..a7faab0868d82 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -598,6 +598,7 @@ fn register_builtins(store: &mut LintStore) { "converted into hard error, see PR #125380 \ for more information", ); + store.register_removed("unsupported_calling_conventions", "converted into hard error"); } fn register_internals(store: &mut LintStore) { diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 45a5ce0ca20e9..b51d44bd51fa6 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -123,7 +123,6 @@ declare_lint_pass! { UNSAFE_OP_IN_UNSAFE_FN, UNSTABLE_NAME_COLLISIONS, UNSTABLE_SYNTAX_PRE_EXPANSION, - UNSUPPORTED_CALLING_CONVENTIONS, UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, UNUSED_ASSIGNMENTS, UNUSED_ASSOCIATED_TYPE_BOUNDS, @@ -3789,53 +3788,6 @@ declare_lint! { crate_level_only } -declare_lint! { - /// The `unsupported_calling_conventions` lint is output whenever there is a use of the - /// `stdcall`, `fastcall`, `thiscall`, `vectorcall` calling conventions (or their unwind - /// variants) on targets that cannot meaningfully be supported for the requested target. - /// - /// 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. - /// - /// Historically MSVC toolchains have fallen back to the regular C calling convention for - /// targets other than x86, but Rust doesn't really see a similar need to introduce a similar - /// hack across many more targets. - /// - /// ### Example - /// - /// ```rust,ignore (needs specific targets) - /// extern "stdcall" fn stdcall() {} - /// ``` - /// - /// This will produce: - /// - /// ```text - /// warning: use of calling convention not supported on this target - /// --> $DIR/unsupported.rs:39:1 - /// | - /// LL | extern "stdcall" fn stdcall() {} - /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - /// | - /// = note: `#[warn(unsupported_calling_conventions)]` on by default - /// = 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 ... - /// ``` - /// - /// ### 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_CALLING_CONVENTIONS, - Warn, - "use of unsupported calling convention", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, - reference: "issue #87678 ", - }; -} - 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 diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index f4b45a0819525..24f5646a9ea4b 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2757,10 +2757,9 @@ impl Target { } } - /// Returns a None if the UNSUPPORTED_CALLING_CONVENTIONS lint should be emitted - pub fn is_abi_supported(&self, abi: Abi) -> Option { + pub fn is_abi_supported(&self, abi: Abi) -> bool { use Abi::*; - Some(match abi { + match abi { Rust | C { .. } | System { .. } @@ -2819,9 +2818,9 @@ impl Target { // architectures for which these calling conventions are actually well defined. Stdcall { .. } | Fastcall { .. } if self.arch == "x86" => true, Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => true, - // Return a `None` for other cases so that we know to emit a future compat lint. - Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } => return None, - }) + // Reject these calling conventions everywhere else. + Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } => false, + } } /// Minimum integer size in bits that this target can perform atomic diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed index 41b424a8e5d53..f7b6e1a186bbd 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed @@ -1,7 +1,7 @@ #![warn(clippy::missing_const_for_fn)] #![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)] -#![allow(unsupported_calling_conventions)] -#![feature(const_trait_impl)] +#![feature(const_trait_impl, abi_vectorcall)] + use std::mem::transmute; @@ -212,8 +212,8 @@ mod extern_fn { //~^ ERROR: this could be a `const fn` const extern "system-unwind" fn system_unwind() {} //~^ ERROR: this could be a `const fn` - pub const extern "stdcall" fn std_call() {} + pub const extern "vectorcall" fn std_call() {} //~^ ERROR: this could be a `const fn` - pub const extern "stdcall-unwind" fn std_call_unwind() {} + pub const extern "vectorcall-unwind" fn std_call_unwind() {} //~^ ERROR: this could be a `const fn` } diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs index 27593575a013f..4866e3210245e 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs @@ -1,7 +1,7 @@ #![warn(clippy::missing_const_for_fn)] #![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)] -#![allow(unsupported_calling_conventions)] -#![feature(const_trait_impl)] +#![feature(const_trait_impl, abi_vectorcall)] + use std::mem::transmute; @@ -212,8 +212,8 @@ mod extern_fn { //~^ ERROR: this could be a `const fn` extern "system-unwind" fn system_unwind() {} //~^ ERROR: this could be a `const fn` - pub extern "stdcall" fn std_call() {} + pub extern "vectorcall" fn std_call() {} //~^ ERROR: this could be a `const fn` - pub extern "stdcall-unwind" fn std_call_unwind() {} + pub extern "vectorcall-unwind" fn std_call_unwind() {} //~^ ERROR: this could be a `const fn` } diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr index 12d97b1711911..f28dec5c7f195 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -319,23 +319,23 @@ LL | const extern "system-unwind" fn system_unwind() {} error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:215:5 | -LL | pub extern "stdcall" fn std_call() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub extern "vectorcall" fn std_call() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: make the function `const` | -LL | pub const extern "stdcall" fn std_call() {} +LL | pub const extern "vectorcall" fn std_call() {} | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:217:5 | -LL | pub extern "stdcall-unwind" fn std_call_unwind() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub extern "vectorcall-unwind" fn std_call_unwind() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: make the function `const` | -LL | pub const extern "stdcall-unwind" fn std_call_unwind() {} +LL | pub const extern "vectorcall-unwind" fn std_call_unwind() {} | +++++ error: aborting due to 26 previous errors diff --git a/tests/ui/abi/unsupported.aarch64.stderr b/tests/ui/abi/unsupported.aarch64.stderr index 82908ef88a8b7..81aa200012feb 100644 --- a/tests/ui/abi/unsupported.aarch64.stderr +++ b/tests/ui/abi/unsupported.aarch64.stderr @@ -105,7 +105,7 @@ LL | extern "thiscall" {} | ^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:170:19 + --> $DIR/unsupported.rs:165:19 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ @@ -113,18 +113,14 @@ 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 -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:183:1 +error[E0570]: `"stdcall"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:178: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 - = note: `#[warn(unsupported_calling_conventions)]` on by default warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:195:21 + --> $DIR/unsupported.rs:185:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -133,7 +129,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { = note: for more information, see issue #130260 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:203:22 + --> $DIR/unsupported.rs:193:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -142,7 +138,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:208:1 + --> $DIR/unsupported.rs:198:1 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -189,21 +185,18 @@ error[E0570]: `"thiscall"` is not a supported ABI for the current target LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: use of calling convention not supported on this target +error[E0570]: `"stdcall"` is not a supported ABI for the current target --> $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 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:201:1 + --> $DIR/unsupported.rs:191:1 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 16 previous errors; 12 warnings emitted +error: aborting due to 18 previous errors; 10 warnings emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.arm.stderr b/tests/ui/abi/unsupported.arm.stderr index 39ec5d16fcd0d..8e758ee451f53 100644 --- a/tests/ui/abi/unsupported.arm.stderr +++ b/tests/ui/abi/unsupported.arm.stderr @@ -90,7 +90,7 @@ LL | extern "thiscall" {} | ^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:170:19 + --> $DIR/unsupported.rs:165:19 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ @@ -98,18 +98,14 @@ 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 -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:183:1 +error[E0570]: `"stdcall"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:178: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 - = note: `#[warn(unsupported_calling_conventions)]` on by default warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:195:21 + --> $DIR/unsupported.rs:185:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -118,7 +114,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { = note: for more information, see issue #130260 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:203:22 + --> $DIR/unsupported.rs:193:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -127,7 +123,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:208:1 + --> $DIR/unsupported.rs:198:1 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -168,21 +164,18 @@ error[E0570]: `"thiscall"` is not a supported ABI for the current target LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: use of calling convention not supported on this target +error[E0570]: `"stdcall"` is not a supported ABI for the current target --> $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 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:201:1 + --> $DIR/unsupported.rs:191:1 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 14 previous errors; 11 warnings emitted +error: aborting due to 16 previous errors; 9 warnings emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.i686.stderr b/tests/ui/abi/unsupported.i686.stderr index 1dc01a66aabc4..b3c74ad635375 100644 --- a/tests/ui/abi/unsupported.i686.stderr +++ b/tests/ui/abi/unsupported.i686.stderr @@ -75,7 +75,7 @@ LL | extern "riscv-interrupt-m" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:195:21 + --> $DIR/unsupported.rs:185:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -84,7 +84,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { = note: for more information, see issue #130260 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:203:22 + --> $DIR/unsupported.rs:193:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -93,7 +93,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:208:1 + --> $DIR/unsupported.rs:198:1 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -129,7 +129,7 @@ LL | extern "riscv-interrupt-m" fn riscv() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:201:1 + --> $DIR/unsupported.rs:191:1 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/unsupported.riscv32.stderr b/tests/ui/abi/unsupported.riscv32.stderr index e7d5197feebbe..92728b1df18c0 100644 --- a/tests/ui/abi/unsupported.riscv32.stderr +++ b/tests/ui/abi/unsupported.riscv32.stderr @@ -90,7 +90,7 @@ LL | extern "thiscall" {} | ^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:170:19 + --> $DIR/unsupported.rs:165:19 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ @@ -98,18 +98,14 @@ 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 -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:183:1 +error[E0570]: `"stdcall"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:178: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 - = note: `#[warn(unsupported_calling_conventions)]` on by default warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:195:21 + --> $DIR/unsupported.rs:185:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -118,7 +114,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { = note: for more information, see issue #130260 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:203:22 + --> $DIR/unsupported.rs:193:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -127,7 +123,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:208:1 + --> $DIR/unsupported.rs:198:1 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -168,21 +164,18 @@ error[E0570]: `"thiscall"` is not a supported ABI for the current target LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: use of calling convention not supported on this target +error[E0570]: `"stdcall"` is not a supported ABI for the current target --> $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 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:201:1 + --> $DIR/unsupported.rs:191:1 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 14 previous errors; 11 warnings emitted +error: aborting due to 16 previous errors; 9 warnings emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.riscv64.stderr b/tests/ui/abi/unsupported.riscv64.stderr index e7d5197feebbe..92728b1df18c0 100644 --- a/tests/ui/abi/unsupported.riscv64.stderr +++ b/tests/ui/abi/unsupported.riscv64.stderr @@ -90,7 +90,7 @@ LL | extern "thiscall" {} | ^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:170:19 + --> $DIR/unsupported.rs:165:19 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ @@ -98,18 +98,14 @@ 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 -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:183:1 +error[E0570]: `"stdcall"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:178: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 - = note: `#[warn(unsupported_calling_conventions)]` on by default warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:195:21 + --> $DIR/unsupported.rs:185:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -118,7 +114,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { = note: for more information, see issue #130260 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:203:22 + --> $DIR/unsupported.rs:193:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -127,7 +123,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:208:1 + --> $DIR/unsupported.rs:198:1 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -168,21 +164,18 @@ error[E0570]: `"thiscall"` is not a supported ABI for the current target LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: use of calling convention not supported on this target +error[E0570]: `"stdcall"` is not a supported ABI for the current target --> $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 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:201:1 + --> $DIR/unsupported.rs:191:1 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 14 previous errors; 11 warnings emitted +error: aborting due to 16 previous errors; 9 warnings emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.rs b/tests/ui/abi/unsupported.rs index 0eb039269a3ee..a56f001ef9520 100644 --- a/tests/ui/abi/unsupported.rs +++ b/tests/ui/abi/unsupported.rs @@ -157,16 +157,11 @@ extern "thiscall" {} //[riscv64]~^^^^^ ERROR is not a supported ABI extern "stdcall" fn stdcall() {} -//[x64]~^ WARN use of calling convention not supported -//[x64]~^^ WARN this was previously accepted -//[arm]~^^^ WARN use of calling convention not supported -//[arm]~^^^^ WARN this was previously accepted -//[aarch64]~^^^^^ WARN use of calling convention not supported -//[aarch64]~^^^^^^ WARN this was previously accepted -//[riscv32]~^^^^^^^ WARN use of calling convention not supported -//[riscv32]~^^^^^^^^ WARN this was previously accepted -//[riscv64]~^^^^^^^^^ WARN use of calling convention not supported -//[riscv64]~^^^^^^^^^^ WARN this was previously accepted +//[x64]~^ ERROR is not a supported ABI +//[arm]~^^ ERROR is not a supported ABI +//[aarch64]~^^^ ERROR is not a supported ABI +//[riscv32]~^^^^ ERROR is not a supported ABI +//[riscv64]~^^^^^ ERROR is not a supported ABI fn stdcall_ptr(f: extern "stdcall" fn()) { //[x64]~^ WARN unsupported_fn_ptr_calling_conventions //[x64]~^^ WARN this was previously accepted @@ -181,16 +176,11 @@ fn stdcall_ptr(f: extern "stdcall" fn()) { f() } extern "stdcall" {} -//[x64]~^ WARN use of calling convention not supported -//[x64]~^^ WARN this was previously accepted -//[arm]~^^^ WARN use of calling convention not supported -//[arm]~^^^^ WARN this was previously accepted -//[aarch64]~^^^^^ WARN use of calling convention not supported -//[aarch64]~^^^^^^ WARN this was previously accepted -//[riscv32]~^^^^^^^ WARN use of calling convention not supported -//[riscv32]~^^^^^^^^ WARN this was previously accepted -//[riscv64]~^^^^^^^^^ WARN use of calling convention not supported -//[riscv64]~^^^^^^^^^^ WARN this was previously accepted +//[x64]~^ ERROR is not a supported ABI +//[arm]~^^ ERROR is not a supported ABI +//[aarch64]~^^^ ERROR is not a supported ABI +//[riscv32]~^^^^ ERROR is not a supported ABI +//[riscv64]~^^^^^ ERROR is not a supported ABI fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { //~^ WARN unsupported_fn_ptr_calling_conventions diff --git a/tests/ui/abi/unsupported.x64.stderr b/tests/ui/abi/unsupported.x64.stderr index bbca754dd41f4..27a4f1f532c6c 100644 --- a/tests/ui/abi/unsupported.x64.stderr +++ b/tests/ui/abi/unsupported.x64.stderr @@ -90,7 +90,7 @@ LL | extern "thiscall" {} | ^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:170:19 + --> $DIR/unsupported.rs:165:19 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ @@ -98,18 +98,14 @@ 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 -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:183:1 +error[E0570]: `"stdcall"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:178: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 - = note: `#[warn(unsupported_calling_conventions)]` on by default warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:195:21 + --> $DIR/unsupported.rs:185:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -118,7 +114,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { = note: for more information, see issue #130260 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:203:22 + --> $DIR/unsupported.rs:193:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -127,7 +123,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:208:1 + --> $DIR/unsupported.rs:198:1 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -168,21 +164,18 @@ error[E0570]: `"thiscall"` is not a supported ABI for the current target LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: use of calling convention not supported on this target +error[E0570]: `"stdcall"` is not a supported ABI for the current target --> $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 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:201:1 + --> $DIR/unsupported.rs:191:1 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 14 previous errors; 11 warnings emitted +error: aborting due to 16 previous errors; 9 warnings emitted For more information about this error, try `rustc --explain E0570`. From b6e4fca378c4dba62feb51f6a255c7e00f2e9309 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 20 Oct 2024 20:35:18 +0000 Subject: [PATCH 9/9] Represent TraitBoundModifiers as distinct parts in HIR --- compiler/rustc_ast/src/ast.rs | 4 +-- compiler/rustc_ast_lowering/src/lib.rs | 22 +++--------- compiler/rustc_hir/src/hir.rs | 29 +++++++-------- .../src/hir_ty_lowering/bounds.rs | 35 +++++++++---------- .../src/hir_ty_lowering/dyn_compatibility.rs | 3 +- compiler/rustc_hir_pretty/src/lib.rs | 14 +++++--- compiler/rustc_lint/src/traits.rs | 5 +-- compiler/rustc_middle/src/ty/diagnostics.rs | 2 +- .../error_reporting/infer/note_and_explain.rs | 2 +- src/librustdoc/clean/mod.rs | 4 +-- src/librustdoc/clean/types.rs | 19 ++++++---- src/librustdoc/html/format.rs | 14 ++++---- src/librustdoc/json/conversions.rs | 24 ++++++------- .../src/implied_bounds_in_impls.rs | 6 ++-- .../clippy_lints/src/needless_maybe_sized.rs | 6 ++-- .../clippy/clippy_lints/src/trait_bounds.rs | 14 ++++---- .../clippy/clippy_utils/src/hir_utils.rs | 14 +++++++- 17 files changed, 108 insertions(+), 109 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 02cb6f188a718..8e4f4c8e71a2e 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2697,7 +2697,7 @@ impl fmt::Debug for ImplPolarity { } /// The polarity of a trait bound. -#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Hash)] #[derive(HashStable_Generic)] pub enum BoundPolarity { /// `Type: Trait` @@ -2719,7 +2719,7 @@ impl BoundPolarity { } /// The constness of a trait bound. -#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Hash)] #[derive(HashStable_Generic)] pub enum BoundConstness { /// `Type: Trait` diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 4d8d22e09d922..28523bcb3bf7b 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1956,7 +1956,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::GenericBound::Trait(hir::PolyTraitRef { bound_generic_params: &[], - modifiers: hir::TraitBoundModifier::None, + modifiers: hir::TraitBoundModifiers::NONE, trait_ref: hir::TraitRef { path: self.make_lang_item_path(trait_lang_item, opaque_ty_span, Some(bound_args)), hir_ref_id: self.next_id(), @@ -2445,22 +2445,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_trait_bound_modifiers( &mut self, modifiers: TraitBoundModifiers, - ) -> hir::TraitBoundModifier { - // Invalid modifier combinations will cause an error during AST validation. - // Arbitrarily pick a placeholder for them to make compilation proceed. - match (modifiers.constness, modifiers.polarity) { - (BoundConstness::Never, BoundPolarity::Positive) => hir::TraitBoundModifier::None, - (_, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe, - (BoundConstness::Never, BoundPolarity::Negative(_)) => { - if self.tcx.features().negative_bounds { - hir::TraitBoundModifier::Negative - } else { - hir::TraitBoundModifier::None - } - } - (BoundConstness::Always(_), _) => hir::TraitBoundModifier::Const, - (BoundConstness::Maybe(_), _) => hir::TraitBoundModifier::MaybeConst, - } + ) -> hir::TraitBoundModifiers { + hir::TraitBoundModifiers { constness: modifiers.constness, polarity: modifiers.polarity } } // Helper methods for building HIR. @@ -2626,7 +2612,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { Res::Def(DefKind::Trait | DefKind::TraitAlias, _) => { let principal = hir::PolyTraitRef { bound_generic_params: &[], - modifiers: hir::TraitBoundModifier::None, + modifiers: hir::TraitBoundModifiers::NONE, trait_ref: hir::TraitRef { path, hir_ref_id: hir_id }, span: self.lower_span(span), }; diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 009c6c4aea558..45be04c6db9ce 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -6,8 +6,8 @@ use rustc_ast::{ LitKind, TraitObjectSyntax, UintTy, }; pub use rustc_ast::{ - BinOp, BinOpKind, BindingMode, BorrowKind, ByRef, CaptureBy, ImplPolarity, IsAuto, Movability, - Mutability, UnOp, + BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy, + ImplPolarity, IsAuto, Movability, Mutability, UnOp, }; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::sorted_map::SortedMap; @@ -502,19 +502,16 @@ pub enum GenericArgsParentheses { ParenSugar, } -/// A modifier on a trait bound. +/// The modifiers on a trait bound. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] -pub enum TraitBoundModifier { - /// `Type: Trait` - None, - /// `Type: !Trait` - Negative, - /// `Type: ?Trait` - Maybe, - /// `Type: const Trait` - Const, - /// `Type: ~const Trait` - MaybeConst, +pub struct TraitBoundModifiers { + pub constness: BoundConstness, + pub polarity: BoundPolarity, +} + +impl TraitBoundModifiers { + pub const NONE: Self = + TraitBoundModifiers { constness: BoundConstness::Never, polarity: BoundPolarity::Positive }; } #[derive(Clone, Copy, Debug, HashStable_Generic)] @@ -3180,7 +3177,7 @@ pub struct PolyTraitRef<'hir> { /// The constness and polarity of the trait ref. /// /// The `async` modifier is lowered directly into a different trait for now. - pub modifiers: TraitBoundModifier, + pub modifiers: TraitBoundModifiers, /// The `Foo<&'a T>` in `for<'a> Foo<&'a T>`. pub trait_ref: TraitRef<'hir>, @@ -4085,7 +4082,7 @@ mod size_asserts { static_assert_size!(ForeignItem<'_>, 88); static_assert_size!(ForeignItemKind<'_>, 56); static_assert_size!(GenericArg<'_>, 16); - static_assert_size!(GenericBound<'_>, 48); + static_assert_size!(GenericBound<'_>, 64); static_assert_size!(Generics<'_>, 56); static_assert_size!(Impl<'_>, 80); static_assert_size!(ImplItem<'_>, 88); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 4721a3a0cf5ad..a8b2b9b7c0ac3 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -45,23 +45,22 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let hir::GenericBound::Trait(ptr) = hir_bound else { continue; }; - match ptr.modifiers { - hir::TraitBoundModifier::Maybe => unbounds.push(ptr), - hir::TraitBoundModifier::Negative => { + match ptr.modifiers.polarity { + hir::BoundPolarity::Maybe(_) => unbounds.push(ptr), + hir::BoundPolarity::Negative(_) => { if let Some(sized_def_id) = sized_def_id && ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) { seen_negative_sized_bound = true; } } - hir::TraitBoundModifier::None => { + hir::BoundPolarity::Positive => { if let Some(sized_def_id) = sized_def_id && ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) { seen_positive_sized_bound = true; } } - _ => {} } } }; @@ -169,20 +168,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { match hir_bound { hir::GenericBound::Trait(poly_trait_ref) => { - let (constness, polarity) = match poly_trait_ref.modifiers { - hir::TraitBoundModifier::Const => { - (Some(ty::BoundConstness::Const), ty::PredicatePolarity::Positive) - } - hir::TraitBoundModifier::MaybeConst => ( - Some(ty::BoundConstness::ConstIfConst), - ty::PredicatePolarity::Positive, - ), - hir::TraitBoundModifier::None => (None, ty::PredicatePolarity::Positive), - hir::TraitBoundModifier::Negative => { - (None, ty::PredicatePolarity::Negative) - } - hir::TraitBoundModifier::Maybe => continue, + let hir::TraitBoundModifiers { constness, polarity } = poly_trait_ref.modifiers; + // FIXME: We could pass these directly into `lower_poly_trait_ref` + // so that we could use these spans in diagnostics within that function... + let constness = match constness { + hir::BoundConstness::Never => None, + hir::BoundConstness::Always(_) => Some(ty::BoundConstness::Const), + hir::BoundConstness::Maybe(_) => Some(ty::BoundConstness::ConstIfConst), }; + let polarity = match polarity { + rustc_ast::BoundPolarity::Positive => ty::PredicatePolarity::Positive, + rustc_ast::BoundPolarity::Negative(_) => ty::PredicatePolarity::Negative, + rustc_ast::BoundPolarity::Maybe(_) => continue, + }; + let _ = self.lower_poly_trait_ref( &poly_trait_ref.trait_ref, poly_trait_ref.span, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index a1ee120e855fd..d79da03df242f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -40,8 +40,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut potential_assoc_types = Vec::new(); let dummy_self = self.tcx().types.trait_object_dummy_self; for trait_bound in hir_trait_bounds.iter().rev() { - // FIXME: This doesn't handle `? const`. - if trait_bound.modifiers == hir::TraitBoundModifier::Maybe { + if let hir::BoundPolarity::Maybe(_) = trait_bound.modifiers.polarity { continue; } if let GenericArgCountResult { diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 9ebfd4f15abd3..3ba9c76bcee3a 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -16,7 +16,6 @@ use rustc_ast_pretty::pprust::{Comments, PrintState}; use rustc_hir::{ BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind, HirId, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, - TraitBoundModifier, }; use rustc_span::FileName; use rustc_span::source_map::SourceMap; @@ -676,9 +675,16 @@ impl<'a> State<'a> { } fn print_poly_trait_ref(&mut self, t: &hir::PolyTraitRef<'_>) { - // FIXME: This isn't correct! - if t.modifiers == TraitBoundModifier::Maybe { - self.word("?"); + let hir::TraitBoundModifiers { constness, polarity } = t.modifiers; + match constness { + hir::BoundConstness::Never => {} + hir::BoundConstness::Always(_) => self.word("const"), + hir::BoundConstness::Maybe(_) => self.word("~const"), + } + match polarity { + hir::BoundPolarity::Positive => {} + hir::BoundPolarity::Negative(_) => self.word("!"), + hir::BoundPolarity::Maybe(_) => self.word("?"), } self.print_formal_generic_params(t.bound_generic_params); self.print_trait_ref(&t.trait_ref); diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs index 5a3666dcbd432..b793ec6a4939e 100644 --- a/compiler/rustc_lint/src/traits.rs +++ b/compiler/rustc_lint/src/traits.rs @@ -114,10 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { let hir::TyKind::TraitObject(bounds, _lifetime, _syntax) = &ty.kind else { return }; for bound in &bounds[..] { let def_id = bound.trait_ref.trait_def_id(); - if def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::Drop)) - // FIXME: ?Drop is not a thing. - && bound.modifiers != hir::TraitBoundModifier::Maybe - { + if def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::Drop)) { let Some(def_id) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { return }; cx.emit_span_lint(DYN_DROP, bound.span, DropGlue { tcx: cx.tcx, def_id }); } diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 4f408ee157481..8bd2ae9128f7c 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -193,7 +193,7 @@ fn suggest_changing_unsized_bound( .enumerate() .filter(|(_, bound)| { if let hir::GenericBound::Trait(poly) = bound - && poly.modifiers == hir::TraitBoundModifier::Maybe + && let hir::BoundPolarity::Maybe(_) = poly.modifiers.polarity && poly.trait_ref.trait_def_id() == def_id { true diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index 62204f63dd09a..0cf7c43beb541 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -894,7 +894,7 @@ fn foo(&self) -> Self::T { String::new() } // FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting. let trait_bounds = bounds.iter().filter_map(|bound| match bound { - hir::GenericBound::Trait(ptr) if ptr.modifiers == hir::TraitBoundModifier::None => { + hir::GenericBound::Trait(ptr) if ptr.modifiers == hir::TraitBoundModifiers::NONE => { Some(ptr) } _ => None, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7d4d8d8941dcb..848f2abe6a9f0 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -216,7 +216,7 @@ fn clean_generic_bound<'tcx>( hir::GenericBound::Outlives(lt) => GenericBound::Outlives(clean_lifetime(lt, cx)), hir::GenericBound::Trait(ref t) => { // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op. - if t.modifiers == hir::TraitBoundModifier::MaybeConst + if let hir::BoundConstness::Maybe(_) = t.modifiers.constness && cx.tcx.lang_items().destruct_trait() == Some(t.trait_ref.trait_def_id().unwrap()) { return None; @@ -263,7 +263,7 @@ fn clean_poly_trait_ref_with_constraints<'tcx>( trait_: clean_trait_ref_with_constraints(cx, poly_trait_ref, constraints), generic_params: clean_bound_vars(poly_trait_ref.bound_vars()), }, - hir::TraitBoundModifier::None, + hir::TraitBoundModifiers::NONE, ) } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 675507a44c9cc..2e3050eee2fb0 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1257,7 +1257,7 @@ impl Eq for Attributes {} #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub(crate) enum GenericBound { - TraitBound(PolyTrait, hir::TraitBoundModifier), + TraitBound(PolyTrait, hir::TraitBoundModifiers), Outlives(Lifetime), /// `use<'a, T>` precise-capturing bound syntax Use(Vec), @@ -1265,19 +1265,22 @@ pub(crate) enum GenericBound { impl GenericBound { pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound { - Self::sized_with(cx, hir::TraitBoundModifier::None) + Self::sized_with(cx, hir::TraitBoundModifiers::NONE) } pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound { - Self::sized_with(cx, hir::TraitBoundModifier::Maybe) + Self::sized_with(cx, hir::TraitBoundModifiers { + polarity: hir::BoundPolarity::Maybe(DUMMY_SP), + constness: hir::BoundConstness::Never, + }) } - fn sized_with(cx: &mut DocContext<'_>, modifier: hir::TraitBoundModifier) -> GenericBound { + fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound { let did = cx.tcx.require_lang_item(LangItem::Sized, None); let empty = ty::Binder::dummy(ty::GenericArgs::empty()); let path = clean_middle_path(cx, did, false, ThinVec::new(), empty); inline::record_extern_fqn(cx, did, ItemType::Trait); - GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifier) + GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifiers) } pub(crate) fn is_trait_bound(&self) -> bool { @@ -1285,8 +1288,10 @@ impl GenericBound { } pub(crate) fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool { - use rustc_hir::TraitBoundModifier as TBM; - if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self + if let GenericBound::TraitBound( + PolyTrait { ref trait_, .. }, + rustc_hir::TraitBoundModifiers::NONE, + ) = *self && Some(trait_.def_id()) == cx.tcx.lang_items().sized_trait() { return true; diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 2e70a8c080de0..5c599f20f9fdb 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -399,13 +399,13 @@ impl clean::GenericBound { ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match self { clean::GenericBound::Outlives(lt) => write!(f, "{}", lt.print()), - clean::GenericBound::TraitBound(ty, modifier) => { - f.write_str(match modifier { - hir::TraitBoundModifier::None => "", - hir::TraitBoundModifier::Maybe => "?", - hir::TraitBoundModifier::Negative => "!", - // `const` and `~const` trait bounds are experimental; don't render them. - hir::TraitBoundModifier::Const | hir::TraitBoundModifier::MaybeConst => "", + clean::GenericBound::TraitBound(ty, modifiers) => { + // `const` and `~const` trait bounds are experimental; don't render them. + let hir::TraitBoundModifiers { polarity, constness: _ } = modifiers; + f.write_str(match polarity { + hir::BoundPolarity::Positive => "", + hir::BoundPolarity::Maybe(_) => "?", + hir::BoundPolarity::Negative(_) => "!", })?; ty.print(cx).fmt(f) } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 0130f2ce517bf..7270f170780a2 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -552,20 +552,18 @@ impl FromClean for GenericBound { } pub(crate) fn from_trait_bound_modifier( - modifier: rustc_hir::TraitBoundModifier, + modifiers: rustc_hir::TraitBoundModifiers, ) -> TraitBoundModifier { - use rustc_hir::TraitBoundModifier::*; - match modifier { - None => TraitBoundModifier::None, - Maybe => TraitBoundModifier::Maybe, - MaybeConst => TraitBoundModifier::MaybeConst, - // FIXME(const_trait_impl): Create rjt::TBM::Const and map to it once always-const bounds - // are less experimental. - Const => TraitBoundModifier::None, - // FIXME(negative-bounds): This bound should be rendered negative, but - // since that's experimental, maybe let's not add it to the rustdoc json - // API just now... - Negative => TraitBoundModifier::None, + use rustc_hir as hir; + let hir::TraitBoundModifiers { constness, polarity } = modifiers; + match (constness, polarity) { + (hir::BoundConstness::Never, hir::BoundPolarity::Positive) => TraitBoundModifier::None, + (hir::BoundConstness::Never, hir::BoundPolarity::Maybe(_)) => TraitBoundModifier::Maybe, + (hir::BoundConstness::Maybe(_), hir::BoundPolarity::Positive) => { + TraitBoundModifier::MaybeConst + } + // FIXME: Fill out the rest of this matrix. + _ => TraitBoundModifier::None, } } diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs index 00f832372248e..65fdc93e0ed99 100644 --- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs +++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet; use rustc_errors::{Applicability, SuggestionStyle}; use rustc_hir::def_id::DefId; use rustc_hir::{ - AssocItemConstraint, GenericArg, GenericBound, GenericBounds, PredicateOrigin, TraitBoundModifier, TyKind, + AssocItemConstraint, GenericArg, GenericBound, GenericBounds, PredicateOrigin, TraitBoundModifiers, TyKind, WherePredicate, }; use rustc_hir_analysis::lower_ty; @@ -234,7 +234,7 @@ fn collect_supertrait_bounds<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds .iter() .filter_map(|bound| { if let GenericBound::Trait(poly_trait) = bound - && let TraitBoundModifier::None = poly_trait.modifiers + && let TraitBoundModifiers::NONE = poly_trait.modifiers && let [.., path] = poly_trait.trait_ref.path.segments && poly_trait.bound_generic_params.is_empty() && let Some(trait_def_id) = path.res.opt_def_id() @@ -300,7 +300,7 @@ fn check<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds<'tcx>) { // simply comparing trait `DefId`s won't be enough. We also need to compare the generics. for (index, bound) in bounds.iter().enumerate() { if let GenericBound::Trait(poly_trait) = bound - && let TraitBoundModifier::None = poly_trait.modifiers + && let TraitBoundModifiers::NONE = poly_trait.modifiers && let [.., path] = poly_trait.trait_ref.path.segments && let implied_args = path.args.map_or([].as_slice(), |a| a.args) && let implied_constraints = path.args.map_or([].as_slice(), |a| a.constraints) diff --git a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs index 68c9af07465d3..9a1c397b5b237 100644 --- a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs +++ b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_errors::Applicability; use rustc_hir::def_id::{DefId, DefIdMap}; -use rustc_hir::{GenericBound, Generics, PolyTraitRef, TraitBoundModifier, WherePredicate}; +use rustc_hir::{GenericBound, Generics, PolyTraitRef, TraitBoundModifiers, BoundPolarity, WherePredicate}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{ClauseKind, PredicatePolarity}; use rustc_session::declare_lint_pass; @@ -118,13 +118,13 @@ impl LateLintPass<'_> for NeedlessMaybeSized { let maybe_sized_params: DefIdMap<_> = type_param_bounds(generics) .filter(|bound| { bound.trait_bound.trait_ref.trait_def_id() == Some(sized_trait) - && bound.trait_bound.modifiers == TraitBoundModifier::Maybe + && matches!(bound.trait_bound.modifiers.polarity, BoundPolarity::Maybe(_)) }) .map(|bound| (bound.param, bound)) .collect(); for bound in type_param_bounds(generics) { - if bound.trait_bound.modifiers == TraitBoundModifier::None + if bound.trait_bound.modifiers == TraitBoundModifiers::NONE && let Some(sized_bound) = maybe_sized_params.get(&bound.param) && let Some(path) = path_to_sized_bound(cx, bound.trait_bound) { diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index 7f528b9d17b80..3da4bf67558dd 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -11,7 +11,7 @@ use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{ GenericBound, Generics, Item, ItemKind, LangItem, Node, Path, PathSegment, PredicateOrigin, QPath, - TraitBoundModifier, TraitItem, TraitRef, Ty, TyKind, WherePredicate, + TraitBoundModifiers, TraitItem, TraitRef, Ty, TyKind, WherePredicate, BoundPolarity, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -233,7 +233,7 @@ impl TraitBounds { fn cannot_combine_maybe_bound(&self, cx: &LateContext<'_>, bound: &GenericBound<'_>) -> bool { if !self.msrv.meets(msrvs::MAYBE_BOUND_IN_WHERE) && let GenericBound::Trait(tr) = bound - && let TraitBoundModifier::Maybe = tr.modifiers + && let BoundPolarity::Maybe(_) = tr.modifiers.polarity { cx.tcx.lang_items().get(LangItem::Sized) == tr.trait_ref.path.res.opt_def_id() } else { @@ -374,12 +374,12 @@ fn check_trait_bound_duplication<'tcx>(cx: &LateContext<'tcx>, generics: &'_ Gen struct ComparableTraitRef<'a, 'tcx> { cx: &'a LateContext<'tcx>, trait_ref: &'tcx TraitRef<'tcx>, - modifier: TraitBoundModifier, + modifiers: TraitBoundModifiers, } impl PartialEq for ComparableTraitRef<'_, '_> { fn eq(&self, other: &Self) -> bool { - self.modifier == other.modifier + SpanlessEq::new(self.cx).eq_modifiers(self.modifiers, other.modifiers) && SpanlessEq::new(self.cx) .paths_by_resolution() .eq_path(self.trait_ref.path, other.trait_ref.path) @@ -390,8 +390,8 @@ impl Hash for ComparableTraitRef<'_, '_> { fn hash(&self, state: &mut H) { let mut s = SpanlessHash::new(self.cx).paths_by_resolution(); s.hash_path(self.trait_ref.path); + s.hash_modifiers(self.modifiers); state.write_u64(s.finish()); - self.modifier.hash(state); } } @@ -400,7 +400,7 @@ fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &' let trait_path = t.trait_ref.path; let trait_span = { let path_span = trait_path.span; - if let TraitBoundModifier::Maybe = t.modifiers { + if let BoundPolarity::Maybe(_) = t.modifiers.polarity { path_span.with_lo(path_span.lo() - BytePos(1)) // include the `?` } else { path_span @@ -427,7 +427,7 @@ fn rollup_traits<'cx, 'tcx>( ComparableTraitRef { cx, trait_ref: &t.trait_ref, - modifier: t.modifiers, + modifiers: t.modifiers, }, t.span, )) diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 27c57808ecea8..181d414cbbded 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -9,7 +9,8 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{ ArrayLen, AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, - LifetimeName, Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind, + LifetimeName, Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitBoundModifiers, Ty, + TyKind, }; use rustc_lexer::{TokenKind, tokenize}; use rustc_lint::LateContext; @@ -126,6 +127,11 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { pub fn eq_path_segments(&mut self, left: &[PathSegment<'_>], right: &[PathSegment<'_>]) -> bool { self.inter_expr().eq_path_segments(left, right) } + + pub fn eq_modifiers(&mut self, left: TraitBoundModifiers, right: TraitBoundModifiers) -> bool { + std::mem::discriminant(&left.constness) == std::mem::discriminant(&right.constness) + && std::mem::discriminant(&left.polarity) == std::mem::discriminant(&right.polarity) + } } pub struct HirEqInterExpr<'a, 'b, 'tcx> { @@ -1143,6 +1149,12 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } } + pub fn hash_modifiers(&mut self, modifiers: TraitBoundModifiers) { + let TraitBoundModifiers { constness, polarity } = modifiers; + std::mem::discriminant(&polarity).hash(&mut self.s); + std::mem::discriminant(&constness).hash(&mut self.s); + } + pub fn hash_stmt(&mut self, b: &Stmt<'_>) { std::mem::discriminant(&b.kind).hash(&mut self.s);