Skip to content

Commit 8f6f09f

Browse files
committed
interpret: more consistently use ImmTy in operators and casts
1 parent 4f22692 commit 8f6f09f

File tree

21 files changed

+200
-188
lines changed

21 files changed

+200
-188
lines changed

compiler/rustc_const_eval/src/const_eval/machine.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use rustc_hir::{LangItem, CRATE_HIR_ID};
33
use rustc_middle::mir;
44
use rustc_middle::mir::interpret::PointerArithmetic;
55
use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout};
6-
use rustc_middle::ty::{self, Ty, TyCtxt};
6+
use rustc_middle::ty::{self, TyCtxt};
77
use rustc_session::lint::builtin::INVALID_ALIGNMENT;
88
use std::borrow::Borrow;
99
use std::hash::Hash;
@@ -596,7 +596,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
596596
_bin_op: mir::BinOp,
597597
_left: &ImmTy<'tcx>,
598598
_right: &ImmTy<'tcx>,
599-
) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
599+
) -> InterpResult<'tcx, (ImmTy<'tcx>, bool)> {
600600
throw_unsup_format!("pointer arithmetic or comparison is not supported at compile-time");
601601
}
602602

compiler/rustc_const_eval/src/interpret/cast.rs

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -34,31 +34,31 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
3434
CastKind::PointerExposeAddress => {
3535
let src = self.read_immediate(src)?;
3636
let res = self.pointer_expose_address_cast(&src, cast_ty)?;
37-
self.write_immediate(res, dest)?;
37+
self.write_immediate(*res, dest)?;
3838
}
3939

4040
CastKind::PointerFromExposedAddress => {
4141
let src = self.read_immediate(src)?;
4242
let res = self.pointer_from_exposed_address_cast(&src, cast_ty)?;
43-
self.write_immediate(res, dest)?;
43+
self.write_immediate(*res, dest)?;
4444
}
4545

4646
CastKind::IntToInt | CastKind::IntToFloat => {
4747
let src = self.read_immediate(src)?;
4848
let res = self.int_to_int_or_float(&src, cast_ty)?;
49-
self.write_immediate(res, dest)?;
49+
self.write_immediate(*res, dest)?;
5050
}
5151

5252
CastKind::FloatToFloat | CastKind::FloatToInt => {
5353
let src = self.read_immediate(src)?;
5454
let res = self.float_to_float_or_int(&src, cast_ty)?;
55-
self.write_immediate(res, dest)?;
55+
self.write_immediate(*res, dest)?;
5656
}
5757

5858
CastKind::FnPtrToPtr | CastKind::PtrToPtr => {
5959
let src = self.read_immediate(src)?;
6060
let res = self.ptr_to_ptr(&src, cast_ty)?;
61-
self.write_immediate(res, dest)?;
61+
self.write_immediate(*res, dest)?;
6262
}
6363

6464
CastKind::PointerCoercion(
@@ -165,55 +165,57 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
165165
&self,
166166
src: &ImmTy<'tcx, M::Provenance>,
167167
cast_ty: Ty<'tcx>,
168-
) -> InterpResult<'tcx, Immediate<M::Provenance>> {
168+
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
169169
assert!(src.layout.ty.is_integral() || src.layout.ty.is_char() || src.layout.ty.is_bool());
170170
assert!(cast_ty.is_floating_point() || cast_ty.is_integral() || cast_ty.is_char());
171171

172-
Ok(self.cast_from_int_like(src.to_scalar(), src.layout, cast_ty)?.into())
172+
let layout = self.layout_of(cast_ty)?;
173+
Ok(ImmTy::from_scalar(
174+
self.cast_from_int_like(src.to_scalar(), src.layout, cast_ty)?,
175+
layout,
176+
))
173177
}
174178

175179
/// Handles 'FloatToFloat' and 'FloatToInt' casts.
176180
pub fn float_to_float_or_int(
177181
&self,
178182
src: &ImmTy<'tcx, M::Provenance>,
179183
cast_ty: Ty<'tcx>,
180-
) -> InterpResult<'tcx, Immediate<M::Provenance>> {
184+
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
181185
use rustc_type_ir::sty::TyKind::*;
182186

