diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index c802d9bbefbed..25694af78f17e 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -757,13 +757,6 @@ fn codegen_regular_intrinsic_call<'tcx>( ret.write_cvalue(fx, val); } - sym::ptr_guaranteed_cmp => { - intrinsic_args!(fx, args => (a, b); intrinsic); - - let val = crate::num::codegen_ptr_binop(fx, BinOp::Eq, a, b).load_scalar(fx); - ret.write_cvalue(fx, CValue::by_val(val, fx.layout_of(fx.tcx.types.u8))); - } - sym::caller_location => { intrinsic_args!(fx, args => (); intrinsic); diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 87b6f0e914c35..b19f52182b650 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -81,10 +81,6 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap {} diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index ba023f96107a4..5532ff6e6a5d7 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -1,7 +1,6 @@ use super::operand::{OperandRef, OperandValue}; use super::place::PlaceRef; use super::FunctionCx; -use crate::common::IntPredicate; use crate::errors; use crate::errors::InvalidMonomorphization; use crate::meth; @@ -456,12 +455,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return Ok(()); } - sym::ptr_guaranteed_cmp => { - let a = args[0].immediate(); - let b = args[1].immediate(); - bx.icmp(IntPredicate::IntEQ, a, b) - } - sym::ptr_offset_from | sym::ptr_offset_from_unsigned => { let ty = fn_args.type_at(0); let pointee_size = bx.layout_of(ty).size; diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 35755a46df3a4..07054c184f401 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -441,7 +441,7 @@ pub fn check_intrinsic_type( sym::ptr_guaranteed_cmp => ( 1, - 0, + 1, vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))], tcx.types.u8, ), @@ -579,7 +579,7 @@ pub fn check_intrinsic_type( sym::is_val_statically_known => (1, 1, vec![param(0)], tcx.types.bool), - sym::const_eval_select => (4, 0, vec![param(0), param(1), param(2)], param(3)), + sym::const_eval_select => (4, 1, vec![param(0), param(1), param(2)], param(3)), sym::vtable_size | sym::vtable_align => { (0, 0, vec![Ty::new_imm_ptr(tcx, Ty::new_unit(tcx))], tcx.types.usize) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index d8cfceab460a0..0a9659745dbf4 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1067,14 +1067,11 @@ fn should_encode_mir( // Full-fledged functions + closures DefKind::AssocFn | DefKind::Fn | DefKind::Closure => { let generics = tcx.generics_of(def_id); - let mut opt = tcx.sess.opts.unstable_opts.always_encode_mir + let opt = tcx.sess.opts.unstable_opts.always_encode_mir || (tcx.sess.opts.output_types.should_codegen() && reachable_set.contains(&def_id) && (generics.requires_monomorphization(tcx) || tcx.cross_crate_inlinable(def_id))); - if let Some(intrinsic) = tcx.intrinsic(def_id) { - opt &= !intrinsic.must_be_overridden; - } // The function has a `const` modifier or is in a `#[const_trait]`. let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id()) || tcx.is_const_default_method(def_id.to_def_id()); diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index e47668b9110ff..d910a15e26202 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -31,6 +31,7 @@ #![feature(array_windows)] #![feature(assert_matches)] #![feature(box_patterns)] +#![feature(closure_track_caller)] #![feature(core_intrinsics)] #![feature(const_type_name)] #![feature(discriminant_kind)] diff --git a/compiler/rustc_middle/src/ty/context/tls.rs b/compiler/rustc_middle/src/ty/context/tls.rs index 788ccd5dbbdc7..5e256dc8d26e2 100644 --- a/compiler/rustc_middle/src/ty/context/tls.rs +++ b/compiler/rustc_middle/src/ty/context/tls.rs @@ -85,6 +85,7 @@ where /// Allows access to the current `ImplicitCtxt` in a closure if one is available. #[inline] +#[track_caller] pub fn with_context_opt(f: F) -> R where F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R, @@ -147,9 +148,13 @@ where /// Allows access to the `TyCtxt` in the current `ImplicitCtxt`. /// The closure is passed None if there is no `ImplicitCtxt` available. #[inline] +#[track_caller] pub fn with_opt(f: F) -> R where F: for<'tcx> FnOnce(Option>) -> R, { - with_context_opt(|opt_context| f(opt_context.map(|context| context.tcx))) + with_context_opt( + #[track_caller] + |opt_context| f(opt_context.map(|context| context.tcx)), + ) } diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs index a67ec99158210..43853a108960f 100644 --- a/compiler/rustc_middle/src/util/bug.rs +++ b/compiler/rustc_middle/src/util/bug.rs @@ -28,14 +28,17 @@ fn opt_span_bug_fmt>( args: fmt::Arguments<'_>, location: &Location<'_>, ) -> ! { - tls::with_opt(move |tcx| { - let msg = format!("{location}: {args}"); - match (tcx, span) { - (Some(tcx), Some(span)) => tcx.dcx().span_bug(span, msg), - (Some(tcx), None) => tcx.dcx().bug(msg), - (None, _) => panic_any(msg), - } - }) + tls::with_opt( + #[track_caller] + move |tcx| { + let msg = format!("{location}: {args}"); + match (tcx, span) { + (Some(tcx), Some(span)) => tcx.dcx().span_bug(span, msg), + (Some(tcx), None) => tcx.dcx().bug(msg), + (None, _) => panic_any(msg), + } + }, + ) } /// A query to trigger a delayed bug. Clearly, if one has a `tcx` one can already trigger a diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 411119b521bcd..acadfe7b35eb7 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -1013,8 +1013,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let Some(source_scope) = scope { self.source_scope = source_scope; } - - self.expr_into_dest(Place::return_place(), block, expr_id) + if self.tcx.intrinsic(self.def_id).is_some_and(|i| i.must_be_overridden) { + let source_info = self.source_info(rustc_span::DUMMY_SP); + self.cfg.terminate(block, source_info, TerminatorKind::Unreachable); + self.cfg.start_new_block().unit() + } else { + self.expr_into_dest(Place::return_place(), block, expr_id) + } } fn set_correct_source_scope_for_arg( diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs index 07e6ecccaa42c..483fd753e7077 100644 --- a/compiler/rustc_mir_transform/src/cross_crate_inline.rs +++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs @@ -23,10 +23,6 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { return false; } - if tcx.intrinsic(def_id).is_some_and(|i| i.must_be_overridden) { - return false; - } - // This just reproduces the logic from Instance::requires_inline. match tcx.def_kind(def_id) { DefKind::Ctor(..) | DefKind::Closure => return true, diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index afe228be12797..c63bdff9a85b0 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -633,12 +633,6 @@ fn optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> &Body<'_> { } fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> { - if tcx.intrinsic(did).is_some_and(|i| i.must_be_overridden) { - span_bug!( - tcx.def_span(did), - "this intrinsic must be overridden by the codegen backend, it has no meaningful body", - ) - } if tcx.is_constructor(did.to_def_id()) { // There's no reason to run all of the MIR passes on constructors when // we can just output the MIR we want directly. This also saves const diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index d8bdbd8c442b0..abe691ba0d83d 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1030,11 +1030,6 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> return false; } - if tcx.intrinsic(def_id).is_some_and(|i| i.must_be_overridden) { - // These are implemented by backends directly and have no meaningful body. - return false; - } - if def_id.is_local() { // Local items cannot be referred to locally without monomorphizing them locally. return true; diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index f939720287fd4..66e55a5e217d6 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2434,20 +2434,29 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn ptr_offset_from_unsigned(ptr: *const T, base: *const T) -> usize; - /// See documentation of `<*const T>::guaranteed_eq` for details. - /// Returns `2` if the result is unknown. - /// Returns `1` if the pointers are guaranteed equal - /// Returns `0` if the pointers are guaranteed inequal - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[rustc_safe_intrinsic] #[rustc_nounwind] + #[cfg(bootstrap)] pub fn ptr_guaranteed_cmp(ptr: *const T, other: *const T) -> u8; +} +/// See documentation of `<*const T>::guaranteed_eq` for details. +/// Returns `2` if the result is unknown. +/// Returns `1` if the pointers are guaranteed equal +/// Returns `0` if the pointers are guaranteed inequal +#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_intrinsic] +#[cfg(not(bootstrap))] +#[rustc_nounwind] +#[rustc_do_not_const_check] +#[inline] +pub const fn ptr_guaranteed_cmp(ptr: *const T, other: *const T) -> u8 { + (ptr == other) as u8 +} + +extern "rust-intrinsic" { /// Determines whether the raw bytes of the two values are equal. /// /// This is particularly handy for arrays, since it allows things like just @@ -2506,64 +2515,10 @@ extern "rust-intrinsic" { /// `ptr` must point to a vtable. /// The intrinsic will return the alignment stored in that vtable. #[rustc_nounwind] + #[cfg(bootstrap)] pub fn vtable_align(ptr: *const ()) -> usize; - /// Selects which function to call depending on the context. - /// - /// If this function is evaluated at compile-time, then a call to this - /// intrinsic will be replaced with a call to `called_in_const`. It gets - /// replaced with a call to `called_at_rt` otherwise. - /// - /// This function is safe to call, but note the stability concerns below. - /// - /// # Type Requirements - /// - /// The two functions must be both function items. They cannot be function - /// pointers or closures. The first function must be a `const fn`. - /// - /// `arg` will be the tupled arguments that will be passed to either one of - /// the two functions, therefore, both functions must accept the same type of - /// arguments. Both functions must return RET. - /// - /// # Stability concerns - /// - /// Rust has not yet decided that `const fn` are allowed to tell whether - /// they run at compile-time or at runtime. Therefore, when using this - /// intrinsic anywhere that can be reached from stable, it is crucial that - /// the end-to-end behavior of the stable `const fn` is the same for both - /// modes of execution. (Here, Undefined Behavior is considered "the same" - /// as any other behavior, so if the function exhibits UB at runtime then - /// it may do whatever it wants at compile-time.) - /// - /// Here is an example of how this could cause a problem: - /// ```no_run - /// #![feature(const_eval_select)] - /// #![feature(core_intrinsics)] - /// # #![allow(internal_features)] - /// # #![cfg_attr(bootstrap, allow(unused))] - /// use std::intrinsics::const_eval_select; - /// - /// // Standard library - /// # #[cfg(not(bootstrap))] - /// pub const fn inconsistent() -> i32 { - /// fn runtime() -> i32 { 1 } - /// const fn compiletime() -> i32 { 2 } - /// - // // ⚠ This code violates the required equivalence of `compiletime` - /// // and `runtime`. - /// const_eval_select((), compiletime, runtime) - /// } - /// # #[cfg(bootstrap)] - /// # pub const fn inconsistent() -> i32 { 0 } - /// - /// // User Crate - /// const X: i32 = inconsistent(); - /// let x = inconsistent(); - /// assert_eq!(x, X); - /// ``` - /// - /// Currently such an assertion would always succeed; until Rust decides - /// otherwise, that principle should not be violated. + #[cfg(bootstrap)] #[rustc_const_unstable(feature = "const_eval_select", issue = "none")] #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)] pub fn const_eval_select( @@ -2576,6 +2531,79 @@ extern "rust-intrinsic" { F: FnOnce; } +/// Selects which function to call depending on the context. +/// +/// If this function is evaluated at compile-time, then a call to this +/// intrinsic will be replaced with a call to `called_in_const`. It gets +/// replaced with a call to `called_at_rt` otherwise. +/// +/// This function is safe to call, but note the stability concerns below. +/// +/// # Type Requirements +/// +/// The two functions must be both function items. They cannot be function +/// pointers or closures. The first function must be a `const fn`. +/// +/// `arg` will be the tupled arguments that will be passed to either one of +/// the two functions, therefore, both functions must accept the same type of +/// arguments. Both functions must return RET. +/// +/// # Stability concerns +/// +/// Rust has not yet decided that `const fn` are allowed to tell whether +/// they run at compile-time or at runtime. Therefore, when using this +/// intrinsic anywhere that can be reached from stable, it is crucial that +/// the end-to-end behavior of the stable `const fn` is the same for both +/// modes of execution. (Here, Undefined Behavior is considered "the same" +/// as any other behavior, so if the function exhibits UB at runtime then +/// it may do whatever it wants at compile-time.) +/// +/// Here is an example of how this could cause a problem: +/// ```no_run +/// #![feature(const_eval_select)] +/// #![feature(core_intrinsics)] +/// # #![allow(internal_features)] +/// # #![cfg_attr(bootstrap, allow(unused))] +/// use std::intrinsics::const_eval_select; +/// +/// // Standard library +/// # #[cfg(not(bootstrap))] +/// pub const fn inconsistent() -> i32 { +/// fn runtime() -> i32 { 1 } +/// const fn compiletime() -> i32 { 2 } +/// +// // ⚠ This code violates the required equivalence of `compiletime` +/// // and `runtime`. +/// const_eval_select((), compiletime, runtime) +/// } +/// # #[cfg(bootstrap)] +/// # pub const fn inconsistent() -> i32 { 0 } +/// +/// // User Crate +/// const X: i32 = inconsistent(); +/// let x = inconsistent(); +/// assert_eq!(x, X); +/// ``` +/// +/// Currently such an assertion would always succeed; until Rust decides +/// otherwise, that principle should not be violated. +#[rustc_const_unstable(feature = "const_eval_select", issue = "none")] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[cfg(not(bootstrap))] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn const_eval_select( + _arg: ARG, + _called_in_const: F, + _called_at_rt: G, +) -> RET +where + G: FnOnce, + F: FnOnce, +{ + unreachable!() +} + /// Returns whether the argument's value is statically known at /// compile-time. /// @@ -2702,13 +2730,24 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) /// The intrinsic will return the size stored in that vtable. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[cfg_attr(not(bootstrap), rustc_intrinsic)] -#[cfg_attr(not(bootstrap), rustc_intrinsic_must_be_overridden)] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] #[cfg(not(bootstrap))] pub unsafe fn vtable_size(_ptr: *const ()) -> usize { unreachable!() } +/// `ptr` must point to a vtable. +/// The intrinsic will return the alignment stored in that vtable. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[cfg(not(bootstrap))] +pub unsafe fn vtable_align(_ptr: *const ()) -> usize { + unreachable!() +} + // Some functions are defined here because they accidentally got made // available in this module on stable. See . // (`transmute` also falls into this category, but it cannot be wrapped due to the diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs index 1b380c989fa4a..281cfdaef28cc 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs @@ -509,17 +509,19 @@ trait StructuralPartialEq {} const fn drop(_: T) {} -extern "rust-intrinsic" { - #[rustc_const_stable(feature = "const_eval_select", since = "1.0.0")] - #[rustc_safe_intrinsic] - fn const_eval_select( - arg: ARG, - called_in_const: F, - called_at_rt: G, - ) -> RET - where - F: const FnOnce, - G: FnOnce; +#[rustc_const_stable(feature = "const_eval_select", since = "1.0.0")] +#[rustc_intrinsic_must_be_overridden] +#[rustc_intrinsic] +const fn const_eval_select( + arg: ARG, + called_in_const: F, + called_at_rt: G, +) -> RET +where + F: const FnOnce, + G: FnOnce, +{ + loop {} } fn test_const_eval_select() {