use crate::thir::*;
use rustc_middle::middle::region;
use rustc_middle::mir::AssertKind;
+use rustc_middle::mir::Place;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, Ty, UpvarSubsts};
use rustc_span::Span;
/// The operand returned from this function will *not be valid* after
/// an ExprKind::Scope is passed, so please do *not* return it from
/// functions to avoid bad miscompiles.
- crate fn as_local_rvalue<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Rvalue<'tcx>>
- where
- M: Mirror<'tcx, Output = Expr<'tcx>>,
- {
+ crate fn as_local_rvalue(
+ &mut self,
+ block: BasicBlock,
+ expr: &Expr<'_, 'tcx>,
+ ) -> BlockAnd<Rvalue<'tcx>> {
let local_scope = self.local_scope();
self.as_rvalue(block, Some(local_scope), expr)
}
/// Compile `expr`, yielding an rvalue.
- fn as_rvalue<M>(
- &mut self,
- block: BasicBlock,
- scope: Option<region::Scope>,
- expr: M,
- ) -> BlockAnd<Rvalue<'tcx>>
- where
- M: Mirror<'tcx, Output = Expr<'tcx>>,
- {
- let expr = self.hir.mirror(expr);
- self.expr_as_rvalue(block, scope, expr)
- }
-
- fn expr_as_rvalue(
+ crate fn as_rvalue(
&mut self,
mut block: BasicBlock,
scope: Option<region::Scope>,
- expr: Expr<'tcx>,
+ expr: &Expr<'_, 'tcx>,
) -> BlockAnd<Rvalue<'tcx>> {
debug!("expr_as_rvalue(block={:?}, scope={:?}, expr={:?})", block, scope, expr);
ExprKind::Unary { op, arg } => {
let arg = unpack!(block = this.as_operand(block, scope, arg));
// Check for -MIN on signed integers
- if this.hir.check_overflow() && op == UnOp::Neg && expr.ty.is_signed() {
- let bool_ty = this.hir.bool_ty();
+ if this.check_overflow && op == UnOp::Neg && expr.ty.is_signed() {
+ let bool_ty = this.tcx.types.bool;
let minval = this.minval_literal(expr_span, expr.ty);
let is_min = this.temp(bool_ty, expr_span);
block,
source_info,
is_min,
- Rvalue::BinaryOp(BinOp::Eq, arg.to_copy(), minval),
+ Rvalue::BinaryOp(BinOp::Eq, box (arg.to_copy(), minval)),
);
block = this.assert(
block.and(Rvalue::UnaryOp(op, arg))
}
ExprKind::Box { value } => {
- let value = this.hir.mirror(value);
// The `Box<T>` temporary created here is not a part of the HIR,
// and therefore is not considered during generator auto-trait
// determination. See the comment about `box` at `yield_in_scope`.
// initialize the box contents:
unpack!(
- block =
- this.into(this.hir.tcx().mk_place_deref(Place::from(result)), block, value)
+ block = this.expr_into_dest(
+ this.tcx.mk_place_deref(Place::from(result)),
+ block,
+ value
+ )
);
block.and(Rvalue::Use(Operand::Move(Place::from(result))))
}
// to the same MIR as `let x = ();`.
// first process the set of fields
- let el_ty = expr.ty.sequence_element_type(this.hir.tcx());
+ let el_ty = expr.ty.sequence_element_type(this.tcx);
let fields: Vec<_> = fields
.into_iter()
.map(|f| unpack!(block = this.as_operand(block, scope, f)))
block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields))
}
- ExprKind::Closure { closure_id, substs, upvars, movability } => {
+ ExprKind::Closure { closure_id, substs, upvars, movability, ref fake_reads } => {
+ // Convert the closure fake reads, if any, from `ExprRef` to mir `Place`
+ // and push the fake reads.
+ // This must come before creating the operands. This is required in case
+ // there is a fake read and a borrow of the same path, since otherwise the
+ // fake read might interfere with the borrow. Consider an example like this
+ // one:
+ // ```
+ // let mut x = 0;
+ // let c = || {
+ // &mut x; // mutable borrow of `x`
+ // match x { _ => () } // fake read of `x`
+ // };
+ // ```
+ // FIXME(RFC2229): Remove feature gate once diagnostics are improved
+ if this.tcx.features().capture_disjoint_fields {
+ for (thir_place, cause, hir_id) in fake_reads.into_iter() {
+ let place_builder =
+ unpack!(block = this.as_place_builder(block, thir_place));
+
+ if let Ok(place_builder_resolved) =
+ place_builder.try_upvars_resolved(this.tcx, this.typeck_results)
+ {
+ let mir_place =
+ place_builder_resolved.into_place(this.tcx, this.typeck_results);
+ this.cfg.push_fake_read(
+ block,
+ this.source_info(this.tcx.hir().span(*hir_id)),
+ *cause,
+ mir_place,
+ );
+ }
+ }
+ }
+
// see (*) above
let operands: Vec<_> = upvars
.into_iter()
.map(|upvar| {
- let upvar = this.hir.mirror(upvar);
match Category::of(&upvar.kind) {
// Use as_place to avoid creating a temporary when
// moving a variable into a closure, so that
}
})
.collect();
+
let result = match substs {
UpvarSubsts::Generator(substs) => {
// We implicitly set the discriminant to 0. See
block.and(Rvalue::Use(Operand::Constant(box Constant {
span: expr_span,
user_ty: None,
- literal: ty::Const::zero_sized(this.hir.tcx(), this.hir.tcx().types.unit),
+ literal: ty::Const::zero_sized(this.tcx, this.tcx.types.unit).into(),
})))
}
ExprKind::Yield { .. }
rhs: Operand<'tcx>,
) -> BlockAnd<Rvalue<'tcx>> {
let source_info = self.source_info(span);
- let bool_ty = self.hir.bool_ty();
- if self.hir.check_overflow() && op.is_checkable() && ty.is_integral() {
- let result_tup = self.hir.tcx().intern_tup(&[ty, bool_ty]);
+ let bool_ty = self.tcx.types.bool;
+ if self.check_overflow && op.is_checkable() && ty.is_integral() {
+ let result_tup = self.tcx.intern_tup(&[ty, bool_ty]);
let result_value = self.temp(result_tup, span);
self.cfg.push_assign(
block,
source_info,
result_value,
- Rvalue::CheckedBinaryOp(op, lhs.to_copy(), rhs.to_copy()),
+ Rvalue::CheckedBinaryOp(op, box (lhs.to_copy(), rhs.to_copy())),
);
let val_fld = Field::new(0);
let of_fld = Field::new(1);
- let tcx = self.hir.tcx();
+ let tcx = self.tcx;
let val = tcx.mk_place_field(result_value, val_fld, ty);
let of = tcx.mk_place_field(result_value, of_fld, bool_ty);
block,
source_info,
is_zero,
- Rvalue::BinaryOp(BinOp::Eq, rhs.to_copy(), zero),
+ Rvalue::BinaryOp(BinOp::Eq, box (rhs.to_copy(), zero)),
);
block = self.assert(block, Operand::Move(is_zero), false, zero_err, span);
block,
source_info,
is_neg_1,
- Rvalue::BinaryOp(BinOp::Eq, rhs.to_copy(), neg_1),
+ Rvalue::BinaryOp(BinOp::Eq, box (rhs.to_copy(), neg_1)),
);
self.cfg.push_assign(
block,
source_info,
is_min,
- Rvalue::BinaryOp(BinOp::Eq, lhs.to_copy(), min),
+ Rvalue::BinaryOp(BinOp::Eq, box (lhs.to_copy(), min)),
);
let is_neg_1 = Operand::Move(is_neg_1);
block,
source_info,
of,
- Rvalue::BinaryOp(BinOp::BitAnd, is_neg_1, is_min),
+ Rvalue::BinaryOp(BinOp::BitAnd, box (is_neg_1, is_min)),
);
block = self.assert(block, Operand::Move(of), false, overflow_err, span);
}
}
- block.and(Rvalue::BinaryOp(op, lhs, rhs))
+ block.and(Rvalue::BinaryOp(op, box (lhs, rhs)))
}
}
upvar_ty: Ty<'tcx>,
temp_lifetime: Option<region::Scope>,
mut block: BasicBlock,
- arg: ExprRef<'tcx>,
+ arg: &Expr<'_, 'tcx>,
) -> BlockAnd<Operand<'tcx>> {
let this = self;
// is same as that of the capture in the parent closure.
PlaceBase::Upvar { .. } => {
let enclosing_upvars_resolved =
- arg_place_builder.clone().into_place(this.hir.tcx(), this.hir.typeck_results());
+ arg_place_builder.clone().into_place(this.tcx, this.typeck_results);
match enclosing_upvars_resolved.as_ref() {
PlaceRef {
Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false },
};
- let arg_place = arg_place_builder.into_place(this.hir.tcx(), this.hir.typeck_results());
+ let arg_place = arg_place_builder.into_place(this.tcx, this.typeck_results);
this.cfg.push_assign(
block,
source_info,
Place::from(temp),
- Rvalue::Ref(this.hir.tcx().lifetimes.re_erased, borrow_kind, arg_place),
+ Rvalue::Ref(this.tcx.lifetimes.re_erased, borrow_kind, arg_place),
);
// See the comment in `expr_as_temp` and on the `rvalue_scopes` field for why
// Helper to get a `-1` value of the appropriate type
fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
let param_ty = ty::ParamEnv::empty().and(ty);
- let bits = self.hir.tcx().layout_of(param_ty).unwrap().size.bits();
+ let bits = self.tcx.layout_of(param_ty).unwrap().size.bits();
let n = (!0u128) >> (128 - bits);
- let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty);
+ let literal = ty::Const::from_bits(self.tcx, n, param_ty);
self.literal_operand(span, literal)
}
fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
assert!(ty.is_signed());
let param_ty = ty::ParamEnv::empty().and(ty);
- let bits = self.hir.tcx().layout_of(param_ty).unwrap().size.bits();
+ let bits = self.tcx.layout_of(param_ty).unwrap().size.bits();
let n = 1 << (bits - 1);
- let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty);
+ let literal = ty::Const::from_bits(self.tcx, n, param_ty);
self.literal_operand(span, literal)
}