summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_mir_build/src/build/expr/as_rvalue.rs')
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs108
1 files changed, 64 insertions, 44 deletions
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index 8631749a5..3742d640e 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -1,6 +1,6 @@
//! See docs in `build/expr/mod.rs`.
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::{Idx, IndexVec};
use rustc_middle::ty::util::IntTypeExt;
use rustc_target::abi::{Abi, FieldIdx, Primitive};
@@ -15,6 +15,7 @@ use rustc_middle::mir::Place;
use rustc_middle::mir::*;
use rustc_middle::thir::*;
use rustc_middle::ty::cast::{mir_cast_kind, CastTy};
+use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::{self, Ty, UpvarSubsts};
use rustc_span::Span;
@@ -225,49 +226,63 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
);
let (op,ty) = (Operand::Move(discr), discr_ty);
- if let Abi::Scalar(scalar) = layout.unwrap().abi{
- if let Primitive::Int(_, signed) = scalar.primitive() {
- let range = scalar.valid_range(&this.tcx);
- // FIXME: Handle wraparound cases too.
- if range.end >= range.start {
- let mut assumer = |range: u128, bin_op: BinOp| {
- // We will be overwriting this val if our scalar is signed value
- // because sign extension on unsigned types might cause unintended things
- let mut range_val =
- ConstantKind::from_bits(this.tcx, range, ty::ParamEnv::empty().and(discr_ty));
- let bool_ty = this.tcx.types.bool;
- if signed {
- let scalar_size_extend = scalar.size(&this.tcx).sign_extend(range);
- let discr_layout = this.tcx.layout_of(this.param_env.and(discr_ty));
- let truncated_val = discr_layout.unwrap().size.truncate(scalar_size_extend);
- range_val = ConstantKind::from_bits(
- this.tcx,
- truncated_val,
- ty::ParamEnv::empty().and(discr_ty),
- );
- }
- let lit_op = this.literal_operand(expr.span, range_val);
- let is_bin_op = this.temp(bool_ty, expr_span);
- this.cfg.push_assign(
- block,
- source_info,
- is_bin_op,
- Rvalue::BinaryOp(bin_op, Box::new(((lit_op), (Operand::Copy(discr))))),
- );
- this.cfg.push(
- block,
- Statement {
- source_info,
- kind: StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume(
- Operand::Copy(is_bin_op),
- ))),
- },
- )
- };
- assumer(range.end, BinOp::Ge);
- assumer(range.start, BinOp::Le);
- }
- }
+ if let Abi::Scalar(scalar) = layout.unwrap().abi
+ && !scalar.is_always_valid(&this.tcx)
+ && let Primitive::Int(int_width, _signed) = scalar.primitive()
+ {
+ let unsigned_ty = int_width.to_ty(this.tcx, false);
+ let unsigned_place = this.temp(unsigned_ty, expr_span);
+ this.cfg.push_assign(
+ block,
+ source_info,
+ unsigned_place,
+ Rvalue::Cast(CastKind::IntToInt, Operand::Copy(discr), unsigned_ty));
+
+ let bool_ty = this.tcx.types.bool;
+ let range = scalar.valid_range(&this.tcx);
+ let merge_op =
+ if range.start <= range.end {
+ BinOp::BitAnd
+ } else {
+ BinOp::BitOr
+ };
+
+ let mut comparer = |range: u128, bin_op: BinOp| -> Place<'tcx> {
+ let range_val =
+ ConstantKind::from_bits(this.tcx, range, ty::ParamEnv::empty().and(unsigned_ty));
+ let lit_op = this.literal_operand(expr.span, range_val);
+ let is_bin_op = this.temp(bool_ty, expr_span);
+ this.cfg.push_assign(
+ block,
+ source_info,
+ is_bin_op,
+ Rvalue::BinaryOp(bin_op, Box::new((Operand::Copy(unsigned_place), lit_op))),
+ );
+ is_bin_op
+ };
+ let assert_place = if range.start == 0 {
+ comparer(range.end, BinOp::Le)
+ } else {
+ let start_place = comparer(range.start, BinOp::Ge);
+ let end_place = comparer(range.end, BinOp::Le);
+ let merge_place = this.temp(bool_ty, expr_span);
+ this.cfg.push_assign(
+ block,
+ source_info,
+ merge_place,
+ Rvalue::BinaryOp(merge_op, Box::new((Operand::Move(start_place), Operand::Move(end_place)))),
+ );
+ merge_place
+ };
+ this.cfg.push(
+ block,
+ Statement {
+ source_info,
+ kind: StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume(
+ Operand::Move(assert_place),
+ ))),
+ },
+ );
}
(op,ty)
@@ -481,6 +496,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}))))
}
+ ExprKind::OffsetOf { container, fields } => {
+ block.and(Rvalue::NullaryOp(NullOp::OffsetOf(fields), container))
+ }
+
ExprKind::Literal { .. }
| ExprKind::NamedConst { .. }
| ExprKind::NonHirLiteral { .. }
@@ -706,6 +725,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
place: to_drop,
target: success,
unwind: UnwindAction::Continue,
+ replace: false,
},
);
this.diverge_from(block);