diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 37b308f9f88d3..34d3f20d0cfa9 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -179,10 +179,10 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir::Arm<'tcx>) { let prev_cx = visitor.cx; - visitor.enter_scope(Scope { id: arm.hir_id.local_id, data: ScopeData::Node }); - visitor.cx.var_parent = visitor.cx.parent; + visitor.terminating_scopes.insert(arm.hir_id.local_id); - visitor.terminating_scopes.insert(arm.body.hir_id.local_id); + visitor.enter_node_scope_with_dtor(arm.hir_id.local_id); + visitor.cx.var_parent = visitor.cx.parent; if let Some(hir::Guard::If(expr)) = arm.guard { visitor.terminating_scopes.insert(expr.hir_id.local_id); diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index 8cad6976c0db1..4046122b6fe67 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -15,7 +15,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) -> BlockAnd<()> { let Block { region_scope, span, ref stmts, expr, targeted_by_break, safety_mode } = self.thir[ast_block]; - let expr = expr.map(|expr| &self.thir[expr]); self.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| { if targeted_by_break { this.in_breakable_scope(None, destination, span, |this| { @@ -49,7 +48,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { mut block: BasicBlock, span: Span, stmts: &[StmtId], - expr: Option<&Expr<'tcx>>, + expr: Option, safety_mode: BlockSafety, region_scope: Scope, ) -> BlockAnd<()> { @@ -90,7 +89,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let si = (*scope, source_info); unpack!( block = this.in_scope(si, LintLevel::Inherited, |this| { - this.stmt_expr(block, &this.thir[*expr], Some(*scope)) + this.stmt_expr(block, *expr, Some(*scope)) }) ); } @@ -205,8 +204,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let visibility_scope = Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None)); - let init = &this.thir[*initializer]; - let initializer_span = init.span; + let initializer_span = this.thir[*initializer].span; let scope = (*init_scope, source_info); let failure = unpack!( block = this.in_scope(scope, *lint_level, |this| { @@ -232,7 +230,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); this.ast_let_else( block, - init, + *initializer, initializer_span, *else_block, &last_remainder_scope, @@ -276,9 +274,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None)); // Evaluate the initializer, if present. - if let Some(init) = initializer { - let init = &this.thir[*init]; - let initializer_span = init.span; + if let Some(init) = *initializer { + let initializer_span = this.thir[init].span; let scope = (*init_scope, source_info); unpack!( @@ -334,13 +331,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // of the block, which is stored into `destination`. let tcx = this.tcx; let destination_ty = destination.ty(&this.local_decls, tcx).ty; - if let Some(expr) = expr { + if let Some(expr_id) = expr { + let expr = &this.thir[expr_id]; let tail_result_is_ignored = destination_ty.is_unit() || this.block_context.currently_ignores_tail_results(); this.block_context .push(BlockFrame::TailExpr { tail_result_is_ignored, span: expr.span }); - unpack!(block = this.expr_into_dest(destination, block, expr)); + unpack!(block = this.expr_into_dest(destination, block, expr_id)); let popped = this.block_context.pop(); assert!(popped.is_some_and(|bf| bf.is_tail_expr())); 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 744111edb84e4..076ee7f85ff68 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs @@ -17,10 +17,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn as_local_operand( &mut self, block: BasicBlock, - expr: &Expr<'tcx>, + expr_id: ExprId, ) -> BlockAnd> { let local_scope = self.local_scope(); - self.as_operand(block, Some(local_scope), expr, LocalInfo::Boring, NeedsTemporary::Maybe) + self.as_operand(block, Some(local_scope), expr_id, LocalInfo::Boring, NeedsTemporary::Maybe) } /// Returns an operand suitable for use until the end of the current scope expression and @@ -76,7 +76,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn as_local_call_operand( &mut self, block: BasicBlock, - expr: &Expr<'tcx>, + expr: ExprId, ) -> BlockAnd> { let local_scope = self.local_scope(); self.as_call_operand(block, Some(local_scope), expr) @@ -101,17 +101,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, mut block: BasicBlock, scope: Option, - expr: &Expr<'tcx>, + expr_id: ExprId, local_info: LocalInfo<'tcx>, needs_temporary: NeedsTemporary, ) -> BlockAnd> { let this = self; + let expr = &this.thir[expr_id]; if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind { let source_info = this.source_info(expr.span); let region_scope = (region_scope, source_info); return this.in_scope(region_scope, lint_level, |this| { - this.as_operand(block, scope, &this.thir[value], local_info, needs_temporary) + this.as_operand(block, scope, value, local_info, needs_temporary) }); } @@ -126,7 +127,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(Operand::Constant(Box::new(constant))) } Category::Constant | Category::Place | Category::Rvalue(..) => { - let operand = unpack!(block = this.as_temp(block, scope, expr, Mutability::Mut)); + let operand = unpack!(block = this.as_temp(block, scope, expr_id, Mutability::Mut)); // Overwrite temp local info if we have something more interesting to record. if !matches!(local_info, LocalInfo::Boring) { let decl_info = @@ -144,16 +145,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, mut block: BasicBlock, scope: Option, - expr: &Expr<'tcx>, + expr_id: ExprId, ) -> BlockAnd> { - debug!("as_call_operand(block={:?}, expr={:?})", block, expr); let this = self; + let expr = &this.thir[expr_id]; + debug!("as_call_operand(block={:?}, expr={:?})", block, expr); if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind { let source_info = this.source_info(expr.span); let region_scope = (region_scope, source_info); return this.in_scope(region_scope, lint_level, |this| { - this.as_call_operand(block, scope, &this.thir[value]) + this.as_call_operand(block, scope, value) }); } @@ -171,9 +173,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // type, and that value is coming from the deref of a box. if let ExprKind::Deref { arg } = expr.kind { // Generate let tmp0 = arg0 - let operand = unpack!( - block = this.as_temp(block, scope, &this.thir[arg], Mutability::Mut) - ); + let operand = unpack!(block = this.as_temp(block, scope, arg, Mutability::Mut)); // Return the operand *tmp0 to be used as the call argument let place = Place { @@ -186,6 +186,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::Maybe) + this.as_operand(block, scope, expr_id, 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 43e8348903ef2..f12e25db6fcd5 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -354,9 +354,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn as_place( &mut self, mut block: BasicBlock, - expr: &Expr<'tcx>, + expr_id: ExprId, ) -> BlockAnd> { - let place_builder = unpack!(block = self.as_place_builder(block, expr)); + let place_builder = unpack!(block = self.as_place_builder(block, expr_id)); block.and(place_builder.to_place(self)) } @@ -365,9 +365,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn as_place_builder( &mut self, block: BasicBlock, - expr: &Expr<'tcx>, + expr_id: ExprId, ) -> BlockAnd> { - self.expr_as_place(block, expr, Mutability::Mut, None) + self.expr_as_place(block, expr_id, Mutability::Mut, None) } /// Compile `expr`, yielding a place that we can move from etc. @@ -378,9 +378,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn as_read_only_place( &mut self, mut block: BasicBlock, - expr: &Expr<'tcx>, + expr_id: ExprId, ) -> BlockAnd> { - let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr)); + let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr_id)); block.and(place_builder.to_place(self)) } @@ -393,18 +393,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn as_read_only_place_builder( &mut self, block: BasicBlock, - expr: &Expr<'tcx>, + expr_id: ExprId, ) -> BlockAnd> { - self.expr_as_place(block, expr, Mutability::Not, None) + self.expr_as_place(block, expr_id, Mutability::Not, None) } fn expr_as_place( &mut self, mut block: BasicBlock, - expr: &Expr<'tcx>, + expr_id: ExprId, mutability: Mutability, fake_borrow_temps: Option<&mut Vec>, ) -> BlockAnd> { + let expr = &self.thir[expr_id]; debug!("expr_as_place(block={:?}, expr={:?}, mutability={:?})", block, expr, mutability); let this = self; @@ -413,14 +414,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match expr.kind { ExprKind::Scope { region_scope, lint_level, value } => { this.in_scope((region_scope, source_info), lint_level, |this| { - this.expr_as_place(block, &this.thir[value], mutability, fake_borrow_temps) + this.expr_as_place(block, value, mutability, fake_borrow_temps) }) } ExprKind::Field { lhs, variant_index, name } => { - let lhs = &this.thir[lhs]; + let lhs_expr = &this.thir[lhs]; let mut place_builder = unpack!(block = this.expr_as_place(block, lhs, mutability, fake_borrow_temps,)); - if let ty::Adt(adt_def, _) = lhs.ty.kind() { + if let ty::Adt(adt_def, _) = lhs_expr.ty.kind() { if adt_def.is_enum() { place_builder = place_builder.downcast(*adt_def, variant_index); } @@ -428,16 +429,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(place_builder.field(name, expr.ty)) } ExprKind::Deref { arg } => { - let place_builder = unpack!( - block = - this.expr_as_place(block, &this.thir[arg], mutability, fake_borrow_temps,) - ); + let place_builder = + unpack!(block = this.expr_as_place(block, arg, mutability, fake_borrow_temps,)); block.and(place_builder.deref()) } ExprKind::Index { lhs, index } => this.lower_index_expression( block, - &this.thir[lhs], - &this.thir[index], + lhs, + index, mutability, fake_borrow_temps, expr.temp_lifetime, @@ -461,12 +460,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ExprKind::PlaceTypeAscription { source, ref user_ty } => { let place_builder = unpack!( - block = this.expr_as_place( - block, - &this.thir[source], - mutability, - fake_borrow_temps, - ) + block = this.expr_as_place(block, source, mutability, fake_borrow_temps,) ); if let Some(user_ty) = user_ty { let annotation_index = @@ -494,9 +488,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(place_builder) } ExprKind::ValueTypeAscription { source, ref user_ty } => { - let source = &this.thir[source]; - let temp = - unpack!(block = this.as_temp(block, source.temp_lifetime, source, mutability)); + let source_expr = &this.thir[source]; + let temp = unpack!( + block = this.as_temp(block, source_expr.temp_lifetime, source, mutability) + ); if let Some(user_ty) = user_ty { let annotation_index = this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { @@ -562,7 +557,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // these are not places, so we need to make a temporary. debug_assert!(!matches!(Category::of(&expr.kind), Some(Category::Place))); let temp = - unpack!(block = this.as_temp(block, expr.temp_lifetime, expr, mutability)); + unpack!(block = this.as_temp(block, expr.temp_lifetime, expr_id, mutability)); block.and(PlaceBuilder::from(temp)) } } @@ -591,8 +586,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn lower_index_expression( &mut self, mut block: BasicBlock, - base: &Expr<'tcx>, - index: &Expr<'tcx>, + base: ExprId, + index: ExprId, mutability: Mutability, fake_borrow_temps: Option<&mut Vec>, temp_lifetime: Option, @@ -609,7 +604,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Making this a *fresh* temporary means we do not have to worry about // the index changing later: Nothing will ever change this temporary. // The "retagging" transformation (for Stacked Borrows) relies on this. - let idx = unpack!(block = self.as_temp(block, temp_lifetime, index, Mutability::Not,)); + let idx = unpack!(block = self.as_temp(block, temp_lifetime, index, Mutability::Not)); block = self.bounds_check(block, &base_place, idx, expr_span, source_info); 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 a5f6bb12ee457..04dcc6854c72f 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -27,10 +27,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn as_local_rvalue( &mut self, block: BasicBlock, - expr: &Expr<'tcx>, + expr_id: ExprId, ) -> BlockAnd> { let local_scope = self.local_scope(); - self.as_rvalue(block, Some(local_scope), expr) + self.as_rvalue(block, Some(local_scope), expr_id) } /// Compile `expr`, yielding an rvalue. @@ -38,11 +38,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, mut block: BasicBlock, scope: Option, - expr: &Expr<'tcx>, + expr_id: ExprId, ) -> BlockAnd> { + let this = self; + let expr = &this.thir[expr_id]; debug!("expr_as_rvalue(block={:?}, scope={:?}, expr={:?})", block, scope, expr); - let this = self; let expr_span = expr.span; let source_info = this.source_info(expr_span); @@ -50,9 +51,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ExprKind::ThreadLocalRef(did) => block.and(Rvalue::ThreadLocalRef(did)), ExprKind::Scope { region_scope, lint_level, value } => { let region_scope = (region_scope, source_info); - this.in_scope(region_scope, lint_level, |this| { - this.as_rvalue(block, scope, &this.thir[value]) - }) + this.in_scope(region_scope, lint_level, |this| this.as_rvalue(block, scope, value)) } ExprKind::Repeat { value, count } => { if Some(0) == count.try_eval_target_usize(this.tcx, this.param_env) { @@ -62,7 +61,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block = this.as_operand( block, scope, - &this.thir[value], + value, LocalInfo::Boring, NeedsTemporary::No ) @@ -75,31 +74,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block = this.as_operand( block, scope, - &this.thir[lhs], + lhs, LocalInfo::Boring, NeedsTemporary::Maybe ) ); let rhs = unpack!( - block = this.as_operand( - block, - scope, - &this.thir[rhs], - LocalInfo::Boring, - NeedsTemporary::No - ) + block = + this.as_operand(block, scope, 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], - LocalInfo::Boring, - NeedsTemporary::No - ) + block = + this.as_operand(block, scope, arg, LocalInfo::Boring, NeedsTemporary::No) ); // Check for -MIN on signed integers if this.check_overflow && op == UnOp::Neg && expr.ty.is_signed() { @@ -126,7 +115,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(Rvalue::UnaryOp(op, arg)) } ExprKind::Box { value } => { - let value = &this.thir[value]; + let value_ty = this.thir[value].ty; let tcx = this.tcx; // `exchange_malloc` is unsafe but box is safe, so need a new scope. @@ -142,7 +131,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, synth_info, size, - Rvalue::NullaryOp(NullOp::SizeOf, value.ty), + Rvalue::NullaryOp(NullOp::SizeOf, value_ty), ); let align = this.temp(tcx.types.usize, expr_span); @@ -150,7 +139,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, synth_info, align, - Rvalue::NullaryOp(NullOp::AlignOf, value.ty), + Rvalue::NullaryOp(NullOp::AlignOf, value_ty), ); // malloc some memory of suitable size and align: @@ -192,7 +181,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } // Transmute `*mut u8` to the box (thus far, uninitialized): - let box_ = Rvalue::ShallowInitBox(Operand::Move(storage), value.ty); + let box_ = Rvalue::ShallowInitBox(Operand::Move(storage), value_ty); this.cfg.push_assign(block, source_info, Place::from(result), box_); // initialize the box contents: @@ -200,24 +189,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block = this.expr_into_dest( this.tcx.mk_place_deref(Place::from(result)), block, - value + value, ) ); block.and(Rvalue::Use(Operand::Move(Place::from(result)))) } ExprKind::Cast { source } => { - let source = &this.thir[source]; + let source_expr = &this.thir[source]; // Casting an enum to an integer is equivalent to computing the discriminant and casting the // discriminant. Previously every backend had to repeat the logic for this operation. Now we // create all the steps directly in MIR with operations all backends need to support anyway. - let (source, ty) = if let ty::Adt(adt_def, ..) = source.ty.kind() + let (source, ty) = if let ty::Adt(adt_def, ..) = source_expr.ty.kind() && adt_def.is_enum() { let discr_ty = adt_def.repr().discr_type().to_ty(this.tcx); let temp = unpack!(block = this.as_temp(block, scope, source, Mutability::Not)); - let layout = this.tcx.layout_of(this.param_env.and(source.ty)); - let discr = this.temp(discr_ty, source.span); + let layout = this.tcx.layout_of(this.param_env.and(source_expr.ty)); + let discr = this.temp(discr_ty, source_expr.span); this.cfg.push_assign( block, source_info, @@ -296,7 +285,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { (op, ty) } else { - let ty = source.ty; + let ty = source_expr.ty; let source = unpack!( block = this.as_operand( block, @@ -310,7 +299,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; let from_ty = CastTy::from_ty(ty); let cast_ty = CastTy::from_ty(expr.ty); - debug!("ExprKind::Cast from_ty={from_ty:?}, cast_ty={:?}/{cast_ty:?}", expr.ty,); + debug!("ExprKind::Cast from_ty={from_ty:?}, cast_ty={:?}/{cast_ty:?}", expr.ty); let cast_kind = mir_cast_kind(ty, expr.ty); block.and(Rvalue::Cast(cast_kind, source, expr.ty)) } @@ -319,7 +308,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block = this.as_operand( block, scope, - &this.thir[source], + source, LocalInfo::Boring, NeedsTemporary::No ) @@ -363,7 +352,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block = this.as_operand( block, scope, - &this.thir[f], + f, LocalInfo::Boring, NeedsTemporary::Maybe ) @@ -384,7 +373,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block = this.as_operand( block, scope, - &this.thir[f], + f, LocalInfo::Boring, NeedsTemporary::Maybe ) @@ -416,8 +405,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // ``` // for (thir_place, cause, hir_id) in fake_reads.into_iter() { - let place_builder = - unpack!(block = this.as_place_builder(block, &this.thir[*thir_place])); + let place_builder = unpack!(block = this.as_place_builder(block, *thir_place)); if let Some(mir_place) = place_builder.try_to_place(this) { this.cfg.push_fake_read( @@ -434,8 +422,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .into_iter() .copied() .map(|upvar| { - let upvar = &this.thir[upvar]; - match Category::of(&upvar.kind) { + let upvar_expr = &this.thir[upvar]; + match Category::of(&upvar_expr.kind) { // Use as_place to avoid creating a temporary when // moving a variable into a closure, so that // borrowck knows which variables to mark as being @@ -453,18 +441,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // borrow captures when capturing an immutable // variable. This is sound because the mutation // that caused the capture will cause an error. - match upvar.kind { + match upvar_expr.kind { ExprKind::Borrow { borrow_kind: BorrowKind::Mut { kind: MutBorrowKind::Default }, arg, } => unpack!( block = this.limit_capture_mutability( - upvar.span, - upvar.ty, + upvar_expr.span, + upvar_expr.ty, scope, block, - &this.thir[arg], + arg, ) ), _ => { @@ -498,7 +486,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(Rvalue::Aggregate(result, operands)) } ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => { - block = unpack!(this.stmt_expr(block, expr, None)); + block = unpack!(this.stmt_expr(block, expr_id, None)); block.and(Rvalue::Use(Operand::Constant(Box::new(ConstOperand { span: expr_span, user_ty: None, @@ -553,8 +541,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Some(Category::Rvalue(RvalueFunc::AsRvalue) | Category::Constant) )); let operand = unpack!( - block = - this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::No) + block = this.as_operand( + block, + scope, + expr_id, + LocalInfo::Boring, + NeedsTemporary::No, + ) ); block.and(Rvalue::Use(operand)) } @@ -719,9 +712,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { outer_source_info: SourceInfo, ) -> BlockAnd> { let this = self; - let value = &this.thir[value]; - let elem_ty = value.ty; - if let Some(Category::Constant) = Category::of(&value.kind) { + let value_expr = &this.thir[value]; + let elem_ty = value_expr.ty; + if let Some(Category::Constant) = Category::of(&value_expr.kind) { // Repeating a const does nothing } else { // For a non-const, we may need to generate an appropriate `Drop` @@ -754,7 +747,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { upvar_ty: Ty<'tcx>, temp_lifetime: Option, mut block: BasicBlock, - arg: &Expr<'tcx>, + arg: ExprId, ) -> BlockAnd> { let this = self; 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 a4ab365fa9a70..27e66e7f54d0a 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -14,13 +14,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, block: BasicBlock, temp_lifetime: Option, - expr: &Expr<'tcx>, + expr_id: ExprId, mutability: Mutability, ) -> BlockAnd { // this is the only place in mir building that we need to truly need to worry about // infinite recursion. Everything else does recurse, too, but it always gets broken up // at some point by inserting an intermediate temporary - ensure_sufficient_stack(|| self.as_temp_inner(block, temp_lifetime, expr, mutability)) + ensure_sufficient_stack(|| self.as_temp_inner(block, temp_lifetime, expr_id, mutability)) } #[instrument(skip(self), level = "debug")] @@ -28,21 +28,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, mut block: BasicBlock, temp_lifetime: Option, - expr: &Expr<'tcx>, + expr_id: ExprId, mutability: Mutability, ) -> BlockAnd { let this = self; + let expr = &this.thir[expr_id]; let expr_span = expr.span; let source_info = this.source_info(expr_span); if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind { return this.in_scope((region_scope, source_info), lint_level, |this| { - this.as_temp(block, temp_lifetime, &this.thir[value], mutability) + this.as_temp(block, temp_lifetime, value, mutability) }); } let expr_ty = expr.ty; - let temp = { + let deduplicate_temps = + this.fixed_temps_scope.is_some() && this.fixed_temps_scope == temp_lifetime; + let temp = if deduplicate_temps && let Some(temp_index) = this.fixed_temps.get(&expr_id) { + *temp_index + } else { let mut local_decl = LocalDecl::new(expr_ty, expr_span); if mutability.is_not() { local_decl = local_decl.immutable(); @@ -71,6 +76,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { **local_decl.local_info.as_mut().assert_crate_local() = local_info; this.local_decls.push(local_decl) }; + if deduplicate_temps { + this.fixed_temps.insert(expr_id, temp); + } let temp_place = Place::from(temp); match expr.kind { @@ -103,7 +111,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - unpack!(block = this.expr_into_dest(temp_place, block, expr)); + unpack!(block = this.expr_into_dest(temp_place, block, expr_id)); if let Some(temp_lifetime) = temp_lifetime { this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value); diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 054661cf2373b..f50945a4de05d 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -19,12 +19,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, destination: Place<'tcx>, mut block: BasicBlock, - expr: &Expr<'tcx>, + expr_id: ExprId, ) -> BlockAnd<()> { // since we frequently have to reference `self` from within a // closure, where `self` would be shadowed, it's easier to // just use the name `this` uniformly let this = self; + let expr = &this.thir[expr_id]; let expr_span = expr.span; let source_info = this.source_info(expr_span); @@ -40,20 +41,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let region_scope = (region_scope, source_info); ensure_sufficient_stack(|| { this.in_scope(region_scope, lint_level, |this| { - this.expr_into_dest(destination, block, &this.thir[value]) + this.expr_into_dest(destination, block, value) }) }) } ExprKind::Block { block: ast_block } => { this.ast_block(destination, block, ast_block, source_info) } - ExprKind::Match { scrutinee, ref arms, .. } => { - this.match_expr(destination, expr_span, block, &this.thir[scrutinee], arms) - } + ExprKind::Match { scrutinee, ref arms, .. } => this.match_expr( + destination, + block, + scrutinee, + arms, + expr_span, + this.thir[scrutinee].span, + ), ExprKind::If { cond, then, else_opt, if_then_scope } => { let then_blk; - let then_expr = &this.thir[then]; - let then_source_info = this.source_info(then_expr.span); + let then_span = this.thir[then].span; + let then_source_info = this.source_info(then_span); let condition_scope = this.local_scope(); let mut else_blk = unpack!( @@ -62,27 +68,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { LintLevel::Inherited, |this| { let source_info = if this.is_let(cond) { - let variable_scope = this.new_source_scope( - then_expr.span, - LintLevel::Inherited, - None, - ); + let variable_scope = + this.new_source_scope(then_span, LintLevel::Inherited, None); this.source_scope = variable_scope; - SourceInfo { span: then_expr.span, scope: variable_scope } + SourceInfo { span: then_span, scope: variable_scope } } else { - this.source_info(then_expr.span) + this.source_info(then_span) }; let (then_block, else_block) = - this.in_if_then_scope(condition_scope, then_expr.span, |this| { + this.in_if_then_scope(condition_scope, then_span, |this| { let then_blk = unpack!(this.then_else_break( block, - &this.thir[cond], + cond, Some(condition_scope), condition_scope, source_info )); - this.expr_into_dest(destination, then_blk, then_expr) + this.expr_into_dest(destination, then_blk, then) }); then_block.and(else_block) }, @@ -90,7 +93,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); else_blk = if let Some(else_opt) = else_opt { - unpack!(this.expr_into_dest(destination, else_blk, &this.thir[else_opt])) + unpack!(this.expr_into_dest(destination, else_blk, else_opt)) } else { // Body of the `if` expression without an `else` clause must return `()`, thus // we implicitly generate an `else {}` if it is not specified. @@ -107,7 +110,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ExprKind::Let { expr, ref pat } => { let scope = this.local_scope(); let (true_block, false_block) = this.in_if_then_scope(scope, expr_span, |this| { - this.lower_let_expr(block, &this.thir[expr], pat, scope, None, expr_span, true) + this.lower_let_expr(block, expr, pat, scope, None, expr_span, true) }); this.cfg.push_assign_constant( @@ -138,14 +141,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { join_block.unit() } ExprKind::NeverToAny { source } => { - let source = &this.thir[source]; + let source_expr = &this.thir[source]; let is_call = - matches!(source.kind, ExprKind::Call { .. } | ExprKind::InlineAsm { .. }); + matches!(source_expr.kind, ExprKind::Call { .. } | ExprKind::InlineAsm { .. }); // (#66975) Source could be a const of type `!`, so has to // exist in the generated MIR. unpack!( - block = this.as_temp(block, Some(this.local_scope()), source, Mutability::Mut,) + block = this.as_temp(block, Some(this.local_scope()), source, Mutability::Mut) ); // This is an optimization. If the expression was a call then we already have an @@ -166,7 +169,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.in_if_then_scope(condition_scope, expr.span, |this| { this.then_else_break( block, - &this.thir[lhs], + lhs, Some(condition_scope), condition_scope, source_info, @@ -192,7 +195,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { const_: Const::from_bool(this.tcx, constant), }, ); - let rhs = unpack!(this.expr_into_dest(destination, continuation, &this.thir[rhs])); + let rhs = unpack!(this.expr_into_dest(destination, continuation, rhs)); let target = this.cfg.start_new_block(); this.cfg.goto(rhs, source_info, target); this.cfg.goto(short_circuit, source_info, target); @@ -231,8 +234,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // introduce a unit temporary as the destination for the loop body. let tmp = this.get_unit_temp(); // Execute the body, branching back to the test. - let body_block_end = - unpack!(this.expr_into_dest(tmp, body_block, &this.thir[body])); + let body_block_end = unpack!(this.expr_into_dest(tmp, body_block, body)); this.cfg.goto(body_block_end, source_info, loop_block); // Loops are only exited by `break` expressions. @@ -240,11 +242,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }) } ExprKind::Call { ty: _, fun, ref args, from_hir_call, fn_span } => { - let fun = unpack!(block = this.as_local_operand(block, &this.thir[fun])); + let fun = unpack!(block = this.as_local_operand(block, fun)); let args: Vec<_> = args .into_iter() .copied() - .map(|arg| unpack!(block = this.as_local_call_operand(block, &this.thir[arg]))) + .map(|arg| unpack!(block = this.as_local_call_operand(block, arg))) .collect(); let success = this.cfg.start_new_block(); @@ -280,16 +282,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.diverge_from(block); success.unit() } - ExprKind::Use { source } => this.expr_into_dest(destination, block, &this.thir[source]), + ExprKind::Use { source } => this.expr_into_dest(destination, block, source), ExprKind::Borrow { arg, borrow_kind } => { - let arg = &this.thir[arg]; // We don't do this in `as_rvalue` because we use `as_place` // for borrow expressions, so we cannot create an `RValue` that // remains valid across user code. `as_rvalue` is usually called // by this method anyway, so this shouldn't cause too many // unnecessary temporaries. let arg_place = match borrow_kind { - BorrowKind::Shared => unpack!(block = this.as_read_only_place(block, arg)), + BorrowKind::Shared => { + unpack!(block = this.as_read_only_place(block, arg)) + } _ => unpack!(block = this.as_place(block, arg)), }; let borrow = Rvalue::Ref(this.tcx.lifetimes.re_erased, borrow_kind, arg_place); @@ -297,7 +300,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.unit() } ExprKind::AddressOf { mutability, arg } => { - let arg = &this.thir[arg]; let place = match mutability { hir::Mutability::Not => this.as_read_only_place(block, arg), hir::Mutability::Mut => this.as_place(block, arg), @@ -332,7 +334,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block = this.as_operand( block, Some(scope), - &this.thir[f.expr], + f.expr, LocalInfo::AggregateTemp, NeedsTemporary::Maybe, ) @@ -344,8 +346,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let field_names = adt_def.variant(variant_index).fields.indices(); let fields = if let Some(FruInfo { base, field_types }) = base { - let place_builder = - unpack!(block = this.as_place_builder(block, &this.thir[*base])); + let place_builder = unpack!(block = this.as_place_builder(block, *base)); // MIR does not natively support FRU, so for each // base-supplied field, generate an operand that @@ -398,19 +399,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .map(|op| match *op { thir::InlineAsmOperand::In { reg, expr } => mir::InlineAsmOperand::In { reg, - value: unpack!(block = this.as_local_operand(block, &this.thir[expr])), + value: unpack!(block = this.as_local_operand(block, expr)), }, thir::InlineAsmOperand::Out { reg, late, expr } => { mir::InlineAsmOperand::Out { reg, late, - place: expr.map(|expr| { - unpack!(block = this.as_place(block, &this.thir[expr])) - }), + place: expr.map(|expr| unpack!(block = this.as_place(block, expr))), } } thir::InlineAsmOperand::InOut { reg, late, expr } => { - let place = unpack!(block = this.as_place(block, &this.thir[expr])); + let place = unpack!(block = this.as_place(block, expr)); mir::InlineAsmOperand::InOut { reg, late, @@ -423,11 +422,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { mir::InlineAsmOperand::InOut { reg, late, - in_value: unpack!( - block = this.as_local_operand(block, &this.thir[in_expr]) - ), + in_value: unpack!(block = this.as_local_operand(block, in_expr)), out_place: out_expr.map(|out_expr| { - unpack!(block = this.as_place(block, &this.thir[out_expr])) + unpack!(block = this.as_place(block, out_expr)) }), } } @@ -488,7 +485,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // These cases don't actually need a destination ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => { - unpack!(block = this.stmt_expr(block, expr, None)); + unpack!(block = this.stmt_expr(block, expr_id, None)); this.cfg.push_assign_unit(block, source_info, destination, this.tcx); block.unit() } @@ -497,7 +494,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::Break { .. } | ExprKind::Return { .. } | ExprKind::Become { .. } => { - unpack!(block = this.stmt_expr(block, expr, None)); + unpack!(block = this.stmt_expr(block, expr_id, None)); // No assign, as these have type `!`. block.unit() } @@ -509,7 +506,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::ValueTypeAscription { .. } => { debug_assert!(Category::of(&expr.kind) == Some(Category::Place)); - let place = unpack!(block = this.as_place(block, expr)); + let place = unpack!(block = this.as_place(block, expr_id)); let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place)); this.cfg.push_assign(block, source_info, destination, rvalue); block.unit() @@ -524,7 +521,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.local_decls.push(LocalDecl::new(expr.ty, expr.span)); } - let place = unpack!(block = this.as_place(block, expr)); + let place = unpack!(block = this.as_place(block, expr_id)); let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place)); this.cfg.push_assign(block, source_info, destination, rvalue); block.unit() @@ -536,7 +533,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block = this.as_operand( block, Some(scope), - &this.thir[value], + value, LocalInfo::Boring, NeedsTemporary::No ) @@ -582,7 +579,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { _ => true, }); - let rvalue = unpack!(block = this.as_local_rvalue(block, expr)); + let rvalue = unpack!(block = this.as_local_rvalue(block, expr_id)); this.cfg.push_assign(block, source_info, destination, rvalue); block.unit() } diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs index 7beaef602a8ea..7f5e45e20cc17 100644 --- a/compiler/rustc_mir_build/src/build/expr/stmt.rs +++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs @@ -11,10 +11,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn stmt_expr( &mut self, mut block: BasicBlock, - expr: &Expr<'tcx>, + expr_id: ExprId, statement_scope: Option, ) -> BlockAnd<()> { let this = self; + let expr = &this.thir[expr_id]; let expr_span = expr.span; let source_info = this.source_info(expr.span); // Handle a number of expressions that don't need a destination at all. This @@ -22,13 +23,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match expr.kind { ExprKind::Scope { region_scope, lint_level, value } => { this.in_scope((region_scope, source_info), lint_level, |this| { - this.stmt_expr(block, &this.thir[value], statement_scope) + this.stmt_expr(block, value, statement_scope) }) } ExprKind::Assign { lhs, rhs } => { - let lhs = &this.thir[lhs]; - let rhs = &this.thir[rhs]; - let lhs_span = lhs.span; + let lhs_expr = &this.thir[lhs]; // Note: we evaluate assignments right-to-left. This // is better for borrowck interaction with overloaded @@ -39,10 +38,10 @@ 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) { + if lhs_expr.ty.needs_drop(this.tcx, this.param_env) { 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)); + unpack!(block = this.build_drop_and_replace(block, lhs_expr.span, lhs, rhs)); } else { let rhs = unpack!(block = this.as_local_rvalue(block, rhs)); let lhs = unpack!(block = this.as_place(block, lhs)); @@ -61,9 +60,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // only affects weird things like `x += {x += 1; x}` // -- is that equal to `x + (x + 1)` or `2*(x+1)`? - let lhs = &this.thir[lhs]; - let rhs = &this.thir[rhs]; - let lhs_ty = lhs.ty; + let lhs_ty = this.thir[lhs].ty; debug!("stmt_expr AssignOp block_context.push(SubExpr) : {:?}", expr); this.block_context.push(BlockFrame::SubExpr); @@ -87,25 +84,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ExprKind::Continue { label } => { this.break_scope(block, None, BreakableTarget::Continue(label), source_info) } - ExprKind::Break { label, value } => this.break_scope( - block, - value.map(|value| &this.thir[value]), - BreakableTarget::Break(label), - source_info, - ), - ExprKind::Return { value } => this.break_scope( - block, - value.map(|value| &this.thir[value]), - BreakableTarget::Return, - source_info, - ), + ExprKind::Break { label, value } => { + this.break_scope(block, value, BreakableTarget::Break(label), source_info) + } + ExprKind::Return { value } => { + this.break_scope(block, value, BreakableTarget::Return, source_info) + } // FIXME(explicit_tail_calls): properly lower tail calls here - ExprKind::Become { value } => this.break_scope( - block, - Some(&this.thir[value]), - BreakableTarget::Return, - source_info, - ), + ExprKind::Become { value } => { + this.break_scope(block, Some(value), BreakableTarget::Return, source_info) + } _ => { assert!( statement_scope.is_some(), @@ -147,7 +135,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; let temp = - unpack!(block = this.as_temp(block, statement_scope, expr, Mutability::Not)); + unpack!(block = this.as_temp(block, statement_scope, expr_id, Mutability::Not)); if let Some(span) = adjusted_span { this.local_decls[temp].source_info.span = span; diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 487b1f44b5e27..7f29e3308f4f5 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -36,19 +36,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn then_else_break( &mut self, mut block: BasicBlock, - expr: &Expr<'tcx>, + expr_id: ExprId, temp_scope_override: Option, break_scope: region::Scope, variable_source_info: SourceInfo, ) -> BlockAnd<()> { let this = self; + let expr = &this.thir[expr_id]; let expr_span = expr.span; match expr.kind { ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => { let lhs_then_block = unpack!(this.then_else_break( block, - &this.thir[lhs], + lhs, temp_scope_override, break_scope, variable_source_info, @@ -56,7 +57,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let rhs_then_block = unpack!(this.then_else_break( lhs_then_block, - &this.thir[rhs], + rhs, temp_scope_override, break_scope, variable_source_info, @@ -70,7 +71,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.in_if_then_scope(local_scope, expr_span, |this| { this.then_else_break( block, - &this.thir[lhs], + lhs, temp_scope_override, local_scope, variable_source_info, @@ -78,7 +79,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }); let rhs_success_block = unpack!(this.then_else_break( failure_block, - &this.thir[rhs], + rhs, temp_scope_override, break_scope, variable_source_info, @@ -97,7 +98,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } this.then_else_break( block, - &this.thir[arg], + arg, temp_scope_override, local_scope, variable_source_info, @@ -111,7 +112,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.in_scope(region_scope, lint_level, |this| { this.then_else_break( block, - &this.thir[value], + value, temp_scope_override, break_scope, variable_source_info, @@ -120,14 +121,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ExprKind::Use { source } => this.then_else_break( block, - &this.thir[source], + source, temp_scope_override, break_scope, variable_source_info, ), ExprKind::Let { expr, ref pat } => this.lower_let_expr( block, - &this.thir[expr], + expr, pat, break_scope, Some(variable_source_info.scope), @@ -138,7 +139,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let temp_scope = temp_scope_override.unwrap_or_else(|| this.local_scope()); let mutability = Mutability::Mut; let place = - unpack!(block = this.as_temp(block, Some(temp_scope), expr, mutability)); + unpack!(block = this.as_temp(block, Some(temp_scope), expr_id, mutability)); let operand = Operand::Move(Place::from(place)); let then_block = this.cfg.start_new_block(); @@ -208,14 +209,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn match_expr( &mut self, destination: Place<'tcx>, - span: Span, mut block: BasicBlock, - scrutinee: &Expr<'tcx>, + scrutinee_id: ExprId, arms: &[ArmId], + span: Span, + scrutinee_span: Span, ) -> BlockAnd<()> { - let scrutinee_span = scrutinee.span; + let scrutinee_span = scrutinee_span; let scrutinee_place = - unpack!(block = self.lower_scrutinee(block, scrutinee, scrutinee_span,)); + unpack!(block = self.lower_scrutinee(block, scrutinee_id, scrutinee_span)); let mut arm_candidates = self.create_match_candidates(&scrutinee_place, arms); @@ -223,7 +225,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut candidates = arm_candidates.iter_mut().map(|(_, candidate)| candidate).collect::>(); - let match_start_span = span.shrink_to_lo().to(scrutinee.span); + let match_start_span = span.shrink_to_lo().to(scrutinee_span); let fake_borrow_temps = self.lower_match_tree( block, @@ -248,10 +250,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn lower_scrutinee( &mut self, mut block: BasicBlock, - scrutinee: &Expr<'tcx>, + scrutinee_id: ExprId, scrutinee_span: Span, ) -> BlockAnd> { - let scrutinee_place_builder = unpack!(block = self.as_place_builder(block, scrutinee)); + let scrutinee_place_builder = unpack!(block = self.as_place_builder(block, scrutinee_id)); if let Some(scrutinee_place) = scrutinee_place_builder.try_to_place(self) { let source_info = self.source_info(scrutinee_span); self.cfg.push_place_mention(block, source_info, scrutinee_place); @@ -394,6 +396,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let arm_scope = (arm.scope, arm_source_info); let match_scope = self.local_scope(); self.in_scope(arm_scope, arm.lint_level, |this| { + let old_dedup_scope = + mem::replace(&mut this.fixed_temps_scope, Some(arm.scope)); + // `try_to_place` may fail if it is unable to resolve the given // `PlaceBuilder` inside a closure. In this case, we don't want to include // a scrutinee place. `scrutinee_place_builder` will fail to be resolved @@ -425,11 +430,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { false, ); + this.fixed_temps_scope = old_dedup_scope; + if let Some(source_scope) = scope { this.source_scope = source_scope; } - this.expr_into_dest(destination, arm_block, &this.thir[arm.body]) + this.expr_into_dest(destination, arm_block, arm.body) }) }) .collect(); @@ -538,14 +545,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, mut block: BasicBlock, irrefutable_pat: &Pat<'tcx>, - initializer: &Expr<'tcx>, + initializer_id: ExprId, ) -> BlockAnd<()> { match irrefutable_pat.kind { // Optimize the case of `let x = ...` to write directly into `x` PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => { let place = self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true); - unpack!(block = self.expr_into_dest(place, block, initializer)); + unpack!(block = self.expr_into_dest(place, block, initializer_id)); // Inject a fake read, see comments on `FakeReadCause::ForLet`. let source_info = self.source_info(irrefutable_pat.span); @@ -576,7 +583,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } => { let place = self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true); - unpack!(block = self.expr_into_dest(place, block, initializer)); + unpack!(block = self.expr_into_dest(place, block, initializer_id)); // Inject a fake read, see comments on `FakeReadCause::ForLet`. let pattern_source_info = self.source_info(irrefutable_pat.span); @@ -616,8 +623,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } _ => { + let initializer = &self.thir[initializer_id]; let place_builder = - unpack!(block = self.lower_scrutinee(block, initializer, initializer.span)); + unpack!(block = self.lower_scrutinee(block, initializer_id, initializer.span)); self.place_into_pattern(block, irrefutable_pat, place_builder, true) } } @@ -1831,15 +1839,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn lower_let_expr( &mut self, mut block: BasicBlock, - expr: &Expr<'tcx>, + expr_id: ExprId, pat: &Pat<'tcx>, else_target: region::Scope, source_scope: Option, span: Span, declare_bindings: bool, ) -> BlockAnd<()> { - let expr_span = expr.span; - let expr_place_builder = unpack!(block = self.lower_scrutinee(block, expr, expr_span)); + let expr_span = self.thir[expr_id].span; + let expr_place_builder = unpack!(block = self.lower_scrutinee(block, expr_id, expr_span)); let wildcard = Pat::wildcard_from_ty(pat.ty); let mut guard_candidate = Candidate::new(expr_place_builder.clone(), pat, false, self); let mut otherwise_candidate = @@ -1865,7 +1873,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.source_info(pat.span), guard_candidate, &fake_borrow_temps, - expr.span, + expr_span, None, false, ); @@ -2028,8 +2036,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let (post_guard_block, otherwise_post_guard_block) = self.in_if_then_scope(match_scope, guard_span, |this| match *guard { Guard::If(e) => { - let e = &this.thir[e]; - guard_span = e.span; + guard_span = this.thir[e].span; this.then_else_break( block, e, @@ -2038,9 +2045,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.source_info(arm.span), ) } - Guard::IfLet(ref pat, scrutinee) => { - let s = &this.thir[scrutinee]; - guard_span = s.span; + Guard::IfLet(ref pat, s) => { + guard_span = this.thir[s].span; this.lower_let_expr(block, s, pat, match_scope, None, arm.span, false) } }); @@ -2334,7 +2340,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn ast_let_else( &mut self, mut block: BasicBlock, - init: &Expr<'tcx>, + init_id: ExprId, initializer_span: Span, else_block: BlockId, let_else_scope: ®ion::Scope, @@ -2342,8 +2348,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) -> BlockAnd { let else_block_span = self.thir[else_block].span; let (matching, failure) = self.in_if_then_scope(*let_else_scope, else_block_span, |this| { - let scrutinee = unpack!(block = this.lower_scrutinee(block, init, initializer_span)); - let pat = Pat { ty: init.ty, span: else_block_span, kind: PatKind::Wild }; + let scrutinee = unpack!(block = this.lower_scrutinee(block, init_id, initializer_span)); + let pat = Pat { ty: pattern.ty, span: else_block_span, kind: PatKind::Wild }; let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false, this); let mut candidate = Candidate::new(scrutinee.clone(), pattern, false, this); let fake_borrow_temps = this.lower_match_tree( diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index dae83d4b41b23..a6336ec63b215 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -18,7 +18,7 @@ use rustc_middle::middle::region; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::*; use rustc_middle::thir::{ - self, BindingMode, Expr, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir, + self, BindingMode, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir, }; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::symbol::sym; @@ -210,6 +210,12 @@ struct Builder<'a, 'tcx> { /// finish building it. guard_context: Vec, + /// Temporaries with fixed indexes. Used so that if-let guards on arms + /// with an or-pattern are only created once. + fixed_temps: FxHashMap, + /// Scope of temporaries that should be deduplicated using [Self::fixed_temps]. + fixed_temps_scope: Option, + /// Maps `HirId`s of variable bindings to the `Local`s created for them. /// (A match binding can have two locals; the 2nd is for the arm's guard.) var_indices: FxHashMap, @@ -539,7 +545,7 @@ fn construct_fn<'tcx>( let return_block = unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| { Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| { - builder.args_and_body(START_BLOCK, arguments, arg_scope, &thir[expr]) + builder.args_and_body(START_BLOCK, arguments, arg_scope, expr) })) })); let source_info = builder.source_info(fn_end); @@ -606,7 +612,7 @@ fn construct_const<'a, 'tcx>( ); let mut block = START_BLOCK; - unpack!(block = builder.expr_into_dest(Place::return_place(), block, &thir[expr])); + unpack!(block = builder.expr_into_dest(Place::return_place(), block, expr)); let source_info = builder.source_info(span); builder.cfg.terminate(block, source_info, TerminatorKind::Return); @@ -752,6 +758,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_scopes: IndexVec::new(), source_scope: OUTERMOST_SOURCE_SCOPE, guard_context: vec![], + fixed_temps: Default::default(), + fixed_temps_scope: None, in_scope_unsafe: safety, local_decls: IndexVec::from_elem_n(LocalDecl::new(return_ty, return_span), 1), canonical_user_type_annotations: IndexVec::new(), @@ -865,8 +873,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { mut block: BasicBlock, arguments: &IndexSlice>, argument_scope: region::Scope, - expr: &Expr<'tcx>, + expr_id: ExprId, ) -> BlockAnd<()> { + let expr_span = self.thir[expr_id].span; // Allocate locals for the function arguments for (argument_index, param) in arguments.iter().enumerate() { let source_info = @@ -899,7 +908,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Make sure we drop (parts of) the argument even when not matched on. self.schedule_drop( - param.pat.as_ref().map_or(expr.span, |pat| pat.span), + param.pat.as_ref().map_or(expr_span, |pat| pat.span), argument_scope, local, DropKind::Value, @@ -941,8 +950,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { _ => { scope = self.declare_bindings( scope, - expr.span, - pat, + expr_span, + &pat, None, Some((Some(&place), span)), ); @@ -958,7 +967,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.source_scope = source_scope; } - self.expr_into_dest(Place::return_place(), block, expr) + self.expr_into_dest(Place::return_place(), block, expr_id) } fn set_correct_source_scope_for_arg( diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 25b79e6a523d6..1a700ac7342ee 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -89,7 +89,7 @@ use rustc_hir::HirId; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::middle::region; use rustc_middle::mir::*; -use rustc_middle::thir::{Expr, LintLevel}; +use rustc_middle::thir::{ExprId, LintLevel}; use rustc_session::lint::Level; use rustc_span::{Span, DUMMY_SP}; @@ -592,7 +592,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn break_scope( &mut self, mut block: BasicBlock, - value: Option<&Expr<'tcx>>, + value: Option, target: BreakableTarget, source_info: SourceInfo, ) -> BlockAnd<()> { diff --git a/tests/ui/drop/dynamic-drop.rs b/tests/ui/drop/dynamic-drop.rs index 5bf2cc30e7fd6..d35913ed6412c 100644 --- a/tests/ui/drop/dynamic-drop.rs +++ b/tests/ui/drop/dynamic-drop.rs @@ -343,6 +343,17 @@ fn if_let_guard(a: &Allocator, c: bool, d: i32) { } } +fn if_let_guard_2(a: &Allocator, num: i32) { + let d = a.alloc(); + match num { + #[allow(irrefutable_let_patterns)] + 1 | 2 if let Ptr(ref _idx, _) = a.alloc() => { + a.alloc(); + } + _ => {} + } +} + fn panic_after_return(a: &Allocator) -> Ptr<'_> { // Panic in the drop of `p` or `q` can leak let exceptions = vec![8, 9]; @@ -514,6 +525,9 @@ fn main() { run_test(|a| if_let_guard(a, false, 0)); run_test(|a| if_let_guard(a, false, 1)); run_test(|a| if_let_guard(a, false, 2)); + run_test(|a| if_let_guard_2(a, 0)); + run_test(|a| if_let_guard_2(a, 1)); + run_test(|a| if_let_guard_2(a, 2)); run_test(|a| { panic_after_return(a); diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/drop-order.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/drop-order.rs new file mode 100644 index 0000000000000..9bb25a66f0927 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/drop-order.rs @@ -0,0 +1,59 @@ +// check drop order of temporaries create in match guards. +// For normal guards all temporaries are dropped before the body of the arm. +// For let guards temporaries live until the end of the arm. + +// run-pass + +#![feature(if_let_guard)] +#![allow(irrefutable_let_patterns)] + +use std::sync::Mutex; + +static A: Mutex> = Mutex::new(Vec::new()); + +struct D(i32); + +fn make_d(x: i32) -> D { + A.lock().unwrap().push(x); + D(x) +} + +impl Drop for D { + fn drop(&mut self) { + A.lock().unwrap().push(!self.0); + } +} + +fn if_guard(num: i32) { + let _d = make_d(1); + match num { + 1 | 2 if make_d(2).0 == 2 => { + make_d(3); + } + _ => {} + } +} + +fn if_let_guard(num: i32) { + let _d = make_d(1); + match num { + 1 | 2 if let D(ref _x) = make_d(2) => { + make_d(3); + } + _ => {} + } +} + +fn main() { + if_guard(1); + if_guard(2); + if_let_guard(1); + if_let_guard(2); + let expected = [ + 1, 2, !2, 3, !3, !1, + 1, 2, !2, 3, !3, !1, + 1, 2, 3, !3, !2, !1, + 1, 2, 3, !3, !2, !1, + ]; + assert_eq!(*A.lock().unwrap(), expected); +} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/loop-mutability.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/loop-mutability.rs new file mode 100644 index 0000000000000..349a24579a473 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/loop-mutability.rs @@ -0,0 +1,19 @@ +// check-pass + +#![feature(if_let_guard)] + +fn split_last(_: &()) -> Option<(&i32, &i32)> { + None +} + +fn assign_twice() { + loop { + match () { + #[allow(irrefutable_let_patterns)] + () if let _ = split_last(&()) => {} + _ => {} + } + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/scoping-consistency-async.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/scoping-consistency-async.rs new file mode 100644 index 0000000000000..86a170141f8a0 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/scoping-consistency-async.rs @@ -0,0 +1,32 @@ +// Check that temporaries in if-let guards are correctly scoped. +// Regression test for #116079. + +// build-pass +// edition:2018 +// -Zvalidate-mir + +#![feature(if_let_guard)] + +static mut A: [i32; 5] = [1, 2, 3, 4, 5]; + +async fn fun() { + unsafe { + match A { + _ => (), + i if let Some(1) = async { Some(1) }.await => (), + _ => (), + } + } +} + +async fn funner() { + unsafe { + match A { + _ => (), + _ | _ if let Some(1) = async { Some(1) }.await => (), + _ => (), + } + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/scoping-consistency.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/scoping-consistency.rs new file mode 100644 index 0000000000000..37fe610637e9d --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/scoping-consistency.rs @@ -0,0 +1,24 @@ +// Check that temporaries in if-let guards are correctly scoped. + +// build-pass +// -Zvalidate-mir + +#![feature(if_let_guard)] + +fn fun() { + match 0 { + _ => (), + _ if let Some(s) = std::convert::identity(&Some(String::new())) => {} + _ => (), + } +} + +fn funner() { + match 0 { + _ => (), + _ | _ if let Some(s) = std::convert::identity(&Some(String::new())) => {} + _ => (), + } +} + +fn main() {} diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout index 60c9283abcff8..e752e4a870215 100644 --- a/tests/ui/thir-print/thir-tree-match.stdout +++ b/tests/ui/thir-print/thir-tree-match.stdout @@ -124,7 +124,7 @@ body: body: Expr { ty: bool - temp_lifetime: Some(Node(13)) + temp_lifetime: Some(Node(12)) span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) kind: Scope { @@ -133,7 +133,7 @@ body: value: Expr { ty: bool - temp_lifetime: Some(Node(13)) + temp_lifetime: Some(Node(12)) span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) kind: Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) }, neg: false) @@ -176,7 +176,7 @@ body: body: Expr { ty: bool - temp_lifetime: Some(Node(19)) + temp_lifetime: Some(Node(18)) span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) kind: Scope { @@ -185,7 +185,7 @@ body: value: Expr { ty: bool - temp_lifetime: Some(Node(19)) + temp_lifetime: Some(Node(18)) span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) kind: Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) }, neg: false) @@ -220,7 +220,7 @@ body: body: Expr { ty: bool - temp_lifetime: Some(Node(24)) + temp_lifetime: Some(Node(23)) span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) kind: Scope { @@ -229,7 +229,7 @@ body: value: Expr { ty: bool - temp_lifetime: Some(Node(24)) + temp_lifetime: Some(Node(23)) span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) kind: Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) }, neg: false)