about summary refs log tree commit diff
diff options
context:
space:
mode:
authorvarkor <github@varkor.com>2018-06-23 13:12:15 +0100
committervarkor <github@varkor.com>2018-06-23 18:00:47 +0100
commit4efd5c75a8d03b9ad2b5d7de3d58eb342428844d (patch)
tree0aed3c0ed29656fd3776340493824d9516fd4336
parentf68ee0b4e14a8a7e50587bf9752fc1aa72297770 (diff)
downloadrust-4efd5c75a8d03b9ad2b5d7de3d58eb342428844d.tar.gz
rust-4efd5c75a8d03b9ad2b5d7de3d58eb342428844d.zip
Fix an ICE with continue inside a closure inside a loop condition
-rw-r--r--src/librustc/hir/lowering.rs40
-rw-r--r--src/test/ui/closure-array-break-length.rs2
-rw-r--r--src/test/ui/closure-array-break-length.stderr11
3 files changed, 36 insertions, 17 deletions
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 02e9415fd8e..13e033e67fc 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 67feed38b6c..4b0e941a3ce 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 a1e28e84ced..7cedcb254d6 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`.