Skip to content

Commit 7f9830b

Browse files
committed
Make const_eval_select a rustc_intrinsic
1 parent 196ff44 commit 7f9830b

File tree

5 files changed

+95
-71
lines changed

5 files changed

+95
-71
lines changed

compiler/rustc_hir_analysis/src/check/intrinsic.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,7 @@ pub fn check_intrinsic_type(
579579

580580
sym::is_val_statically_known => (1, 1, vec![param(0)], tcx.types.bool),
581581

582-
sym::const_eval_select => (4, 0, vec![param(0), param(1), param(2)], param(3)),
582+
sym::const_eval_select => (4, 1, vec![param(0), param(1), param(2)], param(3)),
583583

584584
sym::vtable_size | sym::vtable_align => {
585585
(0, 0, vec![Ty::new_imm_ptr(tcx, Ty::new_unit(tcx))], tcx.types.usize)

compiler/rustc_metadata/src/rmeta/encoder.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1704,8 +1704,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
17041704
{
17051705
for &local_def_id in tcx.mir_keys(()) {
17061706
if let DefKind::AssocFn | DefKind::Fn = tcx.def_kind(local_def_id) {
1707-
record_array!(self.tables.deduced_param_attrs[local_def_id.to_def_id()] <-
1708-
self.tcx.deduced_param_attrs(local_def_id.to_def_id()));
1707+
if tcx.intrinsic(local_def_id).map_or(true, |i| !i.must_be_overridden) {
1708+
record_array!(self.tables.deduced_param_attrs[local_def_id.to_def_id()] <-
1709+
self.tcx.deduced_param_attrs(local_def_id.to_def_id()));
1710+
}
17091711
}
17101712
}
17111713
}

compiler/rustc_middle/src/hir/map/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1365,7 +1365,9 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
13651365

13661366
fn visit_impl_item(&mut self, item: &'hir ImplItem<'hir>) {
13671367
if associated_body(Node::ImplItem(item)).is_some() {
1368-
self.body_owners.push(item.owner_id.def_id);
1368+
if !self.tcx.has_attr(item.owner_id.def_id, sym::rustc_intrinsic_must_be_overridden) {
1369+
self.body_owners.push(item.owner_id.def_id);
1370+
}
13691371
}
13701372

13711373
self.impl_items.push(item.impl_item_id());

library/core/src/intrinsics.rs

+74-56
Original file line numberDiff line numberDiff line change
@@ -2508,62 +2508,7 @@ extern "rust-intrinsic" {
25082508
#[rustc_nounwind]
25092509
pub fn vtable_align(ptr: *const ()) -> usize;
25102510

2511-
/// Selects which function to call depending on the context.
2512-
///
2513-
/// If this function is evaluated at compile-time, then a call to this
2514-
/// intrinsic will be replaced with a call to `called_in_const`. It gets
2515-
/// replaced with a call to `called_at_rt` otherwise.
2516-
///
2517-
/// This function is safe to call, but note the stability concerns below.
2518-
///
2519-
/// # Type Requirements
2520-
///
2521-
/// The two functions must be both function items. They cannot be function
2522-
/// pointers or closures. The first function must be a `const fn`.
2523-
///
2524-
/// `arg` will be the tupled arguments that will be passed to either one of
2525-
/// the two functions, therefore, both functions must accept the same type of
2526-
/// arguments. Both functions must return RET.
2527-
///
2528-
/// # Stability concerns
2529-
///
2530-
/// Rust has not yet decided that `const fn` are allowed to tell whether
2531-
/// they run at compile-time or at runtime. Therefore, when using this
2532-
/// intrinsic anywhere that can be reached from stable, it is crucial that
2533-
/// the end-to-end behavior of the stable `const fn` is the same for both
2534-
/// modes of execution. (Here, Undefined Behavior is considered "the same"
2535-
/// as any other behavior, so if the function exhibits UB at runtime then
2536-
/// it may do whatever it wants at compile-time.)
2537-
///
2538-
/// Here is an example of how this could cause a problem:
2539-
/// ```no_run
2540-
/// #![feature(const_eval_select)]
2541-
/// #![feature(core_intrinsics)]
2542-
/// # #![allow(internal_features)]
2543-
/// # #![cfg_attr(bootstrap, allow(unused))]
2544-
/// use std::intrinsics::const_eval_select;
2545-
///
2546-
/// // Standard library
2547-
/// # #[cfg(not(bootstrap))]
2548-
/// pub const fn inconsistent() -> i32 {
2549-
/// fn runtime() -> i32 { 1 }
2550-
/// const fn compiletime() -> i32 { 2 }
2551-
///
2552-
// // ⚠ This code violates the required equivalence of `compiletime`
2553-
/// // and `runtime`.
2554-
/// const_eval_select((), compiletime, runtime)
2555-
/// }
2556-
/// # #[cfg(bootstrap)]
2557-
/// # pub const fn inconsistent() -> i32 { 0 }
2558-
///
2559-
/// // User Crate
2560-
/// const X: i32 = inconsistent();
2561-
/// let x = inconsistent();
2562-
/// assert_eq!(x, X);
2563-
/// ```
2564-
///
2565-
/// Currently such an assertion would always succeed; until Rust decides
2566-
/// otherwise, that principle should not be violated.
2511+
#[cfg(bootstrap)]
25672512
#[rustc_const_unstable(feature = "const_eval_select", issue = "none")]
25682513
#[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
25692514
pub fn const_eval_select<ARG: Tuple, F, G, RET>(
@@ -2576,6 +2521,79 @@ extern "rust-intrinsic" {
25762521
F: FnOnce<ARG, Output = RET>;
25772522
}
25782523

2524+
/// Selects which function to call depending on the context.
2525+
///
2526+
/// If this function is evaluated at compile-time, then a call to this
2527+
/// intrinsic will be replaced with a call to `called_in_const`. It gets
2528+
/// replaced with a call to `called_at_rt` otherwise.
2529+
///
2530+
/// This function is safe to call, but note the stability concerns below.
2531+
///
2532+
/// # Type Requirements
2533+
///
2534+
/// The two functions must be both function items. They cannot be function
2535+
/// pointers or closures. The first function must be a `const fn`.
2536+
///
2537+
/// `arg` will be the tupled arguments that will be passed to either one of
2538+
/// the two functions, therefore, both functions must accept the same type of
2539+
/// arguments. Both functions must return RET.
2540+
///
2541+
/// # Stability concerns
2542+
///
2543+
/// Rust has not yet decided that `const fn` are allowed to tell whether
2544+
/// they run at compile-time or at runtime. Therefore, when using this
2545+
/// intrinsic anywhere that can be reached from stable, it is crucial that
2546+
/// the end-to-end behavior of the stable `const fn` is the same for both
2547+
/// modes of execution. (Here, Undefined Behavior is considered "the same"
2548+
/// as any other behavior, so if the function exhibits UB at runtime then
2549+
/// it may do whatever it wants at compile-time.)
2550+
///
2551+
/// Here is an example of how this could cause a problem:
2552+
/// ```no_run
2553+
/// #![feature(const_eval_select)]
2554+
/// #![feature(core_intrinsics)]
2555+
/// # #![allow(internal_features)]
2556+
/// # #![cfg_attr(bootstrap, allow(unused))]
2557+
/// use std::intrinsics::const_eval_select;
2558+
///
2559+
/// // Standard library
2560+
/// # #[cfg(not(bootstrap))]
2561+
/// pub const fn inconsistent() -> i32 {
2562+
/// fn runtime() -> i32 { 1 }
2563+
/// const fn compiletime() -> i32 { 2 }
2564+
///
2565+
// // ⚠ This code violates the required equivalence of `compiletime`
2566+
/// // and `runtime`.
2567+
/// const_eval_select((), compiletime, runtime)
2568+
/// }
2569+
/// # #[cfg(bootstrap)]
2570+
/// # pub const fn inconsistent() -> i32 { 0 }
2571+
///
2572+
/// // User Crate
2573+
/// const X: i32 = inconsistent();
2574+
/// let x = inconsistent();
2575+
/// assert_eq!(x, X);
2576+
/// ```
2577+
///
2578+
/// Currently such an assertion would always succeed; until Rust decides
2579+
/// otherwise, that principle should not be violated.
2580+
#[rustc_const_unstable(feature = "const_eval_select", issue = "none")]
2581+
#[unstable(feature = "core_intrinsics", issue = "none")]
2582+
#[cfg(not(bootstrap))]
2583+
#[rustc_intrinsic]
2584+
#[rustc_intrinsic_must_be_overridden]
2585+
pub const fn const_eval_select<ARG: Tuple, F, G, RET>(
2586+
_arg: ARG,
2587+
_called_in_const: F,
2588+
_called_at_rt: G,
2589+
) -> RET
2590+
where
2591+
G: FnOnce<ARG, Output = RET>,
2592+
F: FnOnce<ARG, Output = RET>,
2593+
{
2594+
unreachable!()
2595+
}
2596+
25792597
/// Returns whether the argument's value is statically known at
25802598
/// compile-time.
25812599
///

tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs

+13-11
Original file line numberDiff line numberDiff line change
@@ -509,17 +509,19 @@ trait StructuralPartialEq {}
509509

510510
const fn drop<T: ~const Destruct>(_: T) {}
511511

512-
extern "rust-intrinsic" {
513-
#[rustc_const_stable(feature = "const_eval_select", since = "1.0.0")]
514-
#[rustc_safe_intrinsic]
515-
fn const_eval_select<ARG: Tuple, F, G, RET>(
516-
arg: ARG,
517-
called_in_const: F,
518-
called_at_rt: G,
519-
) -> RET
520-
where
521-
F: const FnOnce<ARG, Output = RET>,
522-
G: FnOnce<ARG, Output = RET>;
512+
#[rustc_const_stable(feature = "const_eval_select", since = "1.0.0")]
513+
#[rustc_intrinsic_must_be_overridden]
514+
#[rustc_intrinsic]
515+
const fn const_eval_select<ARG: Tuple, F, G, RET>(
516+
arg: ARG,
517+
called_in_const: F,
518+
called_at_rt: G,
519+
) -> RET
520+
where
521+
F: const FnOnce<ARG, Output = RET>,
522+
G: FnOnce<ARG, Output = RET>,
523+
{
524+
loop {}
523525
}
524526

525527
fn test_const_eval_select() {

0 commit comments

Comments
 (0)