183-
match src.layout.ty.kind() {
187+
let layout = self.layout_of(cast_ty)?;
188+
let val = match src.layout.ty.kind() {
184189
// Floating point
185-
Float(FloatTy::F32) => {
186-
return Ok(self.cast_from_float(src.to_scalar().to_f32()?, cast_ty).into());
187-
}
188-
Float(FloatTy::F64) => {
189-
return Ok(self.cast_from_float(src.to_scalar().to_f64()?, cast_ty).into());
190-
}
190+
Float(FloatTy::F32) => self.cast_from_float(src.to_scalar().to_f32()?, cast_ty),
191+
Float(FloatTy::F64) => self.cast_from_float(src.to_scalar().to_f64()?, cast_ty),
191192
_ => {
192193
bug!("Can't cast 'Float' type into {:?}", cast_ty);
193194
}
194-
}
195+
};
196+
Ok(ImmTy::from_scalar(val, layout))
195197
}
196198

197199
/// Handles 'FnPtrToPtr' and 'PtrToPtr' casts.
198200
pub fn ptr_to_ptr(
199201
&self,
200202
src: &ImmTy<'tcx, M::Provenance>,
201203
cast_ty: Ty<'tcx>,
202-
) -> InterpResult<'tcx, Immediate<M::Provenance>> {
204+
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
203205
assert!(src.layout.ty.is_any_ptr());
204206
assert!(cast_ty.is_unsafe_ptr());
205207
// Handle casting any ptr to raw ptr (might be a fat ptr).
206208
let dest_layout = self.layout_of(cast_ty)?;
207209
if dest_layout.size == src.layout.size {
208210
// Thin or fat pointer that just hast the ptr kind of target type changed.
209-
return Ok(**src);
211+
return Ok(ImmTy::from_immediate(**src, dest_layout));
210212
} else {
211213
// Casting the metadata away from a fat ptr.
212214
assert_eq!(src.layout.size, 2 * self.pointer_size());
213215
assert_eq!(dest_layout.size, self.pointer_size());
214216
assert!(src.layout.ty.is_unsafe_ptr());
215217
return match **src {
216-
Immediate::ScalarPair(data, _) => Ok(data.into()),
218+
Immediate::ScalarPair(data, _) => Ok(ImmTy::from_scalar(data, dest_layout)),
217219
Immediate::Scalar(..) => span_bug!(
218220
self.cur_span(),
219221
"{:?} input to a fat-to-thin cast ({:?} -> {:?})",
@@ -230,7 +232,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
230232
&mut self,
231233
src: &ImmTy<'tcx, M::Provenance>,
232234
cast_ty: Ty<'tcx>,
233-
) -> InterpResult<'tcx, Immediate<M::Provenance>> {
235+
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
234236
assert_matches!(src.layout.ty.kind(), ty::RawPtr(_) | ty::FnPtr(_));
235237
assert!(cast_ty.is_integral());
236238

@@ -240,14 +242,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
240242
Ok(ptr) => M::expose_ptr(self, ptr)?,
241243
Err(_) => {} // Do nothing, exposing an invalid pointer (`None` provenance) is a NOP.
242244
};
243-
Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into())
245+
let layout = self.layout_of(cast_ty)?;
246+
Ok(ImmTy::from_scalar(self.cast_from_int_like(scalar, src.layout, cast_ty)?, layout))
244247
}
245248

246249
pub fn pointer_from_exposed_address_cast(
247250
&self,
248251
src: &ImmTy<'tcx, M::Provenance>,
249252
cast_ty: Ty<'tcx>,
250-
) -> InterpResult<'tcx, Immediate<M::Provenance>> {
253+
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
251254
assert!(src.layout.ty.is_integral());
252255
assert_matches!(cast_ty.kind(), ty::RawPtr(_));
253256

@@ -258,12 +261,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
258261

259262
// Then turn address into pointer.
260263
let ptr = M::ptr_from_addr_cast(&self, addr)?;
261-
Ok(Scalar::from_maybe_pointer(ptr, self).into())
264+
let layout = self.layout_of(cast_ty)?;
265+
Ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(ptr, self), layout))
262266
}
263267

