Skip to content

Commit a5e9784

Browse files
committed
Auto merge of #142839 - oli-obk:denullarification, r=<try>
Stop backends from needing to support nullary intrinsics And then remove our infrastructure special casing them. Further improvements can now be done to them by avoiding the intermediate ConstValue step, but let's leave that to follow up work r? `@ghost` wanna see perf first
2 parents ea34650 + a44843e commit a5e9784

File tree

9 files changed

+94
-156
lines changed

9 files changed

+94
-156
lines changed

compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -812,21 +812,6 @@ fn codegen_regular_intrinsic_call<'tcx>(
812812
dest.write_cvalue(fx, val);
813813
}
814814

815-
sym::needs_drop | sym::type_id | sym::type_name | sym::variant_count => {
816-
intrinsic_args!(fx, args => (); intrinsic);
817-
818-
let const_val = fx
819-
.tcx
820-
.const_eval_instance(
821-
ty::TypingEnv::fully_monomorphized(),
822-
instance,
823-
source_info.span,
824-
)
825-
.unwrap();
826-
let val = crate::constant::codegen_const_value(fx, const_val, ret.layout().ty);
827-
ret.write_cvalue(fx, val);
828-
}
829-
830815
sym::ptr_offset_from | sym::ptr_offset_from_unsigned => {
831816
intrinsic_args!(fx, args => (ptr, base); intrinsic);
832817
let ptr = ptr.load_scalar(fx);

compiler/rustc_codegen_ssa/src/mir/intrinsic.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
150150
}
151151
value
152152
}
153-
sym::needs_drop | sym::type_id | sym::type_name | sym::variant_count => {
154-
let value = bx.tcx().const_eval_instance(bx.typing_env(), instance, span).unwrap();
155-
OperandRef::from_const(bx, value, result.layout.ty).immediate_or_packed_pair(bx)
156-
}
157153
sym::arith_offset => {
158154
let ty = fn_args.type_at(0);
159155
let layout = bx.layout_of(ty);

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use crate::const_eval::CheckAlignment;
2020
use crate::interpret::{
2121
CtfeValidationMode, GlobalId, Immediate, InternKind, InternResult, InterpCx, InterpErrorKind,
2222
InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, StackPopCleanup, create_static_alloc,
23-
eval_nullary_intrinsic, intern_const_alloc_recursive, interp_ok, throw_exhaust,
23+
intern_const_alloc_recursive, interp_ok, throw_exhaust,
2424
};
2525
use crate::{CTRL_C_RECEIVED, errors};
2626

@@ -280,34 +280,6 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
280280
tcx: TyCtxt<'tcx>,
281281
key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
282282
) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
283-
// We call `const_eval` for zero arg intrinsics, too, in order to cache their value.
284-
// Catch such calls and evaluate them instead of trying to load a constant's MIR.
285-
if let ty::InstanceKind::Intrinsic(def_id) = key.value.instance.def {
286-
let ty = key.value.instance.ty(tcx, key.typing_env);
287-
let ty::FnDef(_, args) = ty.kind() else {
288-
bug!("intrinsic with type {:?}", ty);
289-
};
290-
return eval_nullary_intrinsic(tcx, key.typing_env, def_id, args).report_err().map_err(
291-
|error| {
292-
let span = tcx.def_span(def_id);
293-
294-
// FIXME(oli-obk): why don't we have any tests for this code path?
295-
super::report(
296-
tcx,
297-
error.into_kind(),
298-
span,
299-
|| (span, vec![]),
300-
|diag, span, _| {
301-
diag.span_label(
302-
span,
303-
crate::fluent_generated::const_eval_nullary_intrinsic_fail,
304-
);
305-
},
306-
)
307-
},
308-
);
309-
}
310-
311283
tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key))
312284
}
313285

compiler/rustc_const_eval/src/interpret/intrinsics.rs

Lines changed: 72 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,18 @@ use std::assert_matches::assert_matches;
66

