Stop backends from needing to support nullary intrinsics

This commit is contained in:
Oli Scherer
2025-06-21 11:26:27 +00:00
parent f19142044f
commit 672e0bec9e
9 changed files with 67 additions and 86 deletions

View File

@@ -660,7 +660,7 @@ pub mod intrinsics {
#[rustc_intrinsic]
pub unsafe fn ctlz_nonzero<T>(x: T) -> u32;
#[rustc_intrinsic]
pub fn needs_drop<T: ?::Sized>() -> bool;
pub const fn needs_drop<T: ?::Sized>() -> bool;
#[rustc_intrinsic]
pub fn bitreverse<T>(x: T) -> T;
#[rustc_intrinsic]

View File

@@ -1,4 +1,13 @@
#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local, repr_simd)]
#![feature(
no_core,
lang_items,
never_type,
linkage,
extern_types,
thread_local,
repr_simd,
rustc_private
)]
#![no_core]
#![allow(dead_code, non_camel_case_types, internal_features)]
@@ -207,10 +216,14 @@ fn main() {
assert_eq!(intrinsics::align_of::<u16>() as u8, 2);
assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8);
assert!(!intrinsics::needs_drop::<u8>());
assert!(!intrinsics::needs_drop::<[u8]>());
assert!(intrinsics::needs_drop::<NoisyDrop>());
assert!(intrinsics::needs_drop::<NoisyDropUnsized>());
let u8_needs_drop = const { intrinsics::needs_drop::<u8>() };
assert!(!u8_needs_drop);
let slice_needs_drop = const { intrinsics::needs_drop::<[u8]>() };
assert!(!slice_needs_drop);
let noisy_drop = const { intrinsics::needs_drop::<NoisyDrop>() };
assert!(noisy_drop);
let noisy_unsized_drop = const { intrinsics::needs_drop::<NoisyDropUnsized>() };
assert!(noisy_unsized_drop);
Unique { pointer: NonNull(1 as *mut &str), _marker: PhantomData } as Unique<dyn SomeTrait>;

View File