264268
/// Low-level cast helper function. This works directly on scalars and can take 'int-like' input
265269
/// type (basically everything with a scalar layout) to int/float/char types.
266-
pub fn cast_from_int_like(
270+
fn cast_from_int_like(
267271
&self,
268272
scalar: Scalar<M::Provenance>, // input value (there is no ScalarTy so we separate data+layout)
269273
src_layout: TyAndLayout<'tcx>,

compiler/rustc_const_eval/src/interpret/discriminant.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
7676
let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
7777
let variant_index_relative_val =
7878
ImmTy::from_uint(variant_index_relative, tag_layout);
79-
let tag_val = self.binary_op(
79+
let tag_val = self.wrapping_binary_op(
8080
mir::BinOp::Add,
8181
&variant_index_relative_val,
8282
&niche_start_val,
@@ -153,19 +153,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
153153
// Figure out which discriminant and variant this corresponds to.
154154
let index = match *tag_encoding {
155155
TagEncoding::Direct => {
156-
let scalar = tag_val.to_scalar();
157156
// Generate a specific error if `tag_val` is not an integer.
158157
// (`tag_bits` itself is only used for error messages below.)
159-
let tag_bits = scalar
158+
let tag_bits = tag_val
159+
.to_scalar()
160160
.try_to_int()
161161
.map_err(|dbg_val| err_ub!(InvalidTag(dbg_val)))?
162162
.assert_bits(tag_layout.size);
163163
// Cast bits from tag layout to discriminant layout.
164164
// After the checks we did above, this cannot fail, as
165165
// discriminants are int-like.
166-
let discr_val =
167-
self.cast_from_int_like(scalar, tag_val.layout, discr_layout.ty).unwrap();
168-
let discr_bits = discr_val.assert_bits(discr_layout.size);
166+
let discr_val = self.int_to_int_or_float(&tag_val, discr_layout.ty).unwrap();
167+
let discr_bits = discr_val.to_scalar().assert_bits(discr_layout.size);
169168
// Convert discriminant to variant index, and catch invalid discriminants.
170169
let index = match *ty.kind() {
171170
ty::Adt(adt, _) => {
@@ -208,7 +207,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
208207
let tag_val = ImmTy::from_uint(tag_bits, tag_layout);
209208
let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
210209
let variant_index_relative_val =
211-
self.binary_op(mir::BinOp::Sub, &tag_val, &niche_start_val)?;
210+
self.wrapping_binary_op(mir::BinOp::Sub, &tag_val, &niche_start_val)?;
212211
let variant_index_relative =
213212
variant_index_relative_val.to_scalar().assert_bits(tag_val.layout.size);
214213
// Check if this is in the range that indicates an actual discriminant.

compiler/rustc_const_eval/src/interpret/intrinsics.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
307307
let dist = {
308308
// Addresses are unsigned, so this is a `usize` computation. We have to do the
309309
// overflow check separately anyway.
310-
let (val, overflowed, _ty) = {
310+
let (val, overflowed) = {
311311
let a_offset = ImmTy::from_uint(a_offset, usize_layout);
312312
let b_offset = ImmTy::from_uint(b_offset, usize_layout);
313313
self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?
@@ -324,7 +324,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
324324
// The signed form of the intrinsic allows this. If we interpret the
325325
// difference as isize, we'll get the proper signed difference. If that
326326
// seems *positive*, they were more than isize::MAX apart.
327-
let dist = val.to_target_isize(self)?;
327+
let dist = val.to_scalar().to_target_isize(self)?;
328328
if dist >= 0 {
329329
throw_ub_custom!(
330330
fluent::const_eval_offset_from_underflow,
@@ -334,7 +334,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
334334
dist
335335
} else {
336336
// b >= a
337-
let dist = val.to_target_isize(self)?;
337+
let dist = val.to_scalar().to_target_isize(self)?;
338338
// If converting to isize produced a *negative* result, we had an overflow
339339
// because they were more than isize::MAX apart.
340340
if dist < 0 {
@@ -504,9 +504,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
504504
// Performs an exact division, resulting in undefined behavior where
505505
// `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`.
506506
// First, check x % y != 0 (or if that computation overflows).
507-
let (res, overflow, _ty) = self.overflowing_binary_op(BinOp::Rem, &a, &b)?;
507+
let (res, overflow) = self.overflowing_binary_op(BinOp::Rem, &a, &b)?;
508508
assert!(!overflow); // All overflow is UB, so this should never return on overflow.
509-
if res.assert_bits(a.layout.size) != 0 {
509+
if res.to_scalar().assert_bits(a.layout.size) != 0 {
510510
throw_ub_custom!(
511511
fluent::const_eval_exact_div_has_remainder,
512512
a = format!("{a}"),
@@ -524,7 +524,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
524524
r: &ImmTy<'tcx, M::Provenance>,
525525
) -> InterpResult<'tcx, Scalar<M::Provenance>> {
526526
assert!(matches!(mir_op, BinOp::Add | BinOp::Sub));
527-
let (val, overflowed, _ty) = self.overflowing_binary_op(mir_op, l, r)?;
527+
let (val, overflowed) = self.overflowing_binary_op(mir_op, l, r)?;
528528
Ok(if overflowed {
529529
let size = l.layout.size;
530530
let num_bits = size.bits();
@@ -556,7 +556,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
556556
}
557557
}
558558
} else {
559-
val
559+
val.to_scalar()
560560
})
561561
}
562562

compiler/rustc_const_eval/src/interpret/machine.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::hash::Hash;
99
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
1010
use rustc_middle::mir;
1111
use rustc_middle::ty::layout::TyAndLayout;
12-
use rustc_middle::ty::{self, Ty, TyCtxt};
12+
use rustc_middle::ty::{self, TyCtxt};
1313
use rustc_span::def_id::DefId;
1414
use rustc_target::abi::{Align, Size};
1515
use rustc_target::spec::abi::Abi as CallAbi;
@@ -18,7 +18,7 @@ use crate::const_eval::CheckAlignment;
1818

1919
use super::{
2020
AllocBytes, AllocId, AllocRange, Allocation, ConstAllocation, FnArg, Frame, ImmTy, InterpCx,
21-
InterpResult, MPlaceTy, MemoryKind, OpTy, PlaceTy, Pointer, Provenance, Scalar,
21+
InterpResult, MPlaceTy, MemoryKind, OpTy, PlaceTy, Pointer, Provenance,
2222
};
2323

2424
/// Data returned by Machine::stack_pop,
@@ -238,7 +238,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
238238
bin_op: mir::BinOp,
239239
left: &ImmTy<'tcx, Self::Provenance>,
240240
right: &ImmTy<'tcx, Self::Provenance>,
241-
) -> InterpResult<'tcx, (Scalar<Self::Provenance>, bool, Ty<'tcx>)>;
241+
) -> InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)>;
242242

243243
/// Called before writing the specified `local` of the `frame`.
244244
/// Since writing a ZST is not actually accessing memory or locals, this is never invoked

compiler/rustc_const_eval/src/interpret/operand.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use either::{Either, Left, Right};
88
use rustc_hir::def::Namespace;
99
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
1010
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
11-
use rustc_middle::ty::{ConstInt, Ty};
11+
use rustc_middle::ty::{ConstInt, Ty, TyCtxt};
1212
use rustc_middle::{mir, ty};
1313
use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size};
1414

@@ -188,6 +188,12 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
188188
Self::from_scalar(Scalar::from_int(i, layout.size), layout)
189189
}
190190

191+
#[inline]
192+
pub fn from_bool(b: bool, tcx: TyCtxt<'tcx>) -> Self {
193+
let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(tcx.types.bool)).unwrap();
194+
Self::from_scalar(Scalar::from_bool(b), layout)
195+
}
196+
191197
#[inline]
192198
pub fn to_const_int(self) -> ConstInt {
193199
assert!(self.layout.ty.is_integral());

0 commit comments

Comments
 (0)