77
use rustc_abi::Size;
88
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
9-
use rustc_hir::def_id::DefId;
109
use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic};
1110
use rustc_middle::ty::layout::{LayoutOf as _, TyAndLayout, ValidityRequirement};
12-
use rustc_middle::ty::{GenericArgsRef, Ty, TyCtxt};
11+
use rustc_middle::ty::{Ty, TyCtxt};
1312
use rustc_middle::{bug, ty};
1413
use rustc_span::{Symbol, sym};
1514
use tracing::trace;
1615

1716
use super::memory::MemoryKind;
1817
use super::util::ensure_monomorphic_enough;
1918
use super::{
20-
Allocation, CheckInAllocMsg, ConstAllocation, GlobalId, ImmTy, InterpCx, InterpResult, Machine,
21-
OpTy, PlaceTy, Pointer, PointerArithmetic, Provenance, Scalar, err_inval, err_ub_custom,
19+
Allocation, CheckInAllocMsg, ConstAllocation, ImmTy, InterpCx, InterpResult, Machine, OpTy,
20+
PlaceTy, Pointer, PointerArithmetic, Provenance, Scalar, err_inval, err_ub_custom,
2221
err_unsup_format, interp_ok, throw_inval, throw_ub_custom, throw_ub_format,
2322
};
2423
use crate::fluent_generated as fluent;
@@ -30,73 +29,6 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAll
3029
tcx.mk_const_alloc(alloc)
3130
}
3231

33-
/// The logic for all nullary intrinsics is implemented here. These intrinsics don't get evaluated
34-
/// inside an `InterpCx` and instead have their value computed directly from rustc internal info.
35-
pub(crate) fn eval_nullary_intrinsic<'tcx>(
36-
tcx: TyCtxt<'tcx>,
37-
typing_env: ty::TypingEnv<'tcx>,
38-
def_id: DefId,
39-
args: GenericArgsRef<'tcx>,
40-
) -> InterpResult<'tcx, ConstValue<'tcx>> {
41-
let tp_ty = args.type_at(0);
42-
let name = tcx.item_name(def_id);
43-
interp_ok(match name {
44-
sym::type_name => {
45-
ensure_monomorphic_enough(tcx, tp_ty)?;
46-
let alloc = alloc_type_name(tcx, tp_ty);
47-
ConstValue::Slice { data: alloc, meta: alloc.inner().size().bytes() }
48-
}
49-
sym::needs_drop => {
50-
ensure_monomorphic_enough(tcx, tp_ty)?;
51-
ConstValue::from_bool(tp_ty.needs_drop(tcx, typing_env))
52-
}
53-
sym::type_id => {
54-
ensure_monomorphic_enough(tcx, tp_ty)?;
55-
ConstValue::from_u128(tcx.type_id_hash(tp_ty).as_u128())
56-
}
57-
sym::variant_count => match match tp_ty.kind() {
58-
// Pattern types have the same number of variants as their base type.
59-
// Even if we restrict e.g. which variants are valid, the variants are essentially just uninhabited.
60-
// And `Result<(), !>` still has two variants according to `variant_count`.
61-
ty::Pat(base, _) => *base,
62-
_ => tp_ty,
63-
}
64-
.kind()
65-
{
66-
// Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough.
67-
ty::Adt(adt, _) => ConstValue::from_target_usize(adt.variants().len() as u64, &tcx),
68-
ty::Alias(..) | ty::Param(_) | ty::Placeholder(_) | ty::Infer(_) => {
69-
throw_inval!(TooGeneric)
70-
}
71-
ty::Pat(..) => unreachable!(),
72-
ty::Bound(_, _) => bug!("bound ty during ctfe"),
73-
ty::Bool
74-
| ty::Char
75-
| ty::Int(_)
76-
| ty::Uint(_)
77-
| ty::Float(_)
78-
| ty::Foreign(_)
79-
| ty::Str
80-
| ty::Array(_, _)
81-
| ty::Slice(_)
82-
| ty::RawPtr(_, _)
83-
| ty::Ref(_, _, _)
84-
| ty::FnDef(_, _)
85-
| ty::FnPtr(..)
86-
| ty::Dynamic(_, _, _)
87-
| ty::Closure(_, _)
88-
| ty::CoroutineClosure(_, _)
89-
| ty::Coroutine(_, _)
90-
| ty::CoroutineWitness(..)
91-
| ty::UnsafeBinder(_)
92-
| ty::Never
93-
| ty::Tuple(_)
94-
| ty::Error(_) => ConstValue::from_target_usize(0u64, &tcx),
95-
},
96-
other => bug!("`{}` is not a zero arg intrinsic", other),
97-
})
98-
}
99-
10032
impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
10133
/// Returns `true` if emulation happened.
10234
/// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own
@@ -110,8 +42,77 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
11042
) -> InterpResult<'tcx, bool> {
11143
let instance_args = instance.args;
11244
let intrinsic_name = self.tcx.item_name(instance.def_id());
45+
let tcx = self.tcx.tcx;
11346

