diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 35755a46df3a4..7a1fe3b1cdc4d 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -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..68911f579cd93 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1704,8 +1704,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { { for &local_def_id in tcx.mir_keys(()) { if let DefKind::AssocFn | DefKind::Fn = tcx.def_kind(local_def_id) { - record_array!(self.tables.deduced_param_attrs[local_def_id.to_def_id()] <- - self.tcx.deduced_param_attrs(local_def_id.to_def_id())); + if tcx.intrinsic(local_def_id).map_or(true, |i| !i.must_be_overridden) { + record_array!(self.tables.deduced_param_attrs[local_def_id.to_def_id()] <- + self.tcx.deduced_param_attrs(local_def_id.to_def_id())); + } } } } diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 5043bd855ccb9..57a88a0310919 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1365,7 +1365,9 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> { fn visit_impl_item(&mut self, item: &'hir ImplItem<'hir>) { if associated_body(Node::ImplItem(item)).is_some() { - self.body_owners.push(item.owner_id.def_id); + if !self.tcx.has_attr(item.owner_id.def_id, sym::rustc_intrinsic_must_be_overridden) { + self.body_owners.push(item.owner_id.def_id); + } } self.impl_items.push(item.impl_item_id()); diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index f939720287fd4..9a7ade8a83727 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2508,62 +2508,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] 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 +2521,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. /// 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() {