Skip to content

Commit 018525e

Browse files
committed
address review comments
1 parent 5c0feb8 commit 018525e

File tree

6 files changed

+95
-16
lines changed

6 files changed

+95
-16
lines changed

src/librustc/hir/intravisit.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -411,10 +411,13 @@ pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body) {
411411
}
412412

413413
pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) {
414+
// Intentionally visiting the expr first - the initialization expr
415+
// dominates the local's definition.
416+
walk_list!(visitor, visit_expr, &local.init);
417+
414418
visitor.visit_id(local.id);
415419
visitor.visit_pat(&local.pat);
416420
walk_list!(visitor, visit_ty, &local.ty);
417-
walk_list!(visitor, visit_expr, &local.init);
418421
}
419422

420423
pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {

src/librustc/middle/region.rs

+53-13
Original file line numberDiff line numberDiff line change
@@ -259,8 +259,37 @@ pub struct ScopeTree {
259259
/// lower than theirs, and therefore don't need to be suspended
260260
/// at yield-points at these indexes.
261261
///
262-
/// Let's show that: let `D` be our binding/temporary and `U` be our
263-
/// other HIR node, with `HIR-postorder(U) < HIR-postorder(D)`.
262+
/// For an example, suppose we have some code such as:
263+
/// ```rust,ignore (example)
264+
/// foo(f(), yield y, bar(g()))
265+
/// ```
266+
///
267+
/// With the HIR tree (calls numbered for expository purposes)
268+
/// ```
269+
/// Call#0(foo, [Call#1(f), Yield(y), Call#2(bar, Call#3(g))])
270+
/// ```
271+
///
272+
/// Obviously, the result of `f()` was created before the yield
273+
/// (and therefore needs to be kept valid over the yield) while
274+
/// the result of `g()` occurs after the yield (and therefore
275+
/// doesn't). If we want to infer that, we can look at the
276+
/// postorder traversal:
277+
/// ```
278+
/// `foo` `f` Call#1 `y` Yield `bar` `g` Call#3 Call#2 Call#0
279+
/// ```
280+
///
281+
/// In which we can easily see that `Call#1` occurs before the yield,
282+
/// and `Call#3` after it.
283+
///
284+
/// To see that this method works, consider:
285+
///
286+
/// Let `D` be our binding/temporary and `U` be our other HIR node, with
287+
/// `HIR-postorder(U) < HIR-postorder(D)` (in our example, U would be
288+
/// the yield and D would be one of the calls). Let's show that
289+
/// `D` is storage-dead at `U`.
290+
///
291+
/// Remember that storage-live/storage-dead refers to the state of
292+
/// the *storage*, and does not consider moves/drop flags.
264293
///
265294
/// Then:
266295
/// 1. From the ordering guarantee of HIR visitors (see
@@ -272,17 +301,26 @@ pub struct ScopeTree {
272301
/// or always storage-dead. This is what is being guaranteed
273302
/// by `terminating_scopes` including all blocks where the
274303
/// count of executions is not guaranteed.
275-
/// 4. By `2.` and `3.`, `D` is *statically* dead at `U`,
304+
/// 4. By `2.` and `3.`, `D` is *statically* storage-dead at `U`,
276305
/// QED.
277306
///
278307
/// I don't think this property relies on `3.` in an essential way - it
279308
/// is probably still correct even if we have "unrestricted" terminating
280309
/// scopes. However, why use the complicated proof when a simple one
281310
/// works?
311+
///
312+
/// A subtle thing: `box` expressions, such as `box (&x, yield 2, &y)`. It
313+
/// might seem that a `box` expression creates a `Box<T>` temporary
314+
/// when it *starts* executing, at `HIR-preorder(BOX-EXPR)`. That might
315+
/// be true in the MIR desugaring, but it is not important in the semantics.
316+
///
317+
/// The reason is that semantically, until the `box` expression returns,
318+
/// the values are still owned by their containing expressions. So
319+
/// we'll see that `&x`.
282320
yield_in_scope: FxHashMap<Scope, (Span, usize)>,
283321

284-
/// The number of visit_expr calls done in the body.
285-
/// Used to sanity check visit_expr call count when
322+
/// The number of visit_expr and visit_pat calls done in the body.
323+
/// Used to sanity check visit_expr/visit_pat call count when
286324
/// calculating geneartor interiors.
287325
body_expr_count: FxHashMap<hir::BodyId, usize>,
288326
}
@@ -307,8 +345,8 @@ pub struct Context {
307345
struct RegionResolutionVisitor<'a, 'tcx: 'a> {
308346
tcx: TyCtxt<'a, 'tcx, 'tcx>,
309347

310-
// The number of expressions visited in the current body
311-
expr_count: usize,
348+
// The number of expressions and patterns visited in the current body
349+
expr_and_pat_count: usize,
312350

313351
// Generated scope tree:
314352
scope_tree: ScopeTree,
@@ -758,6 +796,8 @@ fn resolve_pat<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, pat: &
758796
}
759797

760798
intravisit::walk_pat(visitor, pat);
799+
800+
visitor.expr_and_pat_count += 1;
761801
}
762802

763803
fn resolve_stmt<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, stmt: &'tcx hir::Stmt) {
@@ -863,14 +903,14 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
863903
_ => intravisit::walk_expr(visitor, expr)
864904
}
865905

