Skip to content

Commit 76e59c7

Browse files
committed
Auto merge of #115803 - RalfJung:const-eval, r=oli-obk
make the eval() functions on our const types return the resulting value This is a part of #115748 that's hopefully perf-neutral, and that does not depend on #115764.
2 parents 735bb7e + 8ef6b7a commit 76e59c7

File tree

22 files changed

+243
-351
lines changed

22 files changed

+243
-351
lines changed

compiler/rustc_codegen_cranelift/src/base.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -723,11 +723,8 @@ fn codegen_stmt<'tcx>(
723723
}
724724
Rvalue::Repeat(ref operand, times) => {
725725
let operand = codegen_operand(fx, operand);
726-
let times = fx
727-
.monomorphize(times)
728-
.eval(fx.tcx, ParamEnv::reveal_all())
729-
.try_to_bits(fx.tcx.data_layout.pointer_size)
730-
.unwrap();
726+
let times =
727+
fx.monomorphize(times).eval_target_usize(fx.tcx, ParamEnv::reveal_all());
731728
if operand.layout().size.bytes() == 0 {
732729
// Do nothing for ZST's
733730
} else if fx.clif_type(operand.layout().ty) == Some(types::I8) {

compiler/rustc_codegen_cranelift/src/constant.rs

+4-26
Original file line numberDiff line numberDiff line change
@@ -77,31 +77,9 @@ pub(crate) fn eval_mir_constant<'tcx>(
7777
fx: &FunctionCx<'_, '_, 'tcx>,
7878
constant: &Constant<'tcx>,
7979
) -> Option<(ConstValue<'tcx>, Ty<'tcx>)> {
80-
let constant_kind = fx.monomorphize(constant.literal);
81-
let uv = match constant_kind {
82-
ConstantKind::Ty(const_) => match const_.kind() {
83-
ty::ConstKind::Unevaluated(uv) => uv.expand(),
84-
ty::ConstKind::Value(val) => {
85-
return Some((fx.tcx.valtree_to_const_val((const_.ty(), val)), const_.ty()));
86-
}
87-
err => span_bug!(
88-
constant.span,
89-
"encountered bad ConstKind after monomorphizing: {:?}",
90-
err
91-
),
92-
},
93-
ConstantKind::Unevaluated(mir::UnevaluatedConst { def, .. }, _)
94-
if fx.tcx.is_static(def) =>
95-
{
96-
span_bug!(constant.span, "MIR constant refers to static");
97-
}
98-
ConstantKind::Unevaluated(uv, _) => uv,
99-
ConstantKind::Val(val, _) => return Some((val, constant_kind.ty())),
100-
};
101-
102-
let val = fx
103-
.tcx
104-
.const_eval_resolve(ty::ParamEnv::reveal_all(), uv, None)
80+
let cv = fx.monomorphize(constant.literal);
81+
let val = cv
82+
.eval(fx.tcx, ty::ParamEnv::reveal_all(), Some(constant.span))
10583
.map_err(|err| match err {
10684
ErrorHandled::Reported(_) => {
10785
fx.tcx.sess.span_err(constant.span, "erroneous constant encountered");
@@ -111,7 +89,7 @@ pub(crate) fn eval_mir_constant<'tcx>(
11189
}
11290
})
11391
.ok();
114-
val.map(|val| (val, constant_kind.ty()))
92+
val.map(|val| (val, cv.ty()))
11593
}
11694

11795
pub(crate) fn codegen_constant_operand<'tcx>(

compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -670,10 +670,8 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
670670
// avoiding collisions and will make the emitted type names shorter.
671671
let hash_short = tcx.with_stable_hashing_context(|mut hcx| {
672672
let mut hasher = StableHasher::new();
673-
let ct = ct.eval(tcx, ty::ParamEnv::reveal_all());
674-
hcx.while_hashing_spans(false, |hcx| {
675-
ct.to_valtree().hash_stable(hcx, &mut hasher)
676-
});
673+
let ct = ct.eval(tcx, ty::ParamEnv::reveal_all(), None).unwrap();
674+
hcx.while_hashing_spans(false, |hcx| ct.hash_stable(hcx, &mut hasher));
677675
hasher.finish::<Hash64>()
678676
});
679677

compiler/rustc_codegen_ssa/src/mir/constant.rs

+20-32
Original file line numberDiff line numberDiff line change
@@ -24,43 +24,31 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
2424
&self,
2525
constant: &mir::Constant<'tcx>,
2626
) -> Result<ConstValue<'tcx>, ErrorHandled> {
27-
let ct = self.monomorphize(constant.literal);
28-
let uv = match ct {
29-
mir::ConstantKind::Ty(ct) => match ct.kind() {
30-
ty::ConstKind::Unevaluated(uv) => uv.expand(),
31-
ty::ConstKind::Value(val) => {
32-
return Ok(self.cx.tcx().valtree_to_const_val((ct.ty(), val)));
27+
self.monomorphize(constant.literal)
28+
.eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), Some(constant.span))
29+
.map_err(|err| {
30+
match err {
31+
ErrorHandled::Reported(_) => {
32+
self.cx
33+
.tcx()
34+
.sess
35+
.emit_err(errors::ErroneousConstant { span: constant.span });
36+
}
37+
ErrorHandled::TooGeneric => {
38+
self.cx.tcx().sess.diagnostic().emit_bug(
39+
errors::PolymorphicConstantTooGeneric { span: constant.span },
40+
);
41+
}
3342
}
34-
err => span_bug!(
35-
constant.span,
36-
"encountered bad ConstKind after monomorphizing: {:?}",
37-
err
38-
),
39-
},
40-
mir::ConstantKind::Unevaluated(uv, _) => uv,
41-
mir::ConstantKind::Val(val, _) => return Ok(val),
42-
};
43-
44-
self.cx.tcx().const_eval_resolve(ty::ParamEnv::reveal_all(), uv, None).map_err(|err| {
45-
match err {
46-
ErrorHandled::Reported(_) => {
47-
self.cx.tcx().sess.emit_err(errors::ErroneousConstant { span: constant.span });
48-
}
49-
ErrorHandled::TooGeneric => {
50-
self.cx
51-
.tcx()
52-
.sess
53-
.diagnostic()
54-
.emit_bug(errors::PolymorphicConstantTooGeneric { span: constant.span });
55-
}
56-
}
57-
err
58-
})
43+
err
44+
})
5945
}
6046

