diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:20:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:20:39 +0000 |
commit | 1376c5a617be5c25655d0d7cb63e3beaa5a6e026 (patch) | |
tree | 3bb8d61aee02bc7a15eab3f36e3b921afc2075d0 /compiler/rustc_mir_build/src/build/expr | |
parent | Releasing progress-linux version 1.69.0+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-1376c5a617be5c25655d0d7cb63e3beaa5a6e026.tar.xz rustc-1376c5a617be5c25655d0d7cb63e3beaa5a6e026.zip |
Merging upstream version 1.70.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_mir_build/src/build/expr')
-rw-r--r-- | compiler/rustc_mir_build/src/build/expr/as_constant.rs | 6 | ||||
-rw-r--r-- | compiler/rustc_mir_build/src/build/expr/as_operand.rs | 14 | ||||
-rw-r--r-- | compiler/rustc_mir_build/src/build/expr/as_place.rs | 10 | ||||
-rw-r--r-- | compiler/rustc_mir_build/src/build/expr/as_rvalue.rs | 174 | ||||
-rw-r--r-- | compiler/rustc_mir_build/src/build/expr/as_temp.rs | 25 | ||||
-rw-r--r-- | compiler/rustc_mir_build/src/build/expr/into.rs | 28 | ||||
-rw-r--r-- | compiler/rustc_mir_build/src/build/expr/stmt.rs | 2 |
7 files changed, 171 insertions, 88 deletions
diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index cfacb5ea3..99291740a 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -62,21 +62,21 @@ pub fn as_constant_inner<'tcx>( Constant { span, user_ty: None, literal } } ExprKind::NonHirLiteral { lit, ref user_ty } => { - let user_ty = user_ty.as_ref().map(push_cuta).flatten(); + let user_ty = user_ty.as_ref().and_then(push_cuta); let literal = ConstantKind::Val(ConstValue::Scalar(Scalar::Int(lit)), ty); Constant { span, user_ty, literal } } ExprKind::ZstLiteral { ref user_ty } => { - let user_ty = user_ty.as_ref().map(push_cuta).flatten(); + let user_ty = user_ty.as_ref().and_then(push_cuta); let literal = ConstantKind::Val(ConstValue::ZeroSized, ty); Constant { span, user_ty, literal } } ExprKind::NamedConst { def_id, substs, ref user_ty } => { - let user_ty = user_ty.as_ref().map(push_cuta).flatten(); + let user_ty = user_ty.as_ref().and_then(push_cuta); let uneval = mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs); let literal = ConstantKind::Unevaluated(uneval, ty); diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs index ff3198847..6941da331 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs @@ -20,7 +20,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr: &Expr<'tcx>, ) -> BlockAnd<Operand<'tcx>> { let local_scope = self.local_scope(); - self.as_operand(block, Some(local_scope), expr, None, NeedsTemporary::Maybe) + self.as_operand(block, Some(local_scope), expr, LocalInfo::Boring, NeedsTemporary::Maybe) } /// Returns an operand suitable for use until the end of the current scope expression and @@ -102,7 +102,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { mut block: BasicBlock, scope: Option<region::Scope>, expr: &Expr<'tcx>, - local_info: Option<Box<LocalInfo<'tcx>>>, + local_info: LocalInfo<'tcx>, needs_temporary: NeedsTemporary, ) -> BlockAnd<Operand<'tcx>> { let this = self; @@ -124,8 +124,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } Category::Constant | Category::Place | Category::Rvalue(..) => { let operand = unpack!(block = this.as_temp(block, scope, expr, Mutability::Mut)); - if this.local_decls[operand].local_info.is_none() { - this.local_decls[operand].local_info = local_info; + // Overwrite temp local info if we have something more interesting to record. + if !matches!(local_info, LocalInfo::Boring) { + let decl_info = this.local_decls[operand].local_info.as_mut().assert_crate_local(); + if let LocalInfo::Boring | LocalInfo::BlockTailTemp(_) = **decl_info { + **decl_info = local_info; + } } block.and(Operand::Move(Place::from(operand))) } @@ -178,6 +182,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - this.as_operand(block, scope, expr, None, NeedsTemporary::Maybe) + this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::Maybe) } } diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index 33200b80a..fb775766c 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -13,9 +13,7 @@ use rustc_middle::thir::*; use rustc_middle::ty::AdtDef; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, Variance}; use rustc_span::Span; -use rustc_target::abi::VariantIdx; - -use rustc_index::vec::Idx; +use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; use std::assert_matches::assert_matches; use std::iter; @@ -91,8 +89,8 @@ fn convert_to_hir_projections_and_truncate_for_capture( let hir_projection = match mir_projection { ProjectionElem::Deref => HirProjectionKind::Deref, ProjectionElem::Field(field, _) => { - let variant = variant.unwrap_or(VariantIdx::new(0)); - HirProjectionKind::Field(field.index() as u32, variant) + let variant = variant.unwrap_or(FIRST_VARIANT); + HirProjectionKind::Field(*field, variant) } ProjectionElem::Downcast(.., idx) => { // We don't expect to see multi-variant enums here, as earlier @@ -295,7 +293,7 @@ impl<'tcx> PlaceBuilder<'tcx> { &self.projection } - pub(crate) fn field(self, f: Field, ty: Ty<'tcx>) -> Self { + pub(crate) fn field(self, f: FieldIdx, ty: Ty<'tcx>) -> Self { self.project(PlaceElem::Field(f, ty)) } 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 a4e48c154..8631749a5 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -1,14 +1,15 @@ //! See docs in `build/expr/mod.rs`. -use rustc_index::vec::Idx; +use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::ty::util::IntTypeExt; -use rustc_target::abi::{Abi, Primitive}; +use rustc_target::abi::{Abi, FieldIdx, Primitive}; use crate::build::expr::as_place::PlaceBase; use crate::build::expr::category::{Category, RvalueFunc}; use crate::build::{BlockAnd, BlockAndExtension, Builder, NeedsTemporary}; use rustc_hir::lang_items::LangItem; use rustc_middle::middle::region; +use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::AssertKind; use rustc_middle::mir::Place; use rustc_middle::mir::*; @@ -63,7 +64,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, scope, &this.thir[value], - None, + LocalInfo::Boring, NeedsTemporary::No ) ); @@ -72,19 +73,34 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ExprKind::Binary { op, lhs, rhs } => { let lhs = unpack!( - block = - this.as_operand(block, scope, &this.thir[lhs], None, NeedsTemporary::Maybe) + block = this.as_operand( + block, + scope, + &this.thir[lhs], + LocalInfo::Boring, + NeedsTemporary::Maybe + ) ); let rhs = unpack!( - block = - this.as_operand(block, scope, &this.thir[rhs], None, NeedsTemporary::No) + block = this.as_operand( + block, + scope, + &this.thir[rhs], + LocalInfo::Boring, + NeedsTemporary::No + ) ); this.build_binary_op(block, op, expr_span, expr.ty, lhs, rhs) } ExprKind::Unary { op, arg } => { let arg = unpack!( - block = - this.as_operand(block, scope, &this.thir[arg], None, NeedsTemporary::No) + block = this.as_operand( + block, + scope, + &this.thir[arg], + LocalInfo::Boring, + NeedsTemporary::No + ) ); // Check for -MIN on signed integers if this.check_overflow && op == UnOp::Neg && expr.ty.is_signed() { @@ -155,7 +171,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { args: vec![Operand::Move(size), Operand::Move(align)], destination: storage, target: Some(success), - cleanup: None, + unwind: UnwindAction::Continue, from_hir_call: false, fn_span: expr_span, }, @@ -259,7 +275,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } else { let ty = source.ty; let source = unpack!( - block = this.as_operand(block, scope, source, None, NeedsTemporary::No) + block = this.as_operand(block, scope, source, LocalInfo::Boring, NeedsTemporary::No) ); (source, ty) }; @@ -271,8 +287,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ExprKind::Pointer { cast, source } => { let source = unpack!( - block = - this.as_operand(block, scope, &this.thir[source], None, NeedsTemporary::No) + block = this.as_operand( + block, + scope, + &this.thir[source], + LocalInfo::Boring, + NeedsTemporary::No + ) ); block.and(Rvalue::Cast(CastKind::Pointer(cast), source, expr.ty)) } @@ -305,7 +326,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // first process the set of fields let el_ty = expr.ty.sequence_element_type(this.tcx); - let fields: Vec<_> = fields + let fields: IndexVec<FieldIdx, _> = fields .into_iter() .copied() .map(|f| { @@ -314,7 +335,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, scope, &this.thir[f], - None, + LocalInfo::Boring, NeedsTemporary::Maybe ) ) @@ -326,7 +347,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ExprKind::Tuple { ref fields } => { // see (*) above // first process the set of fields - let fields: Vec<_> = fields + let fields: IndexVec<FieldIdx, _> = fields .into_iter() .copied() .map(|f| { @@ -335,7 +356,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, scope, &this.thir[f], - None, + LocalInfo::Boring, NeedsTemporary::Maybe ) ) @@ -380,7 +401,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } // see (*) above - let operands: Vec<_> = upvars + let operands: IndexVec<FieldIdx, _> = upvars .into_iter() .copied() .map(|upvar| { @@ -423,7 +444,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, scope, upvar, - None, + LocalInfo::Boring, NeedsTemporary::Maybe ) ) @@ -501,8 +522,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Category::of(&expr.kind), Some(Category::Rvalue(RvalueFunc::AsRvalue) | Category::Constant) )); - let operand = - unpack!(block = this.as_operand(block, scope, expr, None, NeedsTemporary::No)); + let operand = unpack!( + block = + this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::No) + ); block.and(Rvalue::Use(operand)) } } @@ -519,30 +542,78 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) -> BlockAnd<Rvalue<'tcx>> { let source_info = self.source_info(span); let bool_ty = self.tcx.types.bool; - if self.check_overflow && op.is_checkable() && ty.is_integral() { - let result_tup = self.tcx.mk_tup(&[ty, bool_ty]); - let result_value = self.temp(result_tup, span); - - self.cfg.push_assign( - block, - source_info, - result_value, - Rvalue::CheckedBinaryOp(op, Box::new((lhs.to_copy(), rhs.to_copy()))), - ); - let val_fld = Field::new(0); - let of_fld = Field::new(1); + let rvalue = match op { + BinOp::Add | BinOp::Sub | BinOp::Mul if self.check_overflow && ty.is_integral() => { + let result_tup = self.tcx.mk_tup(&[ty, bool_ty]); + let result_value = self.temp(result_tup, span); - 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); + self.cfg.push_assign( + block, + source_info, + result_value, + Rvalue::CheckedBinaryOp(op, Box::new((lhs.to_copy(), rhs.to_copy()))), + ); + let val_fld = FieldIdx::new(0); + let of_fld = FieldIdx::new(1); - let err = AssertKind::Overflow(op, lhs, rhs); + 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 = self.assert(block, Operand::Move(of), false, err, span); + let err = AssertKind::Overflow(op, lhs, rhs); + block = self.assert(block, Operand::Move(of), false, err, span); - block.and(Rvalue::Use(Operand::Move(val))) - } else { - if ty.is_integral() && (op == BinOp::Div || op == BinOp::Rem) { + Rvalue::Use(Operand::Move(val)) + } + BinOp::Shl | BinOp::Shr if self.check_overflow && ty.is_integral() => { + // For an unsigned RHS, the shift is in-range for `rhs < bits`. + // For a signed RHS, `IntToInt` cast to the equivalent unsigned + // type and do that same comparison. Because the type is the + // same size, there's no negative shift amount that ends up + // overlapping with valid ones, thus it catches negatives too. + let (lhs_size, _) = ty.int_size_and_signed(self.tcx); + let rhs_ty = rhs.ty(&self.local_decls, self.tcx); + let (rhs_size, _) = rhs_ty.int_size_and_signed(self.tcx); + + let (unsigned_rhs, unsigned_ty) = match rhs_ty.kind() { + ty::Uint(_) => (rhs.to_copy(), rhs_ty), + ty::Int(int_width) => { + let uint_ty = self.tcx.mk_mach_uint(int_width.to_unsigned()); + let rhs_temp = self.temp(uint_ty, span); + self.cfg.push_assign( + block, + source_info, + rhs_temp, + Rvalue::Cast(CastKind::IntToInt, rhs.to_copy(), uint_ty), + ); + (Operand::Move(rhs_temp), uint_ty) + } + _ => unreachable!("only integers are shiftable"), + }; + + // This can't overflow because the largest shiftable types are 128-bit, + // which fits in `u8`, the smallest possible `unsigned_ty`. + // (And `from_uint` will `bug!` if that's ever no longer true.) + let lhs_bits = Operand::const_from_scalar( + self.tcx, + unsigned_ty, + Scalar::from_uint(lhs_size.bits(), rhs_size), + span, + ); + + let inbounds = self.temp(bool_ty, span); + self.cfg.push_assign( + block, + source_info, + inbounds, + Rvalue::BinaryOp(BinOp::Lt, Box::new((unsigned_rhs, lhs_bits))), + ); + + let overflow_err = AssertKind::Overflow(op, lhs.to_copy(), rhs.to_copy()); + block = self.assert(block, Operand::Move(inbounds), true, overflow_err, span); + Rvalue::BinaryOp(op, Box::new((lhs, rhs))) + } + BinOp::Div | BinOp::Rem if ty.is_integral() => { // Checking division and remainder is more complex, since we 1. always check // and 2. there are two possible failure cases, divide-by-zero and overflow. @@ -601,10 +672,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block = self.assert(block, Operand::Move(of), false, overflow_err, span); } - } - block.and(Rvalue::BinaryOp(op, Box::new((lhs, rhs)))) - } + Rvalue::BinaryOp(op, Box::new((lhs, rhs))) + } + _ => Rvalue::BinaryOp(op, Box::new((lhs, rhs))), + }; + block.and(rvalue) } fn build_zero_repeat( @@ -621,21 +694,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Repeating a const does nothing } else { // For a non-const, we may need to generate an appropriate `Drop` - let value_operand = - unpack!(block = this.as_operand(block, scope, value, None, NeedsTemporary::No)); + let value_operand = unpack!( + block = this.as_operand(block, scope, value, LocalInfo::Boring, NeedsTemporary::No) + ); if let Operand::Move(to_drop) = value_operand { let success = this.cfg.start_new_block(); this.cfg.terminate( block, outer_source_info, - TerminatorKind::Drop { place: to_drop, target: success, unwind: None }, + TerminatorKind::Drop { + place: to_drop, + target: success, + unwind: UnwindAction::Continue, + }, ); this.diverge_from(block); block = success; } this.record_operands_moved(&[value_operand]); } - block.and(Rvalue::Aggregate(Box::new(AggregateKind::Array(elem_ty)), Vec::new())) + block.and(Rvalue::Aggregate(Box::new(AggregateKind::Array(elem_ty)), IndexVec::new())) } fn limit_capture_mutability( diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs index 3d3cf7555..c8910c272 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -49,29 +49,28 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } debug!("creating temp {:?} with block_context: {:?}", local_decl, this.block_context); - // Find out whether this temp is being created within the - // tail expression of a block whose result is ignored. - if let Some(tail_info) = this.block_context.currently_in_block_tail() { - local_decl = local_decl.block_tail(tail_info); - } - match expr.kind { + let local_info = match expr.kind { ExprKind::StaticRef { def_id, .. } => { assert!(!this.tcx.is_thread_local_static(def_id)); local_decl.internal = true; - local_decl.local_info = - Some(Box::new(LocalInfo::StaticRef { def_id, is_thread_local: false })); + LocalInfo::StaticRef { def_id, is_thread_local: false } } ExprKind::ThreadLocalRef(def_id) => { assert!(this.tcx.is_thread_local_static(def_id)); local_decl.internal = true; - local_decl.local_info = - Some(Box::new(LocalInfo::StaticRef { def_id, is_thread_local: true })); + LocalInfo::StaticRef { def_id, is_thread_local: true } } ExprKind::NamedConst { def_id, .. } | ExprKind::ConstParam { def_id, .. } => { - local_decl.local_info = Some(Box::new(LocalInfo::ConstRef { def_id })); + LocalInfo::ConstRef { def_id } } - _ => {} - } + // Find out whether this temp is being created within the + // tail expression of a block whose result is ignored. + _ if let Some(tail_info) = this.block_context.currently_in_block_tail() => { + LocalInfo::BlockTailTemp(tail_info) + } + _ => LocalInfo::Boring, + }; + **local_decl.local_info.as_mut().assert_crate_local() = local_info; this.local_decls.push(local_decl) }; let temp_place = Place::from(temp); diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index dac9bf0a8..05a723a6b 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -6,7 +6,6 @@ use rustc_ast::InlineAsmOptions; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; -use rustc_index::vec::Idx; use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty::CanonicalUserTypeAnnotation; @@ -229,7 +228,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.cfg.terminate( loop_block, source_info, - TerminatorKind::FalseUnwind { real_target: body_block, unwind: None }, + TerminatorKind::FalseUnwind { + real_target: body_block, + unwind: UnwindAction::Continue, + }, ); this.diverge_from(loop_block); @@ -265,7 +267,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TerminatorKind::Call { func: fun, args, - cleanup: None, + unwind: UnwindAction::Continue, destination, // The presence or absence of a return edge affects control-flow sensitive // MIR checks and ultimately whether code is accepted or not. We can only @@ -319,7 +321,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // See the notes for `ExprKind::Array` in `as_rvalue` and for // `ExprKind::Borrow` above. let is_union = adt_def.is_union(); - let active_field_index = is_union.then(|| fields[0].name.index()); + let active_field_index = is_union.then(|| fields[0].name); let scope = this.local_scope(); @@ -328,7 +330,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let fields_map: FxHashMap<_, _> = fields .into_iter() .map(|f| { - let local_info = Box::new(LocalInfo::AggregateTemp); ( f.name, unpack!( @@ -336,7 +337,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, Some(scope), &this.thir[f.expr], - Some(local_info), + LocalInfo::AggregateTemp, NeedsTemporary::Maybe, ) ), @@ -344,10 +345,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }) .collect(); - let field_names: Vec<_> = - (0..adt_def.variant(variant_index).fields.len()).map(Field::new).collect(); + let field_names = adt_def.variant(variant_index).fields.indices(); - let fields: Vec<_> = if let Some(FruInfo { base, field_types }) = base { + let fields = if let Some(FruInfo { base, field_types }) = base { let place_builder = unpack!(block = this.as_place_builder(block, &this.thir[*base])); @@ -364,7 +364,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }) .collect() } else { - field_names.iter().filter_map(|n| fields_map.get(n).cloned()).collect() + field_names.filter_map(|n| fields_map.get(&n).cloned()).collect() }; let inferred_ty = expr.ty; @@ -469,7 +469,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } else { Some(destination_block) }, - cleanup: None, + unwind: if options.contains(InlineAsmOptions::MAY_UNWIND) { + UnwindAction::Continue + } else { + UnwindAction::Unreachable + }, }, ); if options.contains(InlineAsmOptions::MAY_UNWIND) { @@ -526,7 +530,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, Some(scope), &this.thir[value], - None, + LocalInfo::Boring, NeedsTemporary::No ) ); diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs index 780836851..ea5aeb67d 100644 --- a/compiler/rustc_mir_build/src/build/expr/stmt.rs +++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs @@ -40,7 +40,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Generate better code for things that don't need to be // dropped. if lhs.ty.needs_drop(this.tcx, this.param_env) { - let rhs = unpack!(block = this.as_local_operand(block, rhs)); + let rhs = unpack!(block = this.as_local_rvalue(block, rhs)); let lhs = unpack!(block = this.as_place(block, lhs)); unpack!(block = this.build_drop_and_replace(block, lhs_span, lhs, rhs)); } else { |