866-
visitor.expr_count += 1;
906+
visitor.expr_and_pat_count += 1;
867907

868908
if let hir::ExprYield(..) = expr.node {
869909
// Mark this expr's scope and all parent scopes as containing `yield`.
870910
let mut scope = Scope::Node(expr.hir_id.local_id);
871911
loop {
872912
visitor.scope_tree.yield_in_scope.insert(scope,
873-
(expr.span, visitor.expr_count));
913+
(expr.span, visitor.expr_and_pat_count));
874914

875915
// Keep traversing up while we can.
876916
match visitor.scope_tree.parent_map.get(&scope) {
@@ -1160,7 +1200,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
11601200
body_id,
11611201
self.cx.parent);
11621202

1163-
let outer_ec = mem::replace(&mut self.expr_count, 0);
1203+
let outer_ec = mem::replace(&mut self.expr_and_pat_count, 0);
11641204
let outer_cx = self.cx;
11651205
let outer_ts = mem::replace(&mut self.terminating_scopes, FxHashSet());
11661206
self.terminating_scopes.insert(body.value.hir_id.local_id);
@@ -1207,11 +1247,11 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
12071247
}
12081248

12091249
if body.is_generator {
1210-
self.scope_tree.body_expr_count.insert(body_id, self.expr_count);
1250+
self.scope_tree.body_expr_count.insert(body_id, self.expr_and_pat_count);
12111251
}
12121252

12131253
// Restore context we had at the start.
1214-
self.expr_count = outer_ec;
1254+
self.expr_and_pat_count = outer_ec;
12151255
self.cx = outer_cx;
12161256
self.terminating_scopes = outer_ts;
12171257
}
@@ -1246,7 +1286,7 @@ fn region_scope_tree<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
12461286
let mut visitor = RegionResolutionVisitor {
12471287
tcx,
12481288
scope_tree: ScopeTree::default(),
1249-
expr_count: 0,
1289+
expr_and_pat_count: 0,
12501290
cx: Context {
12511291
root_id: None,
12521292
parent: None,

src/librustc_mir/build/expr/as_rvalue.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
9696
}
9797
ExprKind::Box { value } => {
9898
let value = this.hir.mirror(value);
99-
let result = this.local_decls.push(LocalDecl::new_temp(expr.ty, expr_span));
99+
// The `Box<T>` temporary created here is not a part of the HIR,
100+
// and therefore is not considered during generator OIBIT
101+
// determination. See the comment about `box` at `yield_in_scope`.
102+
let result = this.local_decls.push(
103+
LocalDecl::new_internal(expr.ty, expr_span));
100104
this.cfg.push(block, Statement {
101105
source_info,
102106
kind: StatementKind::StorageLive(result)

src/librustc_typeck/check/generator_interior.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ impl<'a, 'gcx, 'tcx> InteriorVisitor<'a, 'gcx, 'tcx> {
4141
// be storage-live (and therefore live) at any of the yields.
4242
//
4343
// See the mega-comment at `yield_in_scope` for a proof.
44-
if expr.is_none() || expr_count >= self.expr_count {
44+
if expr_count >= self.expr_count {
4545
Some(span)
4646
} else {
4747
None
@@ -115,6 +115,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'gcx, 'tcx> {
115115
self.record(ty, Some(scope), None);
116116
}
117117

118+
self.expr_count += 1;
119+
118120
intravisit::walk_pat(self, pat);
119121
}
120122

src/test/run-pass/generator/yield-in-args-rev.rs

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
// Test that a borrow that occurs after a yield in the same
12+
// argument list is not treated as live across the yield by
13+
// type-checking.
14+
1115
#![feature(generators)]
1216

1317
fn foo(_a: (), _b: &bool) {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that box-statements with yields in them work.
12+
13+
#![feature(generators, box_syntax)]
14+
15+
fn main() {
16+
let x = 0i32;
17+
|| {
18+
let y = 2u32;
19+
{
20+
let _t = box (&x, yield 0, &y);
21+
}
22+
match box (&x, yield 0, &y) {
23+
_t => {}
24+
}
25+
};
26+
}

0 commit comments

Comments
 (0)