@@ -812,21 +812,6 @@ fn codegen_regular_intrinsic_call<'tcx>(
dest.write_cvalue(fx, val);
}
sym::needs_drop | sym::type_id | sym::type_name | sym::variant_count => {
intrinsic_args!(fx, args => (); intrinsic);
let const_val = fx
.tcx
.const_eval_instance(
ty::TypingEnv::fully_monomorphized(),
instance,
source_info.span,
)
.unwrap();
let val = crate::constant::codegen_const_value(fx, const_val, ret.layout().ty);
ret.write_cvalue(fx, val);
}
sym::ptr_offset_from | sym::ptr_offset_from_unsigned => {
intrinsic_args!(fx, args => (ptr, base); intrinsic);
let ptr = ptr.load_scalar(fx);

View File

@@ -6,6 +6,7 @@
)]
#![no_core]
#![allow(dead_code, internal_features, non_camel_case_types)]
#![rustfmt::skip]
extern crate mini_core;
@@ -197,10 +198,10 @@ fn main() {
assert_eq!(intrinsics::align_of::<u16>() as u8, 2);
assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8);
assert!(!intrinsics::needs_drop::<u8>());
assert!(!intrinsics::needs_drop::<[u8]>());
assert!(intrinsics::needs_drop::<NoisyDrop>());
assert!(intrinsics::needs_drop::<NoisyDropUnsized>());
assert!(!const { intrinsics::needs_drop::<u8>() });
assert!(!const { intrinsics::needs_drop::<[u8]>() });
assert!(const { intrinsics::needs_drop::<NoisyDrop>() });
assert!(const { intrinsics::needs_drop::<NoisyDropUnsized>() });
Unique {
pointer: 0 as *const &str,

View File

@@ -150,10 +150,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
value
}
sym::needs_drop | sym::type_id | sym::type_name | sym::variant_count => {
let value = bx.tcx().const_eval_instance(bx.typing_env(), instance, span).unwrap();
OperandRef::from_const(bx, value, result.layout.ty).immediate_or_packed_pair(bx)
}
sym::arith_offset => {
let ty = fn_args.type_at(0);
let layout = bx.layout_of(ty);

View File

@@ -742,7 +742,7 @@ impl TypeId {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_type_id", issue = "77125")]
pub const fn of<T: ?Sized + 'static>() -> TypeId {
let t: u128 = intrinsics::type_id::<T>();
let t: u128 = const { intrinsics::type_id::<T>() };
let t1 = (t >> 64) as u64;
let t2 = t as u64;
@@ -824,7 +824,7 @@ impl fmt::Debug for TypeId {
#[stable(feature = "type_name", since = "1.38.0")]
#[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
pub const fn type_name<T: ?Sized>() -> &'static str {
intrinsics::type_name::<T>()
const { intrinsics::type_name::<T>() }
}
/// Returns the type name of the pointed-to value as a string slice.

View File

@@ -839,10 +839,10 @@ pub const unsafe fn transmute_unchecked<Src, Dst>(src: Src) -> Dst;
/// If the actual type neither requires drop glue nor implements
/// `Copy`, then the return value of this function is unspecified.
///
/// 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.
/// Note that, unlike most intrinsics, this can only be called at compile-time
/// as backends do not have an implementation for it. The only caller (its
/// stable counterpart), wraps this intrinsic call in a `const` block so that
/// backends only see an evaluated constant.
///
/// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop).
#[rustc_intrinsic_const_stable_indirect]
@@ -2655,10 +2655,10 @@ pub const fn align_of<T>() -> usize;
/// Returns the number of variants of the type `T` cast to a `usize`;
/// if `T` has no variants, returns `0`. Uninhabited variants will be counted.
///
/// 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.
/// Note that, unlike most intrinsics, this can only be called at compile-time
/// as backends do not have an implementation for it. The only caller (its
/// stable counterpart), wraps this intrinsic call in a `const` block so that
/// backends only see an evaluated constant.
///
/// The to-be-stabilized version of this intrinsic is [`crate::mem::variant_count`].
#[rustc_nounwind]
@@ -2694,10 +2694,10 @@ pub const unsafe fn align_of_val<T: ?Sized>(ptr: *const T) -> usize;
/// Gets a static string slice containing the name of a type.
///
/// 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.
/// Note that, unlike most intrinsics, this can only be called at compile-time
/// as backends do not have an implementation for it. The only caller (its
/// stable counterpart), wraps this intrinsic call in a `const` block so that
/// backends only see an evaluated constant.
///
/// The stabilized version of this intrinsic is [`core::any::type_name`].
#[rustc_nounwind]
@@ -2709,10 +2709,10 @@ pub const fn type_name<T: ?Sized>() -> &'static str;
/// function will return the same value for a type regardless of whichever
/// crate it is invoked in.
///
/// 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.
/// Note that, unlike most intrinsics, this can only be called at compile-time
/// as backends do not have an implementation for it. The only caller (its
/// stable counterpart), wraps this intrinsic call in a `const` block so that
/// backends only see an evaluated constant.
///
/// The stabilized version of this intrinsic is [`core::any::TypeId::of`].
#[rustc_nounwind]

View File

@@ -616,7 +616,7 @@ pub const unsafe fn align_of_val_raw<T: ?Sized>(val: *const T) -> usize {
#[rustc_const_stable(feature = "const_mem_needs_drop", since = "1.36.0")]
#[rustc_diagnostic_item = "needs_drop"]
pub const fn needs_drop<T: ?Sized>() -> bool {
intrinsics::needs_drop::<T>()
const { intrinsics::needs_drop::<T>() }
}
/// Returns the value of type `T` represented by the all-zero byte-pattern.
@@ -1215,7 +1215,7 @@ pub const fn discriminant<T>(v: &T) -> Discriminant<T> {
#[rustc_const_unstable(feature = "variant_count", issue = "73662")]
#[rustc_diagnostic_item = "mem_variant_count"]
pub const fn variant_count<T>() -> usize {
intrinsics::variant_count::<T>()
const { intrinsics::variant_count::<T>() }
}
/// Provides associated constants for various useful properties of types,

View File

@@ -19,12 +19,6 @@ extern crate rustc_driver;
extern crate rustc_interface;
extern crate stable_mir;
use stable_mir::crate_def::CrateDef;
use stable_mir::mir::alloc::GlobalAlloc;
use stable_mir::mir::mono::{Instance, InstanceKind, StaticDef};
use stable_mir::mir::{Body, TerminatorKind};
use stable_mir::ty::{Allocation, ConstantKind, RigidTy, TyKind};
use stable_mir::{CrateItem, CrateItems, ItemKind};
use std::ascii::Char;
use std::assert_matches::assert_matches;
use std::cmp::{max, min};
@@ -33,6 +27,13 @@ use std::ffi::CStr;
use std::io::Write;
use std::ops::ControlFlow;
use stable_mir::crate_def::CrateDef;
use stable_mir::mir::Body;
use stable_mir::mir::alloc::GlobalAlloc;
use stable_mir::mir::mono::{Instance, StaticDef};
use stable_mir::ty::{Allocation, ConstantKind};
use stable_mir::{CrateItem, CrateItems, ItemKind};
const CRATE_NAME: &str = "input";
/// This function uses the Stable MIR APIs to get information about the test crate.
@@ -44,7 +45,6 @@ fn test_stable_mir() -> ControlFlow<()> {
check_len(*get_item(&items, (ItemKind::Static, "LEN")).unwrap());
check_cstr(*get_item(&items, (ItemKind::Static, "C_STR")).unwrap());
check_other_consts(*get_item(&items, (ItemKind::Fn, "other_consts")).unwrap());
check_type_id(*get_item(&items, (ItemKind::Fn, "check_type_id")).unwrap());
ControlFlow::Continue(())
}
@@ -107,7 +107,9 @@ fn check_other_consts(item: CrateItem) {
// Instance body will force constant evaluation.
let body = Instance::try_from(item).unwrap().body().unwrap();
let assigns = collect_consts(&body);
assert_eq!(assigns.len(), 8);
assert_eq!(assigns.len(), 10);
let mut char_id = None;
let mut bool_id = None;
for (name, alloc) in assigns {
match name.as_str() {
"_max_u128" => {
@@ -149,35 +151,21 @@ fn check_other_consts(item: CrateItem) {
assert_eq!(max(first, second) as u32, u32::MAX);
assert_eq!(min(first, second), 10);
}
"_bool_id" => {
bool_id = Some(alloc);
}
"_char_id" => {
char_id = Some(alloc);
}
_ => {
unreachable!("{name} -- {alloc:?}")
}
}
}
}
/// Check that we can retrieve the type id of char and bool, and that they have different values.
fn check_type_id(item: CrateItem) {
let body = Instance::try_from(item).unwrap().body().unwrap();
let mut ids: Vec<u128> = vec![];
for term in body.blocks.iter().map(|bb| &bb.terminator) {
match &term.kind {
TerminatorKind::Call { func, destination, .. } => {
let TyKind::RigidTy(ty) = func.ty(body.locals()).unwrap().kind() else {
unreachable!()
};
let RigidTy::FnDef(def, args) = ty else { unreachable!() };
let instance = Instance::resolve(def, &args).unwrap();
assert_eq!(instance.kind, InstanceKind::Intrinsic);
let dest_ty = destination.ty(body.locals()).unwrap();
let alloc = instance.try_const_eval(dest_ty).unwrap();
ids.push(alloc.read_uint().unwrap());
}
_ => { /* Do nothing */ }
}
}
assert_eq!(ids.len(), 2);
assert_ne!(ids[0], ids[1]);
let bool_id = bool_id.unwrap();
let char_id = char_id.unwrap();
// FIXME(stable_mir): add `read_ptr` to `Allocation`
assert_ne!(bool_id, char_id);
}
/// Collects all the constant assignments.
@@ -235,6 +223,7 @@ fn generate_input(path: &str) -> std::io::Result<()> {
file,
r#"
#![feature(core_intrinsics)]
#![expect(internal_features)]
use std::intrinsics::type_id;
static LEN: usize = 2;
@@ -254,11 +243,8 @@ fn generate_input(path: &str) -> std::io::Result<()> {
let _ptr = &BAR;
let _null_ptr: *const u8 = NULL;
let _tuple = TUPLE;
}}
fn check_type_id() {{
let _char_id = type_id::<char>();
let _bool_id = type_id::<bool>();
let _char_id = const {{ type_id::<char>() }};
let _bool_id = const {{ type_id::<bool>() }};
}}
pub fn main() {{