Auto merge of #122037 - oli-obk:more_new_intrinsics, r=Nilstrieb
Move more intrinsics to rustc_intrinsic cc https://github.com/rust-lang/rust/issues/63585
This commit is contained in:
commit
200e3f7995
14 changed files with 147 additions and 128 deletions
|
@ -757,13 +757,6 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
||||||
ret.write_cvalue(fx, val);
|
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 => {
|
sym::caller_location => {
|
||||||
intrinsic_args!(fx, args => (); intrinsic);
|
intrinsic_args!(fx, args => (); intrinsic);
|
||||||
|
|
||||||
|
|
|
@ -81,10 +81,6 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S
|
||||||
return library.kind.is_statically_included().then_some(def_id);
|
return library.kind.is_statically_included().then_some(def_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if tcx.intrinsic(def_id).is_some_and(|i| i.must_be_overridden) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only consider nodes that actually have exported symbols.
|
// Only consider nodes that actually have exported symbols.
|
||||||
match tcx.def_kind(def_id) {
|
match tcx.def_kind(def_id) {
|
||||||
DefKind::Fn | DefKind::Static { .. } => {}
|
DefKind::Fn | DefKind::Static { .. } => {}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use super::operand::{OperandRef, OperandValue};
|
use super::operand::{OperandRef, OperandValue};
|
||||||
use super::place::PlaceRef;
|
use super::place::PlaceRef;
|
||||||
use super::FunctionCx;
|
use super::FunctionCx;
|
||||||
use crate::common::IntPredicate;
|
|
||||||
use crate::errors;
|
use crate::errors;
|
||||||
use crate::errors::InvalidMonomorphization;
|
use crate::errors::InvalidMonomorphization;
|
||||||
use crate::meth;
|
use crate::meth;
|
||||||
|
@ -456,12 +455,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
return Ok(());
|
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 => {
|
sym::ptr_offset_from | sym::ptr_offset_from_unsigned => {
|
||||||
let ty = fn_args.type_at(0);
|
let ty = fn_args.type_at(0);
|
||||||
let pointee_size = bx.layout_of(ty).size;
|
let pointee_size = bx.layout_of(ty).size;
|
||||||
|
|
|
@ -441,7 +441,7 @@ pub fn check_intrinsic_type(
|
||||||
|
|
||||||
sym::ptr_guaranteed_cmp => (
|
sym::ptr_guaranteed_cmp => (
|
||||||
1,
|
1,
|
||||||
0,
|
1,
|
||||||
vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))],
|
vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))],
|
||||||
tcx.types.u8,
|
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::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 => {
|
sym::vtable_size | sym::vtable_align => {
|
||||||
(0, 0, vec![Ty::new_imm_ptr(tcx, Ty::new_unit(tcx))], tcx.types.usize)
|
(0, 0, vec![Ty::new_imm_ptr(tcx, Ty::new_unit(tcx))], tcx.types.usize)
|
||||||
|
|
|
@ -1067,14 +1067,11 @@ fn should_encode_mir(
|
||||||
// Full-fledged functions + closures
|
// Full-fledged functions + closures
|
||||||
DefKind::AssocFn | DefKind::Fn | DefKind::Closure => {
|
DefKind::AssocFn | DefKind::Fn | DefKind::Closure => {
|
||||||
let generics = tcx.generics_of(def_id);
|
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()
|
|| (tcx.sess.opts.output_types.should_codegen()
|
||||||
&& reachable_set.contains(&def_id)
|
&& reachable_set.contains(&def_id)
|
||||||
&& (generics.requires_monomorphization(tcx)
|
&& (generics.requires_monomorphization(tcx)
|
||||||
|| tcx.cross_crate_inlinable(def_id)));
|
|| 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]`.
|
// 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())
|
let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id())
|
||||||
|| tcx.is_const_default_method(def_id.to_def_id());
|
|| tcx.is_const_default_method(def_id.to_def_id());
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#![feature(array_windows)]
|
#![feature(array_windows)]
|
||||||
#![feature(assert_matches)]
|
#![feature(assert_matches)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
|
#![feature(closure_track_caller)]
|
||||||
#![feature(core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
#![feature(const_type_name)]
|
#![feature(const_type_name)]
|
||||||
#![feature(discriminant_kind)]
|
#![feature(discriminant_kind)]
|
||||||
|
|
|
@ -85,6 +85,7 @@ where
|
||||||
|
|
||||||
/// Allows access to the current `ImplicitCtxt` in a closure if one is available.
|
/// Allows access to the current `ImplicitCtxt` in a closure if one is available.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[track_caller]
|
||||||
pub fn with_context_opt<F, R>(f: F) -> R
|
pub fn with_context_opt<F, R>(f: F) -> R
|
||||||
where
|
where
|
||||||
F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R,
|
F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R,
|
||||||
|
@ -147,9 +148,13 @@ where
|
||||||
/// Allows access to the `TyCtxt` in the current `ImplicitCtxt`.
|
/// Allows access to the `TyCtxt` in the current `ImplicitCtxt`.
|
||||||
/// The closure is passed None if there is no `ImplicitCtxt` available.
|
/// The closure is passed None if there is no `ImplicitCtxt` available.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[track_caller]
|
||||||
pub fn with_opt<F, R>(f: F) -> R
|
pub fn with_opt<F, R>(f: F) -> R
|
||||||
where
|
where
|
||||||
F: for<'tcx> FnOnce(Option<TyCtxt<'tcx>>) -> R,
|
F: for<'tcx> FnOnce(Option<TyCtxt<'tcx>>) -> 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)),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,14 +28,17 @@ fn opt_span_bug_fmt<S: Into<MultiSpan>>(
|
||||||
args: fmt::Arguments<'_>,
|
args: fmt::Arguments<'_>,
|
||||||
location: &Location<'_>,
|
location: &Location<'_>,
|
||||||
) -> ! {
|
) -> ! {
|
||||||
tls::with_opt(move |tcx| {
|
tls::with_opt(
|
||||||
let msg = format!("{location}: {args}");
|
#[track_caller]
|
||||||
match (tcx, span) {
|
move |tcx| {
|
||||||
(Some(tcx), Some(span)) => tcx.dcx().span_bug(span, msg),
|
let msg = format!("{location}: {args}");
|
||||||
(Some(tcx), None) => tcx.dcx().bug(msg),
|
match (tcx, span) {
|
||||||
(None, _) => panic_any(msg),
|
(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
|
/// A query to trigger a delayed bug. Clearly, if one has a `tcx` one can already trigger a
|
||||||
|
|
|
@ -1013,8 +1013,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
if let Some(source_scope) = scope {
|
if let Some(source_scope) = scope {
|
||||||
self.source_scope = source_scope;
|
self.source_scope = source_scope;
|
||||||
}
|
}
|
||||||
|
if self.tcx.intrinsic(self.def_id).is_some_and(|i| i.must_be_overridden) {
|
||||||
self.expr_into_dest(Place::return_place(), block, expr_id)
|
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(
|
fn set_correct_source_scope_for_arg(
|
||||||
|
|
|
@ -23,10 +23,6 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
|
||||||
return false;
|
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.
|
// This just reproduces the logic from Instance::requires_inline.
|
||||||
match tcx.def_kind(def_id) {
|
match tcx.def_kind(def_id) {
|
||||||
DefKind::Ctor(..) | DefKind::Closure => return true,
|
DefKind::Ctor(..) | DefKind::Closure => return true,
|
||||||
|
|
|
@ -633,12 +633,6 @@ fn optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> &Body<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inner_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()) {
|
if tcx.is_constructor(did.to_def_id()) {
|
||||||
// There's no reason to run all of the MIR passes on constructors when
|
// 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
|
// we can just output the MIR we want directly. This also saves const
|
||||||
|
|
|
@ -1030,11 +1030,6 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) ->
|
||||||
return false;
|
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() {
|
if def_id.is_local() {
|
||||||
// Local items cannot be referred to locally without monomorphizing them locally.
|
// Local items cannot be referred to locally without monomorphizing them locally.
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -2434,20 +2434,29 @@ extern "rust-intrinsic" {
|
||||||
#[rustc_nounwind]
|
#[rustc_nounwind]
|
||||||
pub fn ptr_offset_from_unsigned<T>(ptr: *const T, base: *const T) -> usize;
|
pub fn ptr_offset_from_unsigned<T>(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_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
|
||||||
#[rustc_safe_intrinsic]
|
#[rustc_safe_intrinsic]
|
||||||
#[rustc_nounwind]
|
#[rustc_nounwind]
|
||||||
|
#[cfg(bootstrap)]
|
||||||
pub fn ptr_guaranteed_cmp<T>(ptr: *const T, other: *const T) -> u8;
|
pub fn ptr_guaranteed_cmp<T>(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<T>(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.
|
/// Determines whether the raw bytes of the two values are equal.
|
||||||
///
|
///
|
||||||
/// This is particularly handy for arrays, since it allows things like just
|
/// 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.
|
/// `ptr` must point to a vtable.
|
||||||
/// The intrinsic will return the alignment stored in that vtable.
|
/// The intrinsic will return the alignment stored in that vtable.
|
||||||
#[rustc_nounwind]
|
#[rustc_nounwind]
|
||||||
|
#[cfg(bootstrap)]
|
||||||
pub fn vtable_align(ptr: *const ()) -> usize;
|
pub fn vtable_align(ptr: *const ()) -> usize;
|
||||||
|
|
||||||
/// Selects which function to call depending on the context.
|
#[cfg(bootstrap)]
|
||||||
///
|
|
||||||
/// 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")]
|
#[rustc_const_unstable(feature = "const_eval_select", issue = "none")]
|
||||||
#[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
|
#[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
|
||||||
pub fn const_eval_select<ARG: Tuple, F, G, RET>(
|
pub fn const_eval_select<ARG: Tuple, F, G, RET>(
|
||||||
|
@ -2576,6 +2531,79 @@ extern "rust-intrinsic" {
|
||||||
F: FnOnce<ARG, Output = RET>;
|
F: FnOnce<ARG, Output = RET>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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: Tuple, F, G, RET>(
|
||||||
|
_arg: ARG,
|
||||||
|
_called_in_const: F,
|
||||||
|
_called_at_rt: G,
|
||||||
|
) -> RET
|
||||||
|
where
|
||||||
|
G: FnOnce<ARG, Output = RET>,
|
||||||
|
F: FnOnce<ARG, Output = RET>,
|
||||||
|
{
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns whether the argument's value is statically known at
|
/// Returns whether the argument's value is statically known at
|
||||||
/// compile-time.
|
/// 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.
|
/// The intrinsic will return the size stored in that vtable.
|
||||||
#[rustc_nounwind]
|
#[rustc_nounwind]
|
||||||
#[unstable(feature = "core_intrinsics", issue = "none")]
|
#[unstable(feature = "core_intrinsics", issue = "none")]
|
||||||
#[cfg_attr(not(bootstrap), rustc_intrinsic)]
|
#[rustc_intrinsic]
|
||||||
#[cfg_attr(not(bootstrap), rustc_intrinsic_must_be_overridden)]
|
#[rustc_intrinsic_must_be_overridden]
|
||||||
#[cfg(not(bootstrap))]
|
#[cfg(not(bootstrap))]
|
||||||
pub unsafe fn vtable_size(_ptr: *const ()) -> usize {
|
pub unsafe fn vtable_size(_ptr: *const ()) -> usize {
|
||||||
unreachable!()
|
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
|
// Some functions are defined here because they accidentally got made
|
||||||
// available in this module on stable. See <https://github.com/rust-lang/rust/issues/15702>.
|
// available in this module on stable. See <https://github.com/rust-lang/rust/issues/15702>.
|
||||||
// (`transmute` also falls into this category, but it cannot be wrapped due to the
|
// (`transmute` also falls into this category, but it cannot be wrapped due to the
|
||||||
|
|
|
@ -509,17 +509,19 @@ trait StructuralPartialEq {}
|
||||||
|
|
||||||
const fn drop<T: ~const Destruct>(_: T) {}
|
const fn drop<T: ~const Destruct>(_: T) {}
|
||||||
|
|
||||||
extern "rust-intrinsic" {
|
#[rustc_const_stable(feature = "const_eval_select", since = "1.0.0")]
|
||||||
#[rustc_const_stable(feature = "const_eval_select", since = "1.0.0")]
|
#[rustc_intrinsic_must_be_overridden]
|
||||||
#[rustc_safe_intrinsic]
|
#[rustc_intrinsic]
|
||||||
fn const_eval_select<ARG: Tuple, F, G, RET>(
|
const fn const_eval_select<ARG: Tuple, F, G, RET>(
|
||||||
arg: ARG,
|
arg: ARG,
|
||||||
called_in_const: F,
|
called_in_const: F,
|
||||||
called_at_rt: G,
|
called_at_rt: G,
|
||||||
) -> RET
|
) -> RET
|
||||||
where
|
where
|
||||||
F: const FnOnce<ARG, Output = RET>,
|
F: const FnOnce<ARG, Output = RET>,
|
||||||
G: FnOnce<ARG, Output = RET>;
|
G: FnOnce<ARG, Output = RET>,
|
||||||
|
{
|
||||||
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_const_eval_select() {
|
fn test_const_eval_select() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue