Skip to content

Commit f2348fb

Browse files
committed
Auto merge of rust-lang#119122 - matthewjasper:if-let-guard-scoping, r=TaKO8Ki
Give temporaries in if let guards correct scopes Temporaries in if-let guards have scopes that escape the match arm, this causes problems because the drops might be for temporaries that are not storage live. This PR changes the scope of temporaries in if-let guards to be limited to the arm: ```rust _ if let Some(s) = std::convert::identity(&Some(String::new())) => {} // Temporary for Some(String::new()) is dropped here ^ ``` We also now deduplicate temporaries between copies of the guard created for or-patterns: ```rust // Only create a single Some(String::new()) temporary variable _ | _ if let Some(s) = std::convert::identity(&Some(String::new())) => {} ``` This changes MIR building to pass around `ExprId`s rather than `Expr`s so that we have a way to index different expressions. cc rust-lang#51114 Closes rust-lang#116079
2 parents b87f649 + d437a11 commit f2348fb

File tree

17 files changed

+387
-245
lines changed

17 files changed

+387
-245
lines changed

Diff for: compiler/rustc_hir_analysis/src/check/region.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -179,10 +179,10 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h
179179
fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir::Arm<'tcx>) {
180180
let prev_cx = visitor.cx;
181181

182-
visitor.enter_scope(Scope { id: arm.hir_id.local_id, data: ScopeData::Node });
183-
visitor.cx.var_parent = visitor.cx.parent;
182+
visitor.terminating_scopes.insert(arm.hir_id.local_id);
184183

185-
visitor.terminating_scopes.insert(arm.body.hir_id.local_id);
184+
visitor.enter_node_scope_with_dtor(arm.hir_id.local_id);
185+
visitor.cx.var_parent = visitor.cx.parent;
186186

187187
if let Some(hir::Guard::If(expr)) = arm.guard {
188188
visitor.terminating_scopes.insert(expr.hir_id.local_id);

Diff for: compiler/rustc_mir_build/src/build/block.rs

+9-11
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1515
) -> BlockAnd<()> {
1616
let Block { region_scope, span, ref stmts, expr, targeted_by_break, safety_mode } =
1717
self.thir[ast_block];
18-
let expr = expr.map(|expr| &self.thir[expr]);
1918
self.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
2019
if targeted_by_break {
2120
this.in_breakable_scope(None, destination, span, |this| {
@@ -49,7 +48,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
4948
mut block: BasicBlock,
5049
span: Span,
5150
stmts: &[StmtId],
52-
expr: Option<&Expr<'tcx>>,
51+
expr: Option<ExprId>,
5352
safety_mode: BlockSafety,
5453
region_scope: Scope,
5554
) -> BlockAnd<()> {
@@ -90,7 +89,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
9089
let si = (*scope, source_info);
9190
unpack!(
9291
block = this.in_scope(si, LintLevel::Inherited, |this| {
93-
this.stmt_expr(block, &this.thir[*expr], Some(*scope))
92+
this.stmt_expr(block, *expr, Some(*scope))
9493
})
9594
);
9695
}
@@ -205,8 +204,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
205204
let visibility_scope =
206205
Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None));
207206

208-
let init = &this.thir[*initializer];
209-
let initializer_span = init.span;
207+
let initializer_span = this.thir[*initializer].span;
210208
let scope = (*init_scope, source_info);
211209
let failure = unpack!(
212210
block = this.in_scope(scope, *lint_level, |this| {
@@ -232,7 +230,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
232230
);
233231
this.ast_let_else(
234232
block,
235-
init,
233+
*initializer,
236234
initializer_span,
237235
*else_block,
238236
&last_remainder_scope,
@@ -276,9 +274,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
276274
Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None));
277275

278276
// Evaluate the initializer, if present.
279-
if let Some(init) = initializer {
280-
let init = &this.thir[*init];
281-
let initializer_span = init.span;
277+
if let Some(init) = *initializer {
278+
let initializer_span = this.thir[init].span;
282279
let scope = (*init_scope, source_info);
283280

284281
unpack!(
@@ -334,13 +331,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
334331
// of the block, which is stored into `destination`.
335332
let tcx = this.tcx;
336333
let destination_ty = destination.ty(&this.local_decls, tcx).ty;
337-
if let Some(expr) = expr {
334+
if let Some(expr_id) = expr {
335+
let expr = &this.thir[expr_id];
338336
let tail_result_is_ignored =
339337
destination_ty.is_unit() || this.block_context.currently_ignores_tail_results();
340338
this.block_context
341339
.push(BlockFrame::TailExpr { tail_result_is_ignored, span: expr.span });
342340

343-
unpack!(block = this.expr_into_dest(destination, block, expr));
341+
unpack!(block = this.expr_into_dest(destination, block, expr_id));
344342
let popped = this.block_context.pop();
345343

346344
assert!(popped.is_some_and(|bf| bf.is_tail_expr()));

Diff for: compiler/rustc_mir_build/src/build/expr/as_operand.rs

+13-13
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1717
pub(crate) fn as_local_operand(
1818
&mut self,
1919
block: BasicBlock,
20-
expr: &Expr<'tcx>,
20+
expr_id: ExprId,
2121
) -> BlockAnd<Operand<'tcx>> {
2222
let local_scope = self.local_scope();
23-
self.as_operand(block, Some(local_scope), expr, LocalInfo::Boring, NeedsTemporary::Maybe)
23+
self.as_operand(block, Some(local_scope), expr_id, LocalInfo::Boring, NeedsTemporary::Maybe)
2424
}
2525

2626
/// 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> {
7676
pub(crate) fn as_local_call_operand(
7777
&mut self,
7878
block: BasicBlock,
79-
expr: &Expr<'tcx>,
79+
expr: ExprId,
8080
) -> BlockAnd<Operand<'tcx>> {
8181
let local_scope = self.local_scope();
8282
self.as_call_operand(block, Some(local_scope), expr)
@@ -101,17 +101,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
101101
&mut self,
102102
mut block: BasicBlock,
103103
scope: Option<region::Scope>,
104-
expr: &Expr<'tcx>,
104+
expr_id: ExprId,
105105
local_info: LocalInfo<'tcx>,
106106
needs_temporary: NeedsTemporary,
107107
) -> BlockAnd<Operand<'tcx>> {
108108
let this = self;
109109

110+
let expr = &this.thir[expr_id];
110111
if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
111112
let source_info = this.source_info(expr.span);
112113
let region_scope = (region_scope, source_info);
113114
return this.in_scope(region_scope, lint_level, |this| {
114-
this.as_operand(block, scope, &this.thir[value], local_info, needs_temporary)
115+
this.as_operand(block, scope, value, local_info, needs_temporary)
115116
});
116117
}
117118

@@ -126,7 +127,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
126127
block.and(Operand::Constant(Box::new(constant)))
127128
}
128129
Category::Constant | Category::Place | Category::Rvalue(..) => {
129-
let operand = unpack!(block = this.as_temp(block, scope, expr, Mutability::Mut));
130+
let operand = unpack!(block = this.as_temp(block, scope, expr_id, Mutability::Mut));
130131
// Overwrite temp local info if we have something more interesting to record.
131132
if !matches!(local_info, LocalInfo::Boring) {
132133
let decl_info =
@@ -144,16 +145,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
144145
&mut self,
145146
mut block: BasicBlock,
146147
scope: Option<region::Scope>,
147-
expr: &Expr<'tcx>,
148+
expr_id: ExprId,
148149
) -> BlockAnd<Operand<'tcx>> {
149-
debug!("as_call_operand(block={:?}, expr={:?})", block, expr);
150150
let this = self;
151+
let expr = &this.thir[expr_id];
152+
debug!("as_call_operand(block={:?}, expr={:?})", block, expr);
151153

152154
if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
153155
let source_info = this.source_info(expr.span);
154156
let region_scope = (region_scope, source_info);
155157
return this.in_scope(region_scope, lint_level, |this| {
156-
this.as_call_operand(block, scope, &this.thir[value])
158+
this.as_call_operand(block, scope, value)
157159
});
158160
}
159161

@@ -171,9 +173,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
171173
// type, and that value is coming from the deref of a box.
172174
if let ExprKind::Deref { arg } = expr.kind {
173175
// Generate let tmp0 = arg0
174-
let operand = unpack!(
175-
block = this.as_temp(block, scope, &this.thir[arg], Mutability::Mut)
176-
);
176+
let operand = unpack!(block = this.as_temp(block, scope, arg, Mutability::Mut));
177177

178178
// Return the operand *tmp0 to be used as the call argument
179179
let place = Place {
@@ -186,6 +186,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
186186
}
187187
}
188188

189-
this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::Maybe)
189+
this.as_operand(block, scope, expr_id, LocalInfo::Boring, NeedsTemporary::Maybe)
190190
}
191191
}

Diff for: compiler/rustc_mir_build/src/build/expr/as_place.rs

+26-31
Original file line numberDiff line numberDiff line change
@@ -354,9 +354,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
354354
pub(crate) fn as_place(
355355
&mut self,
356356
mut block: BasicBlock,
357-
expr: &Expr<'tcx>,
357+
expr_id: ExprId,
358358
) -> BlockAnd<Place<'tcx>> {
359-
let place_builder = unpack!(block = self.as_place_builder(block, expr));
359+
let place_builder = unpack!(block = self.as_place_builder(block, expr_id));
360360
block.and(place_builder.to_place(self))
361361
}
362362

@@ -365,9 +365,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
365365
pub(crate) fn as_place_builder(
366366
&mut self,
367367
block: BasicBlock,
368-
expr: &Expr<'tcx>,
368+
expr_id: ExprId,
369369
) -> BlockAnd<PlaceBuilder<'tcx>> {
370-
self.expr_as_place(block, expr, Mutability::Mut, None)
370+
self.expr_as_place(block, expr_id, Mutability::Mut, None)
371371
}
372372

373373
/// Compile `expr`, yielding a place that we can move from etc.
@@ -378,9 +378,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
378378
pub(crate) fn as_read_only_place(
379379
&mut self,
380380
mut block: BasicBlock,
381-
expr: &Expr<'tcx>,
381+
expr_id: ExprId,
382382
) -> BlockAnd<Place<'tcx>> {
383-
let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr));
383+
let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr_id));
384384
block.and(place_builder.to_place(self))
385385
}
386386

@@ -393,18 +393,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
393393
fn as_read_only_place_builder(
394394
&mut self,
395395
block: BasicBlock,
396-
expr: &Expr<'tcx>,
396+
expr_id: ExprId,
397397
) -> BlockAnd<PlaceBuilder<'tcx>> {
398-
self.expr_as_place(block, expr, Mutability::Not, None)
398+
self.expr_as_place(block, expr_id, Mutability::Not, None)
399399
}
400400

401401
fn expr_as_place(
402402
&mut self,
403403
mut block: BasicBlock,
404-
expr: &Expr<'tcx>,
404+
expr_id: ExprId,
405405
mutability: Mutability,
406406
fake_borrow_temps: Option<&mut Vec<Local>>,
407407
) -> BlockAnd<PlaceBuilder<'tcx>> {
408+
let expr = &self.thir[expr_id];
408409
debug!("expr_as_place(block={:?}, expr={:?}, mutability={:?})", block, expr, mutability);
409410

410411
let this = self;
@@ -413,31 +414,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
413414
match expr.kind {
414415
ExprKind::Scope { region_scope, lint_level, value } => {
415416
this.in_scope((region_scope, source_info), lint_level, |this| {
416-
this.expr_as_place(block, &this.thir[value], mutability, fake_borrow_temps)
417+
this.expr_as_place(block, value, mutability, fake_borrow_temps)
417418
})
418419
}
419420
ExprKind::Field { lhs, variant_index, name } => {
420-
let lhs = &this.thir[lhs];
421+
let lhs_expr = &this.thir[lhs];
421422
let mut place_builder =
422423
unpack!(block = this.expr_as_place(block, lhs, mutability, fake_borrow_temps,));
423-
if let ty::Adt(adt_def, _) = lhs.ty.kind() {
424+
if let ty::Adt(adt_def, _) = lhs_expr.ty.kind() {
424425
if adt_def.is_enum() {
425426
place_builder = place_builder.downcast(*adt_def, variant_index);
426427
}
427428
}
428429
block.and(place_builder.field(name, expr.ty))
429430
}
430431
ExprKind::Deref { arg } => {
431-
let place_builder = unpack!(
432-
block =
433-
this.expr_as_place(block, &this.thir[arg], mutability, fake_borrow_temps,)
434-
);
432+
let place_builder =
433+
unpack!(block = this.expr_as_place(block, arg, mutability, fake_borrow_temps,));
435434
block.and(place_builder.deref())
436435
}
437436
ExprKind::Index { lhs, index } => this.lower_index_expression(
438437
block,
439-
&this.thir[lhs],
440-
&this.thir[index],
438+
lhs,
439+
index,
441440
mutability,
442441
fake_borrow_temps,
443442
expr.temp_lifetime,
@@ -461,12 +460,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
461460

462461
ExprKind::PlaceTypeAscription { source, ref user_ty } => {
463462
let place_builder = unpack!(
464-
block = this.expr_as_place(
465-
block,
466-
&this.thir[source],
467-
mutability,
468-
fake_borrow_temps,
469-
)
463+
block = this.expr_as_place(block, source, mutability, fake_borrow_temps,)
470464
);
471465
if let Some(user_ty) = user_ty {
472466
let annotation_index =
@@ -494,9 +488,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
494488
block.and(place_builder)
495489
}
496490
ExprKind::ValueTypeAscription { source, ref user_ty } => {
497-
let source = &this.thir[source];
498-
let temp =
499-
unpack!(block = this.as_temp(block, source.temp_lifetime, source, mutability));
491+
let source_expr = &this.thir[source];
492+
let temp = unpack!(
493+
block = this.as_temp(block, source_expr.temp_lifetime, source, mutability)
494+
);
500495
if let Some(user_ty) = user_ty {
501496
let annotation_index =
502497
this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
@@ -562,7 +557,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
562557
// these are not places, so we need to make a temporary.
563558
debug_assert!(!matches!(Category::of(&expr.kind), Some(Category::Place)));
564559
let temp =
565-
unpack!(block = this.as_temp(block, expr.temp_lifetime, expr, mutability));
560+
unpack!(block = this.as_temp(block, expr.temp_lifetime, expr_id, mutability));
566561
block.and(PlaceBuilder::from(temp))
567562
}
568563
}
@@ -591,8 +586,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
591586
fn lower_index_expression(
592587
&mut self,
593588
mut block: BasicBlock,
594-
base: &Expr<'tcx>,
595-
index: &Expr<'tcx>,
589+
base: ExprId,
590+
index: ExprId,
596591
mutability: Mutability,
597592
fake_borrow_temps: Option<&mut Vec<Local>>,
598593
temp_lifetime: Option<region::Scope>,
@@ -609,7 +604,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
609604
// Making this a *fresh* temporary means we do not have to worry about
610605
// the index changing later: Nothing will ever change this temporary.
611606
// The "retagging" transformation (for Stacked Borrows) relies on this.
612-
let idx = unpack!(block = self.as_temp(block, temp_lifetime, index, Mutability::Not,));
607+
let idx = unpack!(block = self.as_temp(block, temp_lifetime, index, Mutability::Not));
613608

614609
block = self.bounds_check(block, &base_place, idx, expr_span, source_info);
615610

0 commit comments

Comments
 (0)