Skip to content

Commit 1808189

Browse files
authored
Rollup merge of #62388 - rust-lang:fix-loop-break-mir-generation, r=eddyb
Break out of the correct number of scopes in loops We were incorrectly breaking out of one too many drop scopes when generating MIR for loops and breakable blocks, resulting in use after free and associated borrow checker warnings. This wasn't noticed because the scope that we're breaking out of twice is only used for temporaries that are created for adjustments applied to the loop. Since loops generally propagate coercions to the `break` expressions, the only case we see this is when the type of the loop is a smart pointer to a trait object. Closes #62312
2 parents cc696b9 + 1b7ffe5 commit 1808189

File tree

5 files changed

+52
-21
lines changed

5 files changed

+52
-21
lines changed

src/librustc_mir/build/matches/mod.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -228,10 +228,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
228228
};
229229

230230
// Step 5. Create everything else: the guards and the arms.
231+
let match_scope = self.scopes.topmost();
232+
231233
let arm_end_blocks: Vec<_> = arm_candidates.into_iter().map(|(arm, mut candidates)| {
232234
let arm_source_info = self.source_info(arm.span);
233-
let region_scope = (arm.scope, arm_source_info);
234-
self.in_scope(region_scope, arm.lint_level, |this| {
235+
let arm_scope = (arm.scope, arm_source_info);
236+
self.in_scope(arm_scope, arm.lint_level, |this| {
235237
let body = this.hir.mirror(arm.body.clone());
236238
let scope = this.declare_bindings(
237239
None,
@@ -248,7 +250,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
248250
arm.guard.clone(),
249251
&fake_borrow_temps,
250252
scrutinee_span,
251-
region_scope,
253+
match_scope,
252254
);
253255
} else {
254256
arm_block = this.cfg.start_new_block();
@@ -259,7 +261,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
259261
arm.guard.clone(),
260262
&fake_borrow_temps,
261263
scrutinee_span,
262-
region_scope,
264+
match_scope,
263265
);
264266
this.cfg.terminate(
265267
binding_end,
@@ -1339,7 +1341,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
13391341
guard: Option<Guard<'tcx>>,
13401342
fake_borrows: &Vec<(&Place<'tcx>, Local)>,
13411343
scrutinee_span: Span,
1342-
region_scope: (region::Scope, SourceInfo),
1344+
region_scope: region::Scope,
13431345
) -> BasicBlock {
13441346
debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate);
13451347

src/librustc_mir/build/mod.rs

+13-8
Original file line numberDiff line numberDiff line change
@@ -604,9 +604,18 @@ where
604604
}
605605

606606
let arg_scope_s = (arg_scope, source_info);
607-
unpack!(block = builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
608-
builder.args_and_body(block, &arguments, arg_scope, &body.value)
609-
}));
607+
// `return_block` is called when we evaluate a `return` expression, so
608+
// we just use `START_BLOCK` here.
609+
unpack!(block = builder.in_breakable_scope(
610+
None,
611+
START_BLOCK,
612+
Place::RETURN_PLACE,
613+
|builder| {
614+
builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
615+
builder.args_and_body(block, &arguments, arg_scope, &body.value)
616+
})
617+
},
618+
));
610619
// Attribute epilogue to function's closing brace
611620
let fn_end = span.shrink_to_hi();
612621
let source_info = builder.source_info(fn_end);
@@ -860,11 +869,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
860869
}
861870

862871
let body = self.hir.mirror(ast_body);
863-
// `return_block` is called when we evaluate a `return` expression, so
864-
// we just use `START_BLOCK` here.
865-
self.in_breakable_scope(None, START_BLOCK, Place::RETURN_PLACE, |this| {
866-
this.into(&Place::RETURN_PLACE, block, body)
867-
})
872+
self.into(&Place::RETURN_PLACE, block, body)
868873
}
869874

870875
fn get_unit_temp(&mut self) -> Place<'tcx> {

src/librustc_mir/build/scope.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -332,9 +332,9 @@ impl<'tcx> Scopes<'tcx> {
332332
}
333333
}
334334

335-
fn num_scopes_to(&self, region_scope: (region::Scope, SourceInfo), span: Span) -> usize {
336-
let scope_count = 1 + self.scopes.iter().rev()
337-
.position(|scope| scope.region_scope == region_scope.0)
335+
fn num_scopes_above(&self, region_scope: region::Scope, span: Span) -> usize {
336+
let scope_count = self.scopes.iter().rev()
337+
.position(|scope| scope.region_scope == region_scope)
338338
.unwrap_or_else(|| {
339339
span_bug!(span, "region_scope {:?} does not enclose", region_scope)
340340
});
@@ -354,7 +354,7 @@ impl<'tcx> Scopes<'tcx> {
354354

355355
/// Returns the topmost active scope, which is known to be alive until
356356
/// the next scope expression.
357-
fn topmost(&self) -> region::Scope {
357+
pub(super) fn topmost(&self) -> region::Scope {
358358
self.scopes.last().expect("topmost_scope: no scopes present").region_scope
359359
}
360360

@@ -514,7 +514,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
514514
} else {
515515
assert!(value.is_none(), "`return` and `break` should have a destination");
516516
}
517-
self.exit_scope(source_info.span, (region_scope, source_info), block, target_block);
517+
self.exit_scope(source_info.span, region_scope, block, target_block);
518518
self.cfg.start_new_block().unit()
519519
}
520520

@@ -523,12 +523,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
523523
/// needed. See module comment for details.
524524
pub fn exit_scope(&mut self,
525525
span: Span,
526-
region_scope: (region::Scope, SourceInfo),
526+
region_scope: region::Scope,
527527
mut block: BasicBlock,
528528
target: BasicBlock) {
529529
debug!("exit_scope(region_scope={:?}, block={:?}, target={:?})",
530530
region_scope, block, target);
531-
let scope_count = self.scopes.num_scopes_to(region_scope, span);
531+
let scope_count = self.scopes.num_scopes_above(region_scope, span);
532532

533533
// If we are emitting a `drop` statement, we need to have the cached
534534
// diverge cleanup pads ready in case that drop panics.
@@ -545,7 +545,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
545545
continue;
546546
}
547547
let source_info = scope.source_info(span);
548-
block = match scope.cached_exits.entry((target, region_scope.0)) {
548+
block = match scope.cached_exits.entry((target, region_scope)) {
549549
Entry::Occupied(e) => {
550550
self.cfg.terminate(block, source_info,
551551
TerminatorKind::Goto { target: *e.get() });
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Regression test for #62312
2+
3+
// check-pass
4+
// edition:2018
5+
6+
#![feature(async_await)]
7+
8+
async fn make_boxed_object() -> Box<dyn Send> {
9+
Box::new(()) as _
10+
}
11+
12+
async fn await_object() {
13+
let _ = make_boxed_object().await;
14+
}
15+
16+
fn main() {}
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Regression test for #62312
2+
// check-pass
3+
4+
fn main() {
5+
let _ = loop {
6+
break Box::new(()) as Box<dyn Send>;
7+
};
8+
}

0 commit comments

Comments
 (0)