11447
match intrinsic_name {
48+
sym::type_name => {
49+
let tp_ty = instance.args.type_at(0);
50+
ensure_monomorphic_enough(tcx, tp_ty)?;
51+
let alloc = alloc_type_name(tcx, tp_ty);
52+
let val = ConstValue::Slice { data: alloc, meta: alloc.inner().size().bytes() };
53+
let val = self.const_val_to_op(val, dest.layout.ty, Some(dest.layout))?;
54+
self.copy_op(&val, dest)?;
55+
}
56+
sym::needs_drop => {
57+
let tp_ty = instance.args.type_at(0);
58+
ensure_monomorphic_enough(tcx, tp_ty)?;
59+
let val = ConstValue::from_bool(tp_ty.needs_drop(tcx, self.typing_env));
60+
let val = self.const_val_to_op(val, tcx.types.bool, Some(dest.layout))?;
61+
self.copy_op(&val, dest)?;
62+
}
63+
sym::type_id => {
64+
let tp_ty = instance.args.type_at(0);
65+
ensure_monomorphic_enough(tcx, tp_ty)?;
66+
let val = ConstValue::from_u128(tcx.type_id_hash(tp_ty).as_u128());
67+
let val = self.const_val_to_op(val, dest.layout.ty, Some(dest.layout))?;
68+
self.copy_op(&val, dest)?;
69+
}
70+
sym::variant_count => {
71+
let tp_ty = instance.args.type_at(0);
72+
let ty = match tp_ty.kind() {
73+
// Pattern types have the same number of variants as their base type.
74+
// Even if we restrict e.g. which variants are valid, the variants are essentially just uninhabited.
75+
// And `Result<(), !>` still has two variants according to `variant_count`.
76+
ty::Pat(base, _) => *base,
77+
_ => tp_ty,
78+
};
79+
let val = match ty.kind() {
80+
// Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough.
81+
ty::Adt(adt, _) => {
82+
ConstValue::from_target_usize(adt.variants().len() as u64, &tcx)
83+
}
84+
ty::Alias(..) | ty::Param(_) | ty::Placeholder(_) | ty::Infer(_) => {
85+
throw_inval!(TooGeneric)
86+
}
87+
ty::Pat(..) => unreachable!(),
88+
ty::Bound(_, _) => bug!("bound ty during ctfe"),
89+
ty::Bool
90+
| ty::Char
91+
| ty::Int(_)
92+
| ty::Uint(_)
93+
| ty::Float(_)
94+
| ty::Foreign(_)
95+
| ty::Str
96+
| ty::Array(_, _)
97+
| ty::Slice(_)
98+
| ty::RawPtr(_, _)
99+
| ty::Ref(_, _, _)
100+
| ty::FnDef(_, _)
101+
| ty::FnPtr(..)
102+
| ty::Dynamic(_, _, _)
103+
| ty::Closure(_, _)
104+
| ty::CoroutineClosure(_, _)
105+
| ty::Coroutine(_, _)
106+
| ty::CoroutineWitness(..)
107+
| ty::UnsafeBinder(_)
108+
| ty::Never
109+
| ty::Tuple(_)
110+
| ty::Error(_) => ConstValue::from_target_usize(0u64, &tcx),
111+
};
112+
let val = self.const_val_to_op(val, dest.layout.ty, Some(dest.layout))?;
113+
self.copy_op(&val, dest)?;
114+
}
115+
115116
sym::caller_location => {
116117
let span = self.find_closest_untracked_caller_location();
117118
let val = self.tcx.span_as_caller_location(span);
@@ -137,21 +138,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
137138
self.write_scalar(Scalar::from_target_usize(result, self), dest)?;
138139
}
139140

140-
sym::needs_drop | sym::type_id | sym::type_name | sym::variant_count => {
141-
let gid = GlobalId { instance, promoted: None };
142-
let ty = self
143-
.tcx
144-
.fn_sig(instance.def_id())
145-
.instantiate(self.tcx.tcx, instance.args)
146-
.output()
147-
.no_bound_vars()
148-
.unwrap();
149-
let val = self
150-
.ctfe_query(|tcx| tcx.const_eval_global_id(self.typing_env, gid, tcx.span))?;
151-
let val = self.const_val_to_op(val, ty, Some(dest.layout))?;
152-
self.copy_op(&val, dest)?;
153-
}
154-
155141
sym::fadd_algebraic
156142
| sym::fsub_algebraic
157143
| sym::fmul_algebraic

compiler/rustc_const_eval/src/interpret/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ pub use self::intern::{
2929
HasStaticRootDefId, InternKind, InternResult, intern_const_alloc_for_constprop,
3030
intern_const_alloc_recursive,
3131
};
32-
pub(crate) use self::intrinsics::eval_nullary_intrinsic;
3332
pub use self::machine::{AllocMap, Machine, MayLeak, ReturnAction, compile_time_machine};
3433
pub use self::memory::{AllocInfo, AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
3534
use self::operand::Operand;

library/core/src/any.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,7 @@ impl TypeId {
742742
#[stable(feature = "rust1", since = "1.0.0")]
743743
#[rustc_const_unstable(feature = "const_type_id", issue = "77125")]
744744
pub const fn of<T: ?Sized + 'static>() -> TypeId {
745-
let t: u128 = intrinsics::type_id::<T>();
745+
let t: u128 = const { intrinsics::type_id::<T>() };
746746
let t1 = (t >> 64) as u64;
747747
let t2 = t as u64;
748748

@@ -824,7 +824,7 @@ impl fmt::Debug for TypeId {
824824
#[stable(feature = "type_name", since = "1.38.0")]
825825
#[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
826826
pub const fn type_name<T: ?Sized>() -> &'static str {
827-
intrinsics::type_name::<T>()
827+
const { intrinsics::type_name::<T>() }
828828
}
829829

830830
/// Returns the type name of the pointed-to value as a string slice.

library/core/src/intrinsics/mod.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -839,10 +839,10 @@ pub const unsafe fn transmute_unchecked<Src, Dst>(src: Src) -> Dst;
839839
/// If the actual type neither requires drop glue nor implements
840840
/// `Copy`, then the return value of this function is unspecified.
841841
///
842-
/// Note that, unlike most intrinsics, this is safe to call;
843-
/// it does not require an `unsafe` block.
844-
/// Therefore, implementations must not require the user to uphold
845-
/// any safety invariants.
842+
/// Note that, unlike most intrinsics, this can only be called at compile-time
843+
/// as backends do not have an implementation for it. The only caller (its
844+
/// stable counterpart), wraps this intrinsic call in a `const` block so that
845+
/// backends only see an evaluated constant.
846846
///
847847
/// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop).
848848
#[rustc_intrinsic_const_stable_indirect]
@@ -2655,10 +2655,10 @@ pub const fn align_of<T>() -> usize;
26552655
/// Returns the number of variants of the type `T` cast to a `usize`;
26562656
/// if `T` has no variants, returns `0`. Uninhabited variants will be counted.
26572657
///
2658-
/// Note that, unlike most intrinsics, this is safe to call;
2659-
/// it does not require an `unsafe` block.
2660-
/// Therefore, implementations must not require the user to uphold
2661-
/// any safety invariants.
2658+
/// Note that, unlike most intrinsics, this can only be called at compile-time
2659+
/// as backends do not have an implementation for it. The only caller (its
2660+
/// stable counterpart), wraps this intrinsic call in a `const` block so that
2661+
/// backends only see an evaluated constant.
26622662
///
26632663
/// The to-be-stabilized version of this intrinsic is [`crate::mem::variant_count`].
26642664
#[rustc_nounwind]
@@ -2694,10 +2694,10 @@ pub const unsafe fn align_of_val<T: ?Sized>(ptr: *const T) -> usize;
26942694

26952695
/// Gets a static string slice containing the name of a type.
26962696
///
2697-
/// Note that, unlike most intrinsics, this is safe to call;
2698-
/// it does not require an `unsafe` block.
2699-
/// Therefore, implementations must not require the user to uphold
2700-
/// any safety invariants.
2697+
/// Note that, unlike most intrinsics, this can only be called at compile-time
2698+
/// as backends do not have an implementation for it. The only caller (its
2699+
/// stable counterpart), wraps this intrinsic call in a `const` block so that
2700+
/// backends only see an evaluated constant.
27012701
///
27022702
/// The stabilized version of this intrinsic is [`core::any::type_name`].
27032703
#[rustc_nounwind]
@@ -2709,10 +2709,10 @@ pub const fn type_name<T: ?Sized>() -> &'static str;
27092709
/// function will return the same value for a type regardless of whichever
27102710
/// crate it is invoked in.
27112711
///
2712-
/// Note that, unlike most intrinsics, this is safe to call;
2713-
/// it does not require an `unsafe` block.
2714-
/// Therefore, implementations must not require the user to uphold
2715-
/// any safety invariants.
2712+
/// Note that, unlike most intrinsics, this can only be called at compile-time
2713+
/// as backends do not have an implementation for it. The only caller (its
2714+
/// stable counterpart), wraps this intrinsic call in a `const` block so that
2715+
/// backends only see an evaluated constant.
27162716
///
27172717
/// The stabilized version of this intrinsic is [`core::any::TypeId::of`].
27182718
#[rustc_nounwind]

library/core/src/mem/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@ pub const unsafe fn align_of_val_raw<T: ?Sized>(val: *const T) -> usize {
616616
#[rustc_const_stable(feature = "const_mem_needs_drop", since = "1.36.0")]
617617
#[rustc_diagnostic_item = "needs_drop"]
618618
pub const fn needs_drop<T: ?Sized>() -> bool {
619-
intrinsics::needs_drop::<T>()
619+
const { intrinsics::needs_drop::<T>() }
620620
}
621621

622622
/// 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> {
12151215
#[rustc_const_unstable(feature = "variant_count", issue = "73662")]
12161216
#[rustc_diagnostic_item = "mem_variant_count"]
12171217
pub const fn variant_count<T>() -> usize {
1218-
intrinsics::variant_count::<T>()
1218+
const { intrinsics::variant_count::<T>() }
12191219
}
12201220

12211221
/// Provides associated constants for various useful properties of types,

tests/ui/consts/const-fn-type-name.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#![allow(dead_code)]
66

77
const fn type_name_wrapper<T>(_: &T) -> &'static str {
8-
core::intrinsics::type_name::<T>()
8+
const { core::intrinsics::type_name::<T>() }
99
}
1010

1111
struct Struct<TA, TB, TC> {

0 commit comments

Comments
 (0)