6147
/// This is a convenience helper for `simd_shuffle_indices`. It has the precondition
6248
/// that the given `constant` is an `ConstantKind::Unevaluated` and must be convertible to
6349
/// a `ValTree`. If you want a more general version of this, talk to `wg-const-eval` on zulip.
50+
///
51+
/// Note that this function is cursed, since usually MIR consts should not be evaluated to valtrees!
6452
pub fn eval_unevaluated_mir_constant_to_valtree(
6553
&self,
6654
constant: &mir::Constant<'tcx>,
@@ -80,7 +68,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
8068
// `simd_shuffle` call without wrapping the constant argument in a `const {}` block, but
8169
// the user pass through arbitrary expressions.
8270
// FIXME(oli-obk): replace the magic const generic argument of `simd_shuffle` with a real
83-
// const generic.
71+
// const generic, and get rid of this entire function.
8472
other => span_bug!(constant.span, "{other:#?}"),
8573
};
8674
let uv = self.monomorphize(uv);

compiler/rustc_middle/src/mir/interpret/error.rs

+2
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ TrivialTypeTraversalAndLiftImpls! { ErrorHandled }
7171

7272
pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
7373
pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
74+
/// `Ok(None)` indicates the constant was fine, but the valtree couldn't be constructed.
75+
/// This is needed in `thir::pattern::lower_inline_const`.
7476
pub type EvalToValTreeResult<'tcx> = Result<Option<ValTree<'tcx>>, ErrorHandled>;
7577

7678
pub fn struct_error<'tcx>(

compiler/rustc_middle/src/mir/mod.rs

+74-80
Original file line numberDiff line numberDiff line change
@@ -2299,18 +2299,6 @@ impl<'tcx> ConstantKind<'tcx> {
22992299
}
23002300
}
23012301

