From 45dcd90c86d9a502450eeb043f104dbf27293ac3 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 30 Nov 2024 17:45:55 -0800 Subject: [PATCH] Distinguish lowered-to-MIR intrinsics from handled-by-backend intrinsics "Must be overridden" is misleading for things that a backend actually shouldn't override since they'll never see them. --- .../src/intrinsics/mod.rs | 5 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 5 +- .../src/check_consts/check.rs | 2 +- .../src/const_eval/machine.rs | 2 +- .../rustc_const_eval/src/interpret/call.rs | 2 +- compiler/rustc_feature/src/builtin_attrs.rs | 4 + compiler/rustc_middle/src/ty/intrinsic.rs | 28 ++++++- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/util.rs | 19 +++-- compiler/rustc_mir_build/src/build/mod.rs | 2 +- .../src/lower_intrinsics.rs | 11 ++- compiler/rustc_smir/src/rustc_smir/mod.rs | 2 +- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/intrinsics/mod.rs | 84 +++++++++++++------ src/tools/miri/src/intrinsics/mod.rs | 2 +- ...are_char.LowerIntrinsics.panic-unwind.diff | 2 +- ...e_signed.LowerIntrinsics.panic-unwind.diff | 2 +- ...unsigned.LowerIntrinsics.panic-unwind.diff | 2 +- .../intrinsics/both-lowered-and-overridden.rs | 19 +++++ .../both-lowered-and-overridden.stderr | 8 ++ tests/ui/intrinsics/not-lowered-in-mir.rs | 18 ++++ tests/ui/intrinsics/not-lowered-in-mir.stderr | 12 +++ tests/ui/intrinsics/not-overridden.rs | 4 +- tests/ui/intrinsics/not-overridden.stderr | 2 +- 24 files changed, 188 insertions(+), 52 deletions(-) create mode 100644 tests/ui/intrinsics/both-lowered-and-overridden.rs create mode 100644 tests/ui/intrinsics/both-lowered-and-overridden.stderr create mode 100644 tests/ui/intrinsics/not-lowered-in-mir.rs create mode 100644 tests/ui/intrinsics/not-lowered-in-mir.stderr diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 3318c0797ec34..ba3bf560f9603 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -1278,11 +1278,12 @@ fn codegen_regular_intrinsic_call<'tcx>( // by converting the `InstanceKind::Intrinsic` to an `InstanceKind::Item`. _ => { let intrinsic = fx.tcx.intrinsic(instance.def_id()).unwrap(); - if intrinsic.must_be_overridden { + if !intrinsic.has_fallback() { span_bug!( source_info.span, - "intrinsic {} must be overridden by codegen_cranelift, but isn't", + "intrinsic {} ({:?}) must be overridden by codegen_cranelift, but isn't", intrinsic.name, + intrinsic.kind, ); } return Err(Instance::new(instance.def_id(), instance.args)); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index e3ed12b5ce61c..4a43267d0f03b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -952,11 +952,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; } Err(instance) => { - if intrinsic.must_be_overridden { + if !intrinsic.has_fallback() { span_bug!( span, - "intrinsic {} must be overridden by codegen backend, but isn't", + "intrinsic {} ({:?}) got to the codegen backend, but wasn't overridden", intrinsic.name, + intrinsic.kind, ); } Some(instance) diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 916929b6c0bb9..7f11ec6134b0b 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -766,7 +766,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // We also ask is_safe_to_expose_on_stable_const_fn; this determines whether the intrinsic // fallback body is safe to expose on stable. let is_const_stable = intrinsic.const_stable - || (!intrinsic.must_be_overridden + || (intrinsic.has_fallback() && is_safe_to_expose_on_stable_const_fn(tcx, callee)); match tcx.lookup_const_stability(callee) { None => { diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index b27e3606f381a..4f982725f41b2 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -466,7 +466,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { sym::is_val_statically_known => ecx.write_scalar(Scalar::from_bool(false), dest)?, _ => { // We haven't handled the intrinsic, let's see if we can use a fallback body. - if ecx.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden { + if !ecx.tcx.intrinsic(instance.def_id()).unwrap().has_fallback() { throw_unsup_format!( "intrinsic `{intrinsic_name}` is not supported at compile-time" ); diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index ed4a1a9e6478b..3b498cc48fcb4 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -540,7 +540,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { target, unwind, )? { - assert!(!self.tcx.intrinsic(fallback.def_id()).unwrap().must_be_overridden); + assert!(self.tcx.intrinsic(fallback.def_id()).unwrap().has_fallback()); assert_matches!(fallback.def, ty::InstanceKind::Item(_)); return self.init_fn_call( FnVal::Instance(fallback), diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index fd08b35d24297..203f2534b8e14 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1010,6 +1010,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_intrinsic_must_be_overridden, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, intrinsics, "the `#[rustc_intrinsic_must_be_overridden]` attribute is used to declare intrinsics without real bodies", ), + gated!( + rustc_intrinsic_lowers_to_mir, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, intrinsics, + "the `#[rustc_intrinsic_lowers_to_mir]` attribute is used to declare intrinsics translated by `LowerIntrinsics`", + ), rustc_attr!( rustc_no_mir_inline, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, "#[rustc_no_mir_inline] prevents the MIR inliner from inlining a function while not affecting codegen" diff --git a/compiler/rustc_middle/src/ty/intrinsic.rs b/compiler/rustc_middle/src/ty/intrinsic.rs index 6a3ddacb424e8..051b4c163e57f 100644 --- a/compiler/rustc_middle/src/ty/intrinsic.rs +++ b/compiler/rustc_middle/src/ty/intrinsic.rs @@ -4,15 +4,39 @@ use rustc_span::def_id::DefId; use super::TyCtxt; +#[derive(Copy, Clone, Debug, Eq, PartialEq, Decodable, Encodable, HashStable)] +pub enum IntrinsicKind { + /// The intrinsic has no meaningful body and all backends need to shim all calls to it. + MustBeOverridden, + /// The intrinsic lowers to MIR, so does not need to be considered by backends. + LowersToMir, + /// The intrinsic has a meaningful body usable by backends that don't need something special. + HasFallback, +} + #[derive(Copy, Clone, Debug, Decodable, Encodable, HashStable)] pub struct IntrinsicDef { pub name: Symbol, - /// Whether the intrinsic has no meaningful body and all backends need to shim all calls to it. - pub must_be_overridden: bool, + /// Describes how the intrinsic is expected to be handled, based on its definition. + pub kind: IntrinsicKind, /// Whether the intrinsic can be invoked from stable const fn pub const_stable: bool, } +impl IntrinsicDef { + pub fn must_be_overridden(self) -> bool { + self.kind == IntrinsicKind::MustBeOverridden + } + + pub fn has_fallback(self) -> bool { + self.kind == IntrinsicKind::HasFallback + } + + pub fn lowers_to_mir(self) -> bool { + self.kind == IntrinsicKind::LowersToMir + } +} + impl TyCtxt<'_> { pub fn is_intrinsic(self, def_id: DefId, name: Symbol) -> bool { let Some(i) = self.intrinsic(def_id) else { return false }; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index c7a2223ecd78b..38aec018e770b 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -23,7 +23,7 @@ pub use adt::*; pub use assoc::*; pub use generic_args::{GenericArgKind, TermKind, *}; pub use generics::*; -pub use intrinsic::IntrinsicDef; +pub use intrinsic::{IntrinsicDef, IntrinsicKind}; use rustc_abi::{Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, VariantIdx}; use rustc_ast::expand::StrippedCfgItem; use rustc_ast::node_id::NodeMap; diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 797ac9685b1e0..4919f3d780b7c 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1760,11 +1760,20 @@ pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option ty::IntrinsicKind::HasFallback, + (true, false) => ty::IntrinsicKind::MustBeOverridden, + (false, true) => ty::IntrinsicKind::LowersToMir, + (true, true) => bug!( + "intrinsic {name} should be marked with at most one of \ + rustc_intrinsic_must_be_overridden and rustc_intrinsic_lowers_to_mir", + ), + }; + Some(ty::IntrinsicDef { name, kind, const_stable }) } else { None } diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 3317f3b7f8acb..ab3181a88d18e 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -997,7 +997,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let Some(source_scope) = scope { self.source_scope = source_scope; } - if self.tcx.intrinsic(self.def_id).is_some_and(|i| i.must_be_overridden) { + if self.tcx.intrinsic(self.def_id).is_some_and(|i| !i.has_fallback()) { let source_info = self.source_info(rustc_span::DUMMY_SP); self.cfg.terminate(block, source_info, TerminatorKind::Unreachable); self.cfg.start_new_block().unit() diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index 6d635606687a9..0b2c47dd30968 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -320,7 +320,16 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { }); terminator.kind = TerminatorKind::Goto { target }; } - _ => {} + _ => { + if intrinsic.lowers_to_mir() { + span_bug!( + terminator.source_info.span, + "Intrinsic {} was marked as #[rustc_intrinsic_lowers_to_mir] \ + but wasn't lowered by `LowerIntrinsics` pass", + intrinsic.name, + ); + } + } } } } diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index c5d33f090a05b..99e555fa635e3 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -73,7 +73,7 @@ impl<'tcx> Tables<'tcx> { /// In StableMIR, we handle this case as if the body is not available. pub(crate) fn item_has_body(&self, def_id: DefId) -> bool { let must_override = if let Some(intrinsic) = self.tcx.intrinsic(def_id) { - intrinsic.must_be_overridden + intrinsic.must_be_overridden() } else { false }; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 3a07c283e0ebb..ec04a2c0cf2d2 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1702,6 +1702,7 @@ symbols! { rustc_insignificant_dtor, rustc_intrinsic, rustc_intrinsic_const_stable_indirect, + rustc_intrinsic_lowers_to_mir, rustc_intrinsic_must_be_overridden, rustc_layout, rustc_layout_scalar_valid_range_end, diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 6b9011adf3d3d..520eb54efbc65 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -1434,7 +1434,8 @@ pub fn abort() -> ! { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const unsafe fn unreachable() -> ! { unreachable!() } @@ -1453,6 +1454,7 @@ pub const unsafe fn unreachable() -> ! { #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const unsafe fn assume(b: bool) { if !b { // SAFETY: the caller must guarantee the argument is never `false` @@ -1605,7 +1607,8 @@ pub const fn caller_location() -> &'static crate::panic::Location<'static> { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const fn forget(_: T) { unreachable!() } @@ -1901,7 +1904,8 @@ pub const fn forget(_: T) { #[rustc_diagnostic_item = "transmute"] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const unsafe fn transmute(_src: Src) -> Dst { unreachable!() } @@ -1918,7 +1922,8 @@ pub const unsafe fn transmute(_src: Src) -> Dst { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const unsafe fn transmute_unchecked(_src: Src) -> Dst { unreachable!() } @@ -1964,7 +1969,8 @@ pub const fn needs_drop() -> bool { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const unsafe fn offset(_dst: Ptr, _offset: Delta) -> Ptr { unreachable!() } @@ -2879,8 +2885,10 @@ pub const fn bitreverse(_x: T) -> T { /// large and difficult to optimize. /// /// The stabilized version of this intrinsic is [`Ord::cmp`]. +#[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const fn three_way_compare(_lhs: T, _rhss: T) -> crate::cmp::Ordering { unimplemented!() } @@ -2898,7 +2906,8 @@ pub const fn three_way_compare(_lhs: T, _rhss: T) -> crate::cmp::Orderi #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const fn add_with_overflow(_x: T, _y: T) -> (T, bool) { unimplemented!() } @@ -2916,7 +2925,8 @@ pub const fn add_with_overflow(_x: T, _y: T) -> (T, bool) { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const fn sub_with_overflow(_x: T, _y: T) -> (T, bool) { unimplemented!() } @@ -2934,7 +2944,8 @@ pub const fn sub_with_overflow(_x: T, _y: T) -> (T, bool) { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const fn mul_with_overflow(_x: T, _y: T) -> (T, bool) { unimplemented!() } @@ -2959,7 +2970,8 @@ pub const unsafe fn exact_div(_x: T, _y: T) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const unsafe fn unchecked_div(_x: T, _y: T) -> T { unimplemented!() } @@ -2972,7 +2984,8 @@ pub const unsafe fn unchecked_div(_x: T, _y: T) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const unsafe fn unchecked_rem(_x: T, _y: T) -> T { unimplemented!() } @@ -2986,7 +2999,8 @@ pub const unsafe fn unchecked_rem(_x: T, _y: T) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const unsafe fn unchecked_shl(_x: T, _y: U) -> T { unimplemented!() } @@ -2999,7 +3013,8 @@ pub const unsafe fn unchecked_shl(_x: T, _y: U) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const unsafe fn unchecked_shr(_x: T, _y: U) -> T { unimplemented!() } @@ -3012,7 +3027,8 @@ pub const unsafe fn unchecked_shr(_x: T, _y: U) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const unsafe fn unchecked_add(_x: T, _y: T) -> T { unimplemented!() } @@ -3025,7 +3041,8 @@ pub const unsafe fn unchecked_add(_x: T, _y: T) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const unsafe fn unchecked_sub(_x: T, _y: T) -> T { unimplemented!() } @@ -3038,7 +3055,8 @@ pub const unsafe fn unchecked_sub(_x: T, _y: T) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const unsafe fn unchecked_mul(_x: T, _y: T) -> T { unimplemented!() } @@ -3092,7 +3110,8 @@ pub const fn rotate_right(_x: T, _shift: u32) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const fn wrapping_add(_a: T, _b: T) -> T { unimplemented!() } @@ -3109,7 +3128,8 @@ pub const fn wrapping_add(_a: T, _b: T) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const fn wrapping_sub(_a: T, _b: T) -> T { unimplemented!() } @@ -3126,7 +3146,8 @@ pub const fn wrapping_sub(_a: T, _b: T) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const fn wrapping_mul(_a: T, _b: T) -> T { unimplemented!() } @@ -3175,7 +3196,8 @@ pub const fn saturating_sub(_a: T, _b: T) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const unsafe fn read_via_copy(_ptr: *const T) -> T { unimplemented!() } @@ -3189,7 +3211,8 @@ pub const unsafe fn read_via_copy(_ptr: *const T) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const unsafe fn write_via_move(_ptr: *mut T, _value: T) { unimplemented!() } @@ -3206,7 +3229,8 @@ pub const unsafe fn write_via_move(_ptr: *mut T, _value: T) { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const fn discriminant_value(_v: &T) -> ::Discriminant { unimplemented!() } @@ -3601,6 +3625,7 @@ pub const unsafe fn typed_swap(x: *mut T, y: *mut T) { #[rustc_intrinsic_const_stable_indirect] // just for UB checks #[inline(always)] #[rustc_intrinsic] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const fn ub_checks() -> bool { cfg!(ub_checks) } @@ -3683,7 +3708,8 @@ pub unsafe fn vtable_align(_ptr: *const ()) -> usize { #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const fn size_of() -> usize { unreachable!() } @@ -3700,7 +3726,8 @@ pub const fn size_of() -> usize { #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const fn min_align_of() -> usize { unreachable!() } @@ -3807,7 +3834,8 @@ pub const fn type_id() -> u128 { #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const fn aggregate_raw_ptr, D, M>(_data: D, _meta: M) -> P { // To implement a fallback we'd have to assume the layout of the pointer, // but the whole point of this intrinsic is that we shouldn't do that. @@ -3832,7 +3860,8 @@ impl AggregateRawPtr<*mut T> for *mut P { #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] +#[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] pub const fn ptr_metadata + ?Sized, M>(_ptr: *const P) -> M { // To implement a fallback we'd have to assume the layout of the pointer, // but the whole point of this intrinsic is that we shouldn't do that. @@ -3939,7 +3968,8 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] + #[cfg_attr(bootstrap, rustc_intrinsic_must_be_overridden)] + #[cfg_attr(not(bootstrap), rustc_intrinsic_lowers_to_mir)] const unsafe fn copy_nonoverlapping(_src: *const T, _dst: *mut T, _count: usize) { unreachable!() } diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 9eebbc5d3631e..411eb554c2f48 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -37,7 +37,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match this.emulate_intrinsic_by_name(intrinsic_name, instance.args, args, dest, ret)? { EmulateItemResult::NotSupported => { // We haven't handled the intrinsic, let's see if we can use a fallback body. - if this.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden { + if !this.tcx.intrinsic(instance.def_id()).unwrap().has_fallback() { throw_unsup_format!("unimplemented intrinsic: `{intrinsic_name}`") } let intrinsic_fallback_is_spec = Symbol::intern("intrinsic_fallback_is_spec"); diff --git a/tests/mir-opt/lower_intrinsics.three_way_compare_char.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.three_way_compare_char.LowerIntrinsics.panic-unwind.diff index 596ad70b3bfad..f29bc5dfc6e4f 100644 --- a/tests/mir-opt/lower_intrinsics.three_way_compare_char.LowerIntrinsics.panic-unwind.diff +++ b/tests/mir-opt/lower_intrinsics.three_way_compare_char.LowerIntrinsics.panic-unwind.diff @@ -18,7 +18,7 @@ _4 = copy _1; StorageLive(_5); _5 = copy _2; -- _3 = three_way_compare::(move _4, move _5) -> [return: bb1, unwind continue]; +- _3 = three_way_compare::(move _4, move _5) -> [return: bb1, unwind unreachable]; + _3 = Cmp(move _4, move _5); + goto -> bb1; } diff --git a/tests/mir-opt/lower_intrinsics.three_way_compare_signed.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.three_way_compare_signed.LowerIntrinsics.panic-unwind.diff index 987c216669271..654cb2503df58 100644 --- a/tests/mir-opt/lower_intrinsics.three_way_compare_signed.LowerIntrinsics.panic-unwind.diff +++ b/tests/mir-opt/lower_intrinsics.three_way_compare_signed.LowerIntrinsics.panic-unwind.diff @@ -15,7 +15,7 @@ _4 = copy _1; StorageLive(_5); _5 = copy _2; -- _3 = three_way_compare::(move _4, move _5) -> [return: bb1, unwind continue]; +- _3 = three_way_compare::(move _4, move _5) -> [return: bb1, unwind unreachable]; + _3 = Cmp(move _4, move _5); + goto -> bb1; } diff --git a/tests/mir-opt/lower_intrinsics.three_way_compare_unsigned.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.three_way_compare_unsigned.LowerIntrinsics.panic-unwind.diff index d7ec6dcfa2c3c..82c89b7ce549c 100644 --- a/tests/mir-opt/lower_intrinsics.three_way_compare_unsigned.LowerIntrinsics.panic-unwind.diff +++ b/tests/mir-opt/lower_intrinsics.three_way_compare_unsigned.LowerIntrinsics.panic-unwind.diff @@ -18,7 +18,7 @@ _4 = copy _1; StorageLive(_5); _5 = copy _2; -- _3 = three_way_compare::(move _4, move _5) -> [return: bb1, unwind continue]; +- _3 = three_way_compare::(move _4, move _5) -> [return: bb1, unwind unreachable]; + _3 = Cmp(move _4, move _5); + goto -> bb1; } diff --git a/tests/ui/intrinsics/both-lowered-and-overridden.rs b/tests/ui/intrinsics/both-lowered-and-overridden.rs new file mode 100644 index 0000000000000..33858b55241e8 --- /dev/null +++ b/tests/ui/intrinsics/both-lowered-and-overridden.rs @@ -0,0 +1,19 @@ +//! Check that intrinsics that do not get overridden, but are marked as such, +//! cause an error instead of silently invoking the body. +#![feature(intrinsics)] +//@ check-fail +//@ failure-status:101 +//@ normalize-stderr-test: ".*note: .*\n\n" -> "" +//@ normalize-stderr-test: "thread 'rustc' panicked.*:\n.*\n" -> "" +//@ normalize-stderr-test: "internal compiler error:.*: " -> "" +//@ error-pattern: intrinsic const_deallocate should be marked with at most one of rustc_intrinsic_must_be_overridden and rustc_intrinsic_lowers_to_mir +//@ rustc-env:RUST_BACKTRACE=0 + +#[rustc_intrinsic] +#[rustc_intrinsic_lowers_to_mir] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} + +fn main() { + unsafe { const_deallocate(std::ptr::null_mut(), 0, 0) } +} diff --git a/tests/ui/intrinsics/both-lowered-and-overridden.stderr b/tests/ui/intrinsics/both-lowered-and-overridden.stderr new file mode 100644 index 0000000000000..426fb6822a5e4 --- /dev/null +++ b/tests/ui/intrinsics/both-lowered-and-overridden.stderr @@ -0,0 +1,8 @@ +error: intrinsic const_deallocate should be marked with at most one of rustc_intrinsic_must_be_overridden and rustc_intrinsic_lowers_to_mir + +query stack during panic: +#0 [intrinsic_raw] fetch intrinsic name if `const_deallocate` is an intrinsic +#1 [check_well_formed] checking that `const_deallocate` is well-formed +end of query stack +error: aborting due to 1 previous error + diff --git a/tests/ui/intrinsics/not-lowered-in-mir.rs b/tests/ui/intrinsics/not-lowered-in-mir.rs new file mode 100644 index 0000000000000..8129bcf2d1a74 --- /dev/null +++ b/tests/ui/intrinsics/not-lowered-in-mir.rs @@ -0,0 +1,18 @@ +//! Check that intrinsics that do not get lowered to MIR, but are marked as such, +//! cause an error instead of silently invoking the body. +#![feature(intrinsics)] +//@ build-fail +//@ failure-status:101 +//@ normalize-stderr-test: ".*note: .*\n\n" -> "" +//@ normalize-stderr-test: "thread 'rustc' panicked.*:\n.*\n" -> "" +//@ normalize-stderr-test: "internal compiler error:.*: " -> "" +//@ rustc-env:RUST_BACKTRACE=0 + +#[rustc_intrinsic] +#[rustc_intrinsic_lowers_to_mir] +pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} + +fn main() { + unsafe { const_deallocate(std::ptr::null_mut(), 0, 0) } + //~^ ERROR: Intrinsic const_deallocate was marked as #[rustc_intrinsic_lowers_to_mir] but wasn't lowered by `LowerIntrinsics` pass +} diff --git a/tests/ui/intrinsics/not-lowered-in-mir.stderr b/tests/ui/intrinsics/not-lowered-in-mir.stderr new file mode 100644 index 0000000000000..b0d691a8ef4b3 --- /dev/null +++ b/tests/ui/intrinsics/not-lowered-in-mir.stderr @@ -0,0 +1,12 @@ +error: Intrinsic const_deallocate was marked as #[rustc_intrinsic_lowers_to_mir] but wasn't lowered by `LowerIntrinsics` pass + --> $DIR/not-lowered-in-mir.rs:16:14 + | +LL | unsafe { const_deallocate(std::ptr::null_mut(), 0, 0) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +query stack during panic: +#0 [mir_drops_elaborated_and_const_checked] elaborating drops for `main` +#1 [analysis] running analysis passes on this crate +end of query stack +error: aborting due to 1 previous error + diff --git a/tests/ui/intrinsics/not-overridden.rs b/tests/ui/intrinsics/not-overridden.rs index 16f8e9bcf6a73..1834369cd4557 100644 --- a/tests/ui/intrinsics/not-overridden.rs +++ b/tests/ui/intrinsics/not-overridden.rs @@ -5,7 +5,7 @@ //@ failure-status:101 //@ normalize-stderr-test: ".*note: .*\n\n" -> "" //@ normalize-stderr-test: "thread 'rustc' panicked.*:\n.*\n" -> "" -//@ normalize-stderr-test: "internal compiler error:.*: intrinsic const_deallocate " -> "" +//@ normalize-stderr-test: "internal compiler error:.*: " -> "" //@ rustc-env:RUST_BACKTRACE=0 #[rustc_intrinsic] @@ -14,5 +14,5 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) fn main() { unsafe { const_deallocate(std::ptr::null_mut(), 0, 0) } - //~^ ERROR: must be overridden + //~^ ERROR: intrinsic const_deallocate (MustBeOverridden) got to the codegen backend, but wasn't overridden } diff --git a/tests/ui/intrinsics/not-overridden.stderr b/tests/ui/intrinsics/not-overridden.stderr index 9b8849cea1ced..23da36e9ae4f9 100644 --- a/tests/ui/intrinsics/not-overridden.stderr +++ b/tests/ui/intrinsics/not-overridden.stderr @@ -1,4 +1,4 @@ -error: must be overridden by codegen backend, but isn't +error: intrinsic const_deallocate (MustBeOverridden) got to the codegen backend, but wasn't overridden --> $DIR/not-overridden.rs:16:14 | LL | unsafe { const_deallocate(std::ptr::null_mut(), 0, 0) }