Skip to content

Commit ad3b725

Browse files
committed
Auto merge of #142839 - oli-obk:denullarification, r=RalfJung,celinval
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? `@RalfJung`
2 parents f191420 + d0bb9a7 commit ad3b725

File tree

15 files changed

+164
-208
lines changed

15 files changed

+164
-208
lines changed

compiler/rustc_codegen_cranelift/example/mini_core.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,7 @@ pub mod intrinsics {
660660
#[rustc_intrinsic]
661661
pub unsafe fn ctlz_nonzero<T>(x: T) -> u32;
662662
#[rustc_intrinsic]
663-
pub fn needs_drop<T: ?::Sized>() -> bool;
663+
pub const fn needs_drop<T: ?::Sized>() -> bool;
664664
#[rustc_intrinsic]
665665
pub fn bitreverse<T>(x: T) -> T;
666666
#[rustc_intrinsic]

compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
1-
#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local, repr_simd)]
1+
#![feature(
2+
no_core,
3+
lang_items,
4+
never_type,
5+
linkage,
6+
extern_types,
7+
thread_local,
8+
repr_simd,
9+
rustc_private
10+
)]
211
#![no_core]
312
#![allow(dead_code, non_camel_case_types, internal_features)]
413

@@ -207,10 +216,14 @@ fn main() {
207216
assert_eq!(intrinsics::align_of::<u16>() as u8, 2);
208217
assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8);
209218

210-
assert!(!intrinsics::needs_drop::<u8>());
211-
assert!(!intrinsics::needs_drop::<[u8]>());
212-
assert!(intrinsics::needs_drop::<NoisyDrop>());
213-
assert!(intrinsics::needs_drop::<NoisyDropUnsized>());
219+
let u8_needs_drop = const { intrinsics::needs_drop::<u8>() };
220+
assert!(!u8_needs_drop);
221+
let slice_needs_drop = const { intrinsics::needs_drop::<[u8]>() };
222+
assert!(!slice_needs_drop);
223+
let noisy_drop = const { intrinsics::needs_drop::<NoisyDrop>() };
224+
assert!(noisy_drop);
225+
let noisy_unsized_drop = const { intrinsics::needs_drop::<NoisyDropUnsized>() };
226+
assert!(noisy_unsized_drop);
214227

215228
Unique { pointer: NonNull(1 as *mut &str), _marker: PhantomData } as Unique<dyn SomeTrait>;
216229

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_gcc/example/mini_core_hello_world.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
)]
77
#![no_core]
88
#![allow(dead_code, internal_features, non_camel_case_types)]
9+
#![rustfmt::skip]
910

1011
extern crate mini_core;
1112

@@ -197,10 +198,10 @@ fn main() {
197198
assert_eq!(intrinsics::align_of::<u16>() as u8, 2);
198199
assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8);
199200

200-
assert!(!intrinsics::needs_drop::<u8>());
201-
assert!(!intrinsics::needs_drop::<[u8]>());
202-
assert!(intrinsics::needs_drop::<NoisyDrop>());
203-
assert!(intrinsics::needs_drop::<NoisyDropUnsized>());
201+
assert!(!const { intrinsics::needs_drop::<u8>() });
202+
assert!(!const { intrinsics::needs_drop::<[u8]>() });
203+
assert!(const { intrinsics::needs_drop::<NoisyDrop>() });
204+
assert!(const { intrinsics::needs_drop::<NoisyDropUnsized>() });
204205

205206
Unique {
206207
pointer: 0 as *const &str,

compiler/rustc_codegen_ssa/src/mir/intrinsic.rs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use rustc_abi::WrappingRange;
2-
use rustc_middle::bug;
32
use rustc_middle::mir::SourceInfo;
43
use rustc_middle::ty::{self, Ty, TyCtxt};
4+
use rustc_middle::{bug, span_bug};
55
use rustc_session::config::OptLevel;
66
use rustc_span::sym;
77

@@ -98,6 +98,27 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
9898
discr.to_atomic_ordering()
9999
};
100100

101+
if args.is_empty() {
102+
match name {
103+
sym::abort
104+
| sym::unreachable
105+
| sym::cold_path
106+
| sym::breakpoint
107+
| sym::assert_zero_valid
108+
| sym::assert_mem_uninitialized_valid
109+
| sym::assert_inhabited
110+
| sym::ub_checks
111+
| sym::contract_checks
112+
| sym::atomic_fence
113+
| sym::atomic_singlethreadfence
114+
| sym::caller_location => {}
115+
_ => {
116+
span_bug!(span, "nullary intrinsic {name} must either be in a const block or explicitly opted out because it is inherently a runtime intrinsic
117+
");
118+
}
119+
}
120+
}
121+
101122
let llval = match name {
102123
sym::abort => {
103124
bx.abort();
@@ -150,10 +171,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
150171
}
151172
value
152173
}
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-
}
157174
sym::arith_offset => {
158175
let ty = fn_args.type_at(0);
159176
let layout = bx.layout_of(ty);

compiler/rustc_const_eval/messages.ftl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,9 +263,6 @@ const_eval_non_const_try_block_from_output =
263263
const_eval_not_enough_caller_args =
264264
calling a function with fewer arguments than it requires
265265
266-
const_eval_nullary_intrinsic_fail =
267-
could not evaluate nullary intrinsic
268-
269266
const_eval_offset_from_different_allocations =
270267
`{$name}` called on two different pointers that are not both derived from the same allocation
271268
const_eval_offset_from_out_of_bounds =

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::{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;

0 commit comments

Comments
 (0)