2302-
#[inline]
2303-
pub fn try_to_value(self, tcx: TyCtxt<'tcx>) -> Option<interpret::ConstValue<'tcx>> {
2304-
match self {
2305-
ConstantKind::Ty(c) => match c.kind() {
2306-
ty::ConstKind::Value(valtree) => Some(tcx.valtree_to_const_val((c.ty(), valtree))),
2307-
_ => None,
2308-
},
2309-
ConstantKind::Val(val, _) => Some(val),
2310-
ConstantKind::Unevaluated(..) => None,
2311-
}
2312-
}
2313-
23142302
#[inline]
23152303
pub fn try_to_scalar(self) -> Option<Scalar> {
23162304
match self {
@@ -2342,37 +2330,59 @@ impl<'tcx> ConstantKind<'tcx> {
23422330
}
23432331

23442332
#[inline]
2345-
pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
2346-
match self {
2347-
Self::Ty(c) => {
2348-
if let Some(val) = c.try_eval_for_mir(tcx, param_env) {
2349-
match val {
2350-
Ok(val) => Self::Val(val, c.ty()),
2351-
Err(guar) => Self::Ty(ty::Const::new_error(tcx, guar, self.ty())),
2352-
}
2333+
pub fn eval(
2334+
self,
2335+
tcx: TyCtxt<'tcx>,
2336+
param_env: ty::ParamEnv<'tcx>,
2337+
span: Option<Span>,
2338+
) -> Result<interpret::ConstValue<'tcx>, ErrorHandled> {
2339+
let (uneval, param_env) = match self {
2340+
ConstantKind::Ty(c) => {
2341+
if let ty::ConstKind::Unevaluated(uneval) = c.kind() {
2342+
// Avoid the round-trip via valtree, evaluate directly to ConstValue.
2343+
let (param_env, uneval) = uneval.prepare_for_eval(tcx, param_env);
2344+
(uneval.expand(), param_env)
23532345
} else {
2354-
self
2346+
// It's already a valtree, or an error.
2347+
let val = c.eval(tcx, param_env, span)?;
2348+
return Ok(tcx.valtree_to_const_val((self.ty(), val)));
23552349
}
23562350
}
2357-
Self::Val(_, _) => self,
2358-
Self::Unevaluated(uneval, ty) => {
2359-
// FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
2360-
match tcx.const_eval_resolve(param_env, uneval, None) {
2361-
Ok(val) => Self::Val(val, ty),
2362-
Err(ErrorHandled::TooGeneric) => self,
2363-
Err(ErrorHandled::Reported(guar)) => {
2364-
Self::Ty(ty::Const::new_error(tcx, guar.into(), ty))
2365-
}
2366-
}
2351+
ConstantKind::Unevaluated(uneval, _) => (uneval, param_env),
2352+
ConstantKind::Val(val, _) => return Ok(val),
2353+
};
2354+
// FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
2355+
tcx.const_eval_resolve(param_env, uneval, span)
2356+
}
2357+
2358+
/// Normalizes the constant to a value or an error if possible.
2359+
#[inline]
2360+
pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
2361+
match self.eval(tcx, param_env, None) {
2362+
Ok(val) => Self::Val(val, self.ty()),
2363+
Err(ErrorHandled::Reported(guar)) => {
2364+
Self::Ty(ty::Const::new_error(tcx, guar.into(), self.ty()))
23672365
}
2366+
Err(ErrorHandled::TooGeneric) => self,
23682367
}
23692368
}
23702369

2371-
/// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
23722370
#[inline]
2373-
pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
2374-
self.try_eval_bits(tcx, param_env, ty)
2375-
.unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
2371+
pub fn try_eval_scalar(
2372+
self,
2373+
tcx: TyCtxt<'tcx>,
2374+
param_env: ty::ParamEnv<'tcx>,
2375+
) -> Option<Scalar> {
2376+
self.eval(tcx, param_env, None).ok()?.try_to_scalar()
2377+
}
2378+
2379+
#[inline]
2380+
pub fn try_eval_scalar_int(
2381+
self,
2382+
tcx: TyCtxt<'tcx>,
2383+
param_env: ty::ParamEnv<'tcx>,
2384+
) -> Option<ScalarInt> {
2385+
self.try_eval_scalar(tcx, param_env)?.try_to_int().ok()
23762386
}
23772387

23782388
#[inline]
@@ -2382,59 +2392,38 @@ impl<'tcx> ConstantKind<'tcx> {
23822392
param_env: ty::ParamEnv<'tcx>,
23832393
ty: Ty<'tcx>,
23842394
) -> Option<u128> {
2385-
match self {
2386-
Self::Ty(ct) => ct.try_eval_bits(tcx, param_env, ty),
2387-
Self::Val(val, t) => {
2388-
assert_eq!(*t, ty);
2389-
let size =
2390-
tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
2391-
val.try_to_bits(size)
2392-
}
2393-
Self::Unevaluated(uneval, ty) => {
2394-
match tcx.const_eval_resolve(param_env, *uneval, None) {
2395-
Ok(val) => {
2396-
let size = tcx
2397-
.layout_of(param_env.with_reveal_all_normalized(tcx).and(*ty))
2398-
.ok()?
2399-
.size;
2400-
val.try_to_bits(size)
2401-
}
2402-
Err(_) => None,
2403-
}
2404-
}
2405-
}
2395+
let int = self.try_eval_scalar_int(tcx, param_env)?;
2396+
assert_eq!(self.ty(), ty);
2397+
let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
2398+
int.to_bits(size).ok()
24062399
}
24072400

2401+
/// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
24082402
#[inline]
2409-
pub fn try_eval_bool(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<bool> {
2410-
match self {
2411-
Self::Ty(ct) => ct.try_eval_bool(tcx, param_env),
2412-
Self::Val(val, _) => val.try_to_bool(),
2413-
Self::Unevaluated(uneval, _) => {
2414-
match tcx.const_eval_resolve(param_env, *uneval, None) {
2415-
Ok(val) => val.try_to_bool(),
2416-
Err(_) => None,
2417-
}
2418-
}
2419-
}
2403+
pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
2404+
self.try_eval_bits(tcx, param_env, ty)
2405+
.unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
24202406
}
24212407

24222408
#[inline]
24232409
pub fn try_eval_target_usize(
2424-
&self,
2410+
self,
24252411
tcx: TyCtxt<'tcx>,
24262412
param_env: ty::ParamEnv<'tcx>,
24272413
) -> Option<u64> {
2428-
match self {
2429-
Self::Ty(ct) => ct.try_eval_target_usize(tcx, param_env),
2430-
Self::Val(val, _) => val.try_to_target_usize(tcx),
2431-
Self::Unevaluated(uneval, _) => {
2432-
match tcx.const_eval_resolve(param_env, *uneval, None) {
2433-
Ok(val) => val.try_to_target_usize(tcx),
2434-
Err(_) => None,
2435-
}
2436-
}
2437-
}
2414+
self.try_eval_scalar_int(tcx, param_env)?.try_to_target_usize(tcx).ok()
2415+
}
2416+
2417+
#[inline]
2418+
/// Panics if the value cannot be evaluated or doesn't contain a valid `usize`.
2419+
pub fn eval_target_usize(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> u64 {
2420+
self.try_eval_target_usize(tcx, param_env)
2421+
.unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
2422+
}
2423+
2424+
#[inline]
2425+
pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<bool> {
2426+
self.try_eval_scalar_int(tcx, param_env)?.try_into().ok()
24382427
}
24392428

24402429
#[inline]
@@ -2576,7 +2565,7 @@ impl<'tcx> ConstantKind<'tcx> {
25762565
}
25772566
}
25782567

2579-
pub fn from_const(c: ty::Const<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
2568+
pub fn from_ty_const(c: ty::Const<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
25802569
match c.kind() {
25812570
ty::ConstKind::Value(valtree) => {
25822571
let const_val = tcx.valtree_to_const_val((c.ty(), valtree));
@@ -2610,6 +2599,11 @@ impl<'tcx> UnevaluatedConst<'tcx> {
26102599
pub fn new(def: DefId, args: GenericArgsRef<'tcx>) -> UnevaluatedConst<'tcx> {
26112600
UnevaluatedConst { def, args, promoted: Default::default() }
26122601
}
2602+
2603+
#[inline]
2604+
pub fn from_instance(instance: ty::Instance<'tcx>) -> Self {
2605+
UnevaluatedConst::new(instance.def_id(), instance.args)
2606+
}
26132607
}
26142608

26152609
/// A collection of projections into user types.
@@ -2884,7 +2878,7 @@ fn pretty_print_const_value<'tcx>(
28842878
}
28852879
}
28862880
(ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => {
2887-
let n = n.try_to_bits(tcx.data_layout.pointer_size).unwrap();
2881+
let n = n.try_to_target_usize(tcx).unwrap();
28882882
// cast is ok because we already checked for pointer size (32 or 64 bit) above
28892883
let range = AllocRange { start: offset, size: Size::from_bytes(n) };
28902884
let byte_str = alloc.inner().get_bytes_strip_provenance(&tcx, range).unwrap();

0 commit comments

Comments
 (0)