From f68ee0b4e14a8a7e50587bf9752fc1aa72297770 Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 23 Jun 2018 11:52:45 +0100 Subject: [PATCH 1/5] Fix an ICE with `continue` as an array length --- src/librustc_typeck/check/mod.rs | 9 ++++++++- src/test/ui/closure-array-break-length.rs | 13 +++++++++++++ src/test/ui/closure-array-break-length.stderr | 9 +++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/closure-array-break-length.rs create mode 100644 src/test/ui/closure-array-break-length.stderr diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e84586520b1e4..889073f6b4ca9 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3846,7 +3846,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - hir::ExprContinue(_) => { tcx.types.never } + hir::ExprContinue(destination) => { + if let Ok(_) = destination.target_id { + tcx.types.never + } else { + // There was an error, make typecheck fail + tcx.types.err + } + } hir::ExprRet(ref expr_opt) => { if self.ret_coercion.is_none() { struct_span_err!(self.tcx.sess, expr.span, E0572, diff --git a/src/test/ui/closure-array-break-length.rs b/src/test/ui/closure-array-break-length.rs new file mode 100644 index 0000000000000..67feed38b6c3d --- /dev/null +++ b/src/test/ui/closure-array-break-length.rs @@ -0,0 +1,13 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + |_: [_; continue]| {}; //~ ERROR: `continue` outside of loop +} diff --git a/src/test/ui/closure-array-break-length.stderr b/src/test/ui/closure-array-break-length.stderr new file mode 100644 index 0000000000000..a1e28e84ced66 --- /dev/null +++ b/src/test/ui/closure-array-break-length.stderr @@ -0,0 +1,9 @@ +error[E0268]: `continue` outside of loop + --> $DIR/closure-array-break-length.rs:12:13 + | +LL | |_: [_; continue]| {}; //~ ERROR: `continue` outside of loop + | ^^^^^^^^ cannot break outside of a loop + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0268`. From 4efd5c75a8d03b9ad2b5d7de3d58eb342428844d Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 23 Jun 2018 13:12:15 +0100 Subject: [PATCH 2/5] Fix an ICE with continue inside a closure inside a loop condition --- src/librustc/hir/lowering.rs | 40 ++++++++++++------- src/test/ui/closure-array-break-length.rs | 2 + src/test/ui/closure-array-break-length.stderr | 11 ++++- 3 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 02e9415fd8e3c..13e033e67fcbb 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -3538,12 +3538,22 @@ impl<'a> LoweringContext<'a> { this.expr_block(block, ThinVec::new()) }) }) - }, + } ExprKind::Closure( - capture_clause, asyncness, movability, ref decl, ref body, fn_decl_span) => - { - self.with_new_scopes(|this| { - if let IsAsync::Async(async_closure_node_id) = asyncness { + capture_clause, asyncness, movability, ref decl, ref body, fn_decl_span + ) => { + if let IsAsync::Async(async_closure_node_id) = asyncness { + let outer_decl = FnDecl { + inputs: decl.inputs.clone(), + output: FunctionRetTy::Default(fn_decl_span), + variadic: false, + }; + // We need to lower the declaration outside the new scope, because we + // have to conserve the state of being inside a loop condition for the + // closure argument types. + let fn_decl = self.lower_fn_decl(&outer_decl, None, false, false); + + self.with_new_scopes(|this| { // FIXME(cramertj) allow `async` non-`move` closures with if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() @@ -3563,11 +3573,6 @@ impl<'a> LoweringContext<'a> { // Transform `async |x: u8| -> X { ... }` into // `|x: u8| future_from_generator(|| -> X { ... })` - let outer_decl = FnDecl { - inputs: decl.inputs.clone(), - output: FunctionRetTy::Default(fn_decl_span), - variadic: false, - }; let body_id = this.lower_body(Some(&outer_decl), |this| { let async_ret_ty = if let FunctionRetTy::Ty(ty) = &decl.output { Some(&**ty) @@ -3581,12 +3586,17 @@ impl<'a> LoweringContext<'a> { }); hir::ExprClosure( this.lower_capture_clause(capture_clause), - this.lower_fn_decl(&outer_decl, None, false, false), + fn_decl, body_id, fn_decl_span, None, ) - } else { + }) + } else { + // Lower outside new scope to preserve `is_in_loop_condition`. + let fn_decl = self.lower_fn_decl(decl, None, false, false); + + self.with_new_scopes(|this| { let mut is_generator = false; let body_id = this.lower_body(Some(decl), |this| { let e = this.lower_expr(body); @@ -3620,13 +3630,13 @@ impl<'a> LoweringContext<'a> { }; hir::ExprClosure( this.lower_capture_clause(capture_clause), - this.lower_fn_decl(decl, None, false, false), + fn_decl, body_id, fn_decl_span, generator_option, ) - } - }) + }) + } } ExprKind::Block(ref blk, opt_label) => { hir::ExprBlock(self.lower_block(blk, diff --git a/src/test/ui/closure-array-break-length.rs b/src/test/ui/closure-array-break-length.rs index 67feed38b6c3d..4b0e941a3ce2a 100644 --- a/src/test/ui/closure-array-break-length.rs +++ b/src/test/ui/closure-array-break-length.rs @@ -10,4 +10,6 @@ fn main() { |_: [_; continue]| {}; //~ ERROR: `continue` outside of loop + + while |_: [_; continue]| {} {} //~ ERROR: `break` or `continue` with no label } diff --git a/src/test/ui/closure-array-break-length.stderr b/src/test/ui/closure-array-break-length.stderr index a1e28e84ced66..7cedcb254d697 100644 --- a/src/test/ui/closure-array-break-length.stderr +++ b/src/test/ui/closure-array-break-length.stderr @@ -4,6 +4,13 @@ error[E0268]: `continue` outside of loop LL | |_: [_; continue]| {}; //~ ERROR: `continue` outside of loop | ^^^^^^^^ cannot break outside of a loop -error: aborting due to previous error +error[E0590]: `break` or `continue` with no label in the condition of a `while` loop + --> $DIR/closure-array-break-length.rs:14:19 + | +LL | while |_: [_; continue]| {} {} //~ ERROR: `break` or `continue` with no label + | ^^^^^^^^ unlabeled `continue` in the condition of a `while` loop + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0268`. +Some errors occurred: E0268, E0590. +For more information about an error, try `rustc --explain E0268`. From dc7d77f88e213214d144643612939d52431396c9 Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 23 Jun 2018 13:21:09 +0100 Subject: [PATCH 3/5] Add a test for break --- src/test/ui/closure-array-break-length.rs | 2 ++ src/test/ui/closure-array-break-length.stderr | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/test/ui/closure-array-break-length.rs b/src/test/ui/closure-array-break-length.rs index 4b0e941a3ce2a..2e99921956ab2 100644 --- a/src/test/ui/closure-array-break-length.rs +++ b/src/test/ui/closure-array-break-length.rs @@ -12,4 +12,6 @@ fn main() { |_: [_; continue]| {}; //~ ERROR: `continue` outside of loop while |_: [_; continue]| {} {} //~ ERROR: `break` or `continue` with no label + + while |_: [_; break]| {} {} //~ ERROR: `break` or `continue` with no label } diff --git a/src/test/ui/closure-array-break-length.stderr b/src/test/ui/closure-array-break-length.stderr index 7cedcb254d697..139153992e274 100644 --- a/src/test/ui/closure-array-break-length.stderr +++ b/src/test/ui/closure-array-break-length.stderr @@ -10,7 +10,13 @@ error[E0590]: `break` or `continue` with no label in the condition of a `while` LL | while |_: [_; continue]| {} {} //~ ERROR: `break` or `continue` with no label | ^^^^^^^^ unlabeled `continue` in the condition of a `while` loop -error: aborting due to 2 previous errors +error[E0590]: `break` or `continue` with no label in the condition of a `while` loop + --> $DIR/closure-array-break-length.rs:16:19 + | +LL | while |_: [_; break]| {} {} //~ ERROR: `break` or `continue` with no label + | ^^^^^ unlabeled `break` in the condition of a `while` loop + +error: aborting due to 3 previous errors Some errors occurred: E0268, E0590. For more information about an error, try `rustc --explain E0268`. From ee7e30f14aa8437294aca766440ef1897d1a5703 Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 23 Jun 2018 16:32:32 +0100 Subject: [PATCH 4/5] Fix codegen tests --- src/test/mir-opt/end_region_6.rs | 6 +++--- src/test/mir-opt/end_region_7.rs | 6 +++--- src/test/mir-opt/validate_1.rs | 6 +++--- src/test/mir-opt/validate_5.rs | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/test/mir-opt/end_region_6.rs b/src/test/mir-opt/end_region_6.rs index dadc755eb8c57..30ba14c1bab3a 100644 --- a/src/test/mir-opt/end_region_6.rs +++ b/src/test/mir-opt/end_region_6.rs @@ -68,17 +68,17 @@ fn foo(f: F) where F: FnOnce() -> i32 { // fn main::{{closure}}(_1: [closure@NodeId(22) d:&'19s D]) -> i32 { // let mut _0: i32; // ... -// let _2: &'15_0rs D; +// let _2: &'16_0rs D; // ... // let mut _3: i32; // bb0: { // StorageLive(_2); -// _2 = &'15_0rs (*(_1.0: &'19s D)); +// _2 = &'16_0rs (*(_1.0: &'19s D)); // StorageLive(_3); // _3 = ((*_2).0: i32); // _0 = move _3; // StorageDead(_3); -// EndRegion('15_0rs); +// EndRegion('16_0rs); // StorageDead(_2); // return; // } diff --git a/src/test/mir-opt/end_region_7.rs b/src/test/mir-opt/end_region_7.rs index 1426174b482b6..6d6afa25ae30e 100644 --- a/src/test/mir-opt/end_region_7.rs +++ b/src/test/mir-opt/end_region_7.rs @@ -76,17 +76,17 @@ fn foo(f: F) where F: FnOnce() -> i32 { // fn main::{{closure}}(_1: [closure@NodeId(22) d:D]) -> i32 { // let mut _0: i32; // ... -// let _2: &'15_0rs D; +// let _2: &'16_0rs D; // ... // let mut _3: i32; // bb0: { // StorageLive(_2); -// _2 = &'15_0rs (_1.0: D); +// _2 = &'16_0rs (_1.0: D); // StorageLive(_3); // _3 = ((*_2).0: i32); // _0 = move _3; // StorageDead(_3); -// EndRegion('15_0rs); +// EndRegion('16_0rs); // StorageDead(_2); // drop(_1) -> [return: bb2, unwind: bb1]; // } diff --git a/src/test/mir-opt/validate_1.rs b/src/test/mir-opt/validate_1.rs index e6cd535500055..c331276aade77 100644 --- a/src/test/mir-opt/validate_1.rs +++ b/src/test/mir-opt/validate_1.rs @@ -64,14 +64,14 @@ fn main() { // bb0: { // Validate(Acquire, [_1: &ReFree(DefId(0/1:11 ~ validate_1[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(50)], _2: &ReFree(DefId(0/1:11 ~ validate_1[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]); // StorageLive(_3); -// Validate(Suspend(ReScope(Remainder(BlockRemainder { block: ItemLocalId(22), first_statement_index: 0 }))), [(*_2): i32]); +// Validate(Suspend(ReScope(Remainder(BlockRemainder { block: ItemLocalId(25), first_statement_index: 0 }))), [(*_2): i32]); // _3 = &ReErased (*_2); -// Validate(Acquire, [(*_3): i32/ReScope(Remainder(BlockRemainder { block: ItemLocalId(22), first_statement_index: 0 })) (imm)]); +// Validate(Acquire, [(*_3): i32/ReScope(Remainder(BlockRemainder { block: ItemLocalId(25), first_statement_index: 0 })) (imm)]); // StorageLive(_4); // _4 = (*_3); // _0 = move _4; // StorageDead(_4); -// EndRegion(ReScope(Remainder(BlockRemainder { block: ItemLocalId(22), first_statement_index: 0 }))); +// EndRegion(ReScope(Remainder(BlockRemainder { block: ItemLocalId(25), first_statement_index: 0 }))); // StorageDead(_3); // return; // } diff --git a/src/test/mir-opt/validate_5.rs b/src/test/mir-opt/validate_5.rs index d8d83fb5b4537..b4d4479bab94a 100644 --- a/src/test/mir-opt/validate_5.rs +++ b/src/test/mir-opt/validate_5.rs @@ -53,12 +53,12 @@ fn main() { // StorageLive(_3); // StorageLive(_4); // StorageLive(_5); -// Validate(Suspend(ReScope(Node(ItemLocalId(9)))), [(*_2): i32]); +// Validate(Suspend(ReScope(Node(ItemLocalId(12)))), [(*_2): i32]); // _5 = &ReErased mut (*_2); -// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(9)))]); +// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(12)))]); // _4 = move _5 as *mut i32 (Misc); // _3 = move _4; -// EndRegion(ReScope(Node(ItemLocalId(9)))); +// EndRegion(ReScope(Node(ItemLocalId(12)))); // StorageDead(_4); // StorageDead(_5); // Validate(Release, [_0: bool, _3: *mut i32]); From c3d6ee9e7b652546b892bc2eac56896a8a39415a Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 25 Jun 2018 15:27:37 +0100 Subject: [PATCH 5/5] Make find_breakable_scope non-mutable --- src/librustc_mir/build/scope.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index ee0a087a1dd0a..b9d6486d9174a 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -540,12 +540,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // ============== /// Finds the breakable scope for a given label. This is used for /// resolving `break` and `continue`. - pub fn find_breakable_scope(&mut self, + pub fn find_breakable_scope(&self, span: Span, label: region::Scope) - -> &mut BreakableScope<'tcx> { + -> &BreakableScope<'tcx> { // find the loop-scope with the correct id - self.breakable_scopes.iter_mut() + self.breakable_scopes.iter() .rev() .filter(|breakable_scope| breakable_scope.region_scope == label) .next()