about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/hir/lowering.rs60
-rw-r--r--src/librustc/middle/expr_use_visitor.rs53
-rw-r--r--src/librustc/ty/layout.rs8
-rw-r--r--src/librustc_borrowck/borrowck/unused.rs18
-rw-r--r--src/librustc_mir/build/mod.rs13
-rw-r--r--src/librustc_mir/build/scope.rs6
-rw-r--r--src/librustc_mir/hair/pattern/check_match.rs83
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs29
-rw-r--r--src/librustc_passes/loops.rs11
-rw-r--r--src/librustc_typeck/check/mod.rs10
-rw-r--r--src/librustc_typeck/check/regionck.rs12
-rw-r--r--src/librustc_typeck/check/writeback.rs12
-rw-r--r--src/test/ui/array-break-length.rs19
-rw-r--r--src/test/ui/array-break-length.stderr15
-rw-r--r--src/test/ui/closure-array-break-length.rs4
-rw-r--r--src/test/ui/closure-array-break-length.stderr15
-rw-r--r--src/test/ui/issue-51714.rs11
-rw-r--r--src/test/ui/issue-51714.stderr27
-rw-r--r--src/test/ui/return-match-array-const.rs17
-rw-r--r--src/test/ui/return-match-array-const.stderr21
20 files changed, 288 insertions, 156 deletions
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 5990340ae29..56df9533607 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -103,6 +103,7 @@ pub struct LoweringContext<'a> {
     loop_scopes: Vec<NodeId>,
     is_in_loop_condition: bool,
     is_in_trait_impl: bool,
+    is_in_anon_const: bool,
 
     /// What to do when we encounter either an "anonymous lifetime
     /// reference". The term "anonymous" is meant to encompass both
@@ -230,6 +231,7 @@ pub fn lower_crate(
         node_id_to_hir_id: IndexVec::new(),
         is_generator: false,
         is_in_trait_impl: false,
+        is_in_anon_const: false,
         lifetimes_to_define: Vec::new(),
         is_collecting_in_band_lifetimes: false,
         in_scope_lifetimes: Vec::new(),
@@ -968,31 +970,30 @@ impl<'a> LoweringContext<'a> {
     }
 
     fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination {
-        match destination {
-            Some((id, label)) => {
-                let target_id = if let Def::Label(loop_id) = self.expect_full_def(id) {
-                    Ok(self.lower_node_id(loop_id).node_id)
-                } else {
-                    Err(hir::LoopIdError::UnresolvedLabel)
-                };
-                hir::Destination {
-                    label: self.lower_label(Some(label)),
-                    target_id,
+        let target_id = if self.is_in_anon_const {
+            Err(hir::LoopIdError::OutsideLoopScope)
+        } else {
+            match destination {
+                Some((id, _)) => {
+                    if let Def::Label(loop_id) = self.expect_full_def(id) {
+                        Ok(self.lower_node_id(loop_id).node_id)
+                    } else {
+                        Err(hir::LoopIdError::UnresolvedLabel)
+                    }
                 }
-            }
-            None => {
-                let target_id = self.loop_scopes
-                    .last()
-                    .map(|innermost_loop_id| *innermost_loop_id)
-                    .map(|id| Ok(self.lower_node_id(id).node_id))
-                    .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope))
-                    .into();
-
-                hir::Destination {
-                    label: None,
-                    target_id,
+                None => {
+                    self.loop_scopes
+                        .last()
+                        .map(|innermost_loop_id| *innermost_loop_id)
+                        .map(|id| Ok(self.lower_node_id(id).node_id))
+                        .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope))
+                        .into()
                 }
             }
+        };
+        hir::Destination {
+            label: self.lower_label(destination.map(|(_, label)| label)),
+            target_id,
         }
     }
 
@@ -3447,13 +3448,22 @@ impl<'a> LoweringContext<'a> {
     }
 
     fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst {
-        let LoweredNodeId { node_id, hir_id } = self.lower_node_id(c.id);
+        let was_in_loop_condition = self.is_in_loop_condition;
+        self.is_in_loop_condition = false;
+        let was_in_anon_const = self.is_in_anon_const;
+        self.is_in_anon_const = true;
 
-        hir::AnonConst {
+        let LoweredNodeId { node_id, hir_id } = self.lower_node_id(c.id);
+        let anon_const = hir::AnonConst {
             id: node_id,
             hir_id,
             body: self.lower_body(None, |this| this.lower_expr(&c.value)),
-        }
+        };
+
+        self.is_in_anon_const = was_in_anon_const;
+        self.is_in_loop_condition = was_in_loop_condition;
+
+        anon_const
     }
 
     fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 6ccf09f4dfc..a83aa47fd4f 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -840,6 +840,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
     fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat, match_mode: MatchMode) {
         debug!("walk_pat(cmt_discr={:?}, pat={:?})", cmt_discr, pat);
 
+        let tcx = self.tcx();
         let ExprUseVisitor { ref mc, ref mut delegate, param_env } = *self;
         return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |cmt_pat, pat| {
             if let PatKind::Binding(_, canonical_id, ..) = pat.node {
@@ -849,34 +850,36 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                     pat,
                     match_mode,
                 );
-                let bm = *mc.tables.pat_binding_modes().get(pat.hir_id)
-                                                     .expect("missing binding mode");
-                debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
-
-                // pat_ty: the type of the binding being produced.
-                let pat_ty = return_if_err!(mc.node_ty(pat.hir_id));
-                debug!("walk_pat: pat_ty={:?}", pat_ty);
-
-                // Each match binding is effectively an assignment to the
-                // binding being produced.
-                let def = Def::Local(canonical_id);
-                if let Ok(ref binding_cmt) = mc.cat_def(pat.hir_id, pat.span, pat_ty, def) {
-                    delegate.mutate(pat.id, pat.span, binding_cmt, MutateMode::Init);
-                }
+                if let Some(&bm) = mc.tables.pat_binding_modes().get(pat.hir_id) {
+                    debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
+
+                    // pat_ty: the type of the binding being produced.
+                    let pat_ty = return_if_err!(mc.node_ty(pat.hir_id));
+                    debug!("walk_pat: pat_ty={:?}", pat_ty);
+
+                    // Each match binding is effectively an assignment to the
+                    // binding being produced.
+                    let def = Def::Local(canonical_id);
+                    if let Ok(ref binding_cmt) = mc.cat_def(pat.hir_id, pat.span, pat_ty, def) {
+                        delegate.mutate(pat.id, pat.span, binding_cmt, MutateMode::Init);
+                    }
 
-                // It is also a borrow or copy/move of the value being matched.
-                match bm {
-                    ty::BindByReference(m) => {
-                        if let ty::TyRef(r, _, _) = pat_ty.sty {
-                            let bk = ty::BorrowKind::from_mutbl(m);
-                            delegate.borrow(pat.id, pat.span, &cmt_pat, r, bk, RefBinding);
+                    // It is also a borrow or copy/move of the value being matched.
+                    match bm {
+                        ty::BindByReference(m) => {
+                            if let ty::TyRef(r, _, _) = pat_ty.sty {
+                                let bk = ty::BorrowKind::from_mutbl(m);
+                                delegate.borrow(pat.id, pat.span, &cmt_pat, r, bk, RefBinding);
+                            }
+                        }
+                        ty::BindByValue(..) => {
+                            let mode = copy_or_move(mc, param_env, &cmt_pat, PatBindingMove);
+                            debug!("walk_pat binding consuming pat");
+                            delegate.consume_pat(pat, &cmt_pat, mode);
                         }
                     }
-                    ty::BindByValue(..) => {
-                        let mode = copy_or_move(mc, param_env, &cmt_pat, PatBindingMove);
-                        debug!("walk_pat binding consuming pat");
-                        delegate.consume_pat(pat, &cmt_pat, mode);
-                    }
+                } else {
+                    tcx.sess.delay_span_bug(pat.span, "missing binding mode");
                 }
             }
         }));
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index f5c2a0c3f9f..a32fdbb285d 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -1115,12 +1115,12 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
                 }
                 tcx.layout_raw(param_env.and(normalized))?
             }
-            ty::TyParam(_) => {
-                return Err(LayoutError::Unknown(ty));
-            }
-            ty::TyGeneratorWitness(..) | ty::TyInfer(_) | ty::TyError => {
+            ty::TyGeneratorWitness(..) | ty::TyInfer(_) => {
                 bug!("LayoutDetails::compute: unexpected type `{}`", ty)
             }
+            ty::TyParam(_) | ty::TyError => {
+                return Err(LayoutError::Unknown(ty));
+            }
         })
     }
 
diff --git a/src/librustc_borrowck/borrowck/unused.rs b/src/librustc_borrowck/borrowck/unused.rs
index 294ae1e63a9..475ff0b7443 100644
--- a/src/librustc_borrowck/borrowck/unused.rs
+++ b/src/librustc_borrowck/borrowck/unused.rs
@@ -54,16 +54,16 @@ impl<'a, 'tcx> UnusedMutCx<'a, 'tcx> {
 
                 // Skip anything that looks like `&foo` or `&mut foo`, only look
                 // for by-value bindings
-                let bm = match self.bccx.tables.pat_binding_modes().get(hir_id) {
-                    Some(&bm) => bm,
-                    None => span_bug!(span, "missing binding mode"),
-                };
-                match bm {
-                    ty::BindByValue(hir::MutMutable) => {}
-                    _ => return,
+                if let Some(&bm) = self.bccx.tables.pat_binding_modes().get(hir_id) {
+                    match bm {
+                        ty::BindByValue(hir::MutMutable) => {}
+                        _ => return,
+                    }
+
+                    mutables.entry(ident.name).or_insert(Vec::new()).push((hir_id, span));
+                } else {
+                    tcx.sess.delay_span_bug(span, "missing binding mode");
                 }
-
-                mutables.entry(ident.name).or_insert(Vec::new()).push((hir_id, span));
             });
         }
 
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index c0821cdd3ba..8fb5b5c0fa4 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -541,13 +541,14 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
                 if let hir::PatKind::Binding(_, _, ident, _) = pat.node {
                     decl.debug_name = ident.name;
 
-                    let bm = *hir.tables.pat_binding_modes()
-                                        .get(pat.hir_id)
-                                        .expect("missing binding mode");
-                    if bm == ty::BindByValue(hir::MutMutable) {
-                        decl.mutability = Mutability::Mut;
+                    if let Some(&bm) = hir.tables.pat_binding_modes().get(pat.hir_id) {
+                        if bm == ty::BindByValue(hir::MutMutable) {
+                            decl.mutability = Mutability::Mut;
+                        } else {
+                            decl.mutability = Mutability::Not;
+                        }
                     } else {
-                        decl.mutability = Mutability::Not;
+                        tcx.sess.delay_span_bug(pat.span, "missing binding mode");
                     }
                 }
             }
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index b9d6486d917..502091e5192 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -541,9 +541,9 @@ 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(&self,
-                           span: Span,
-                           label: region::Scope)
-                           -> &BreakableScope<'tcx> {
+                                span: Span,
+                                label: region::Scope)
+                                -> &BreakableScope<'tcx> {
         // find the loop-scope with the correct id
         self.breakable_scopes.iter()
             .rev()
diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs
index e04cdcfa027..18ae7c77459 100644
--- a/src/librustc_mir/hair/pattern/check_match.rs
+++ b/src/librustc_mir/hair/pattern/check_match.rs
@@ -309,33 +309,32 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
 fn check_for_bindings_named_the_same_as_variants(cx: &MatchVisitor, pat: &Pat) {
     pat.walk(|p| {
         if let PatKind::Binding(_, _, ident, None) = p.node {
-            let bm = *cx.tables
-                        .pat_binding_modes()
-                        .get(p.hir_id)
-                        .expect("missing binding mode");
-
-            if bm != ty::BindByValue(hir::MutImmutable) {
-                // Nothing to check.
-                return true;
-            }
-            let pat_ty = cx.tables.pat_ty(p);
-            if let ty::TyAdt(edef, _) = pat_ty.sty {
-                if edef.is_enum() && edef.variants.iter().any(|variant| {
-                    variant.name == ident.name && variant.ctor_kind == CtorKind::Const
-                }) {
-                    let ty_path = cx.tcx.item_path_str(edef.did);
-                    let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170,
-                        "pattern binding `{}` is named the same as one \
-                         of the variants of the type `{}`",
-                        ident, ty_path);
-                    err.span_suggestion_with_applicability(
-                        p.span,
-                        "to match on the variant, qualify the path",
-                        format!("{}::{}", ty_path, ident),
-                        Applicability::MachineApplicable
-                    );
-                    err.emit();
+            if let Some(&bm) = cx.tables.pat_binding_modes().get(p.hir_id) {
+                if bm != ty::BindByValue(hir::MutImmutable) {
+                    // Nothing to check.
+                    return true;
                 }
+                let pat_ty = cx.tables.pat_ty(p);
+                if let ty::TyAdt(edef, _) = pat_ty.sty {
+                    if edef.is_enum() && edef.variants.iter().any(|variant| {
+                        variant.name == ident.name && variant.ctor_kind == CtorKind::Const
+                    }) {
+                        let ty_path = cx.tcx.item_path_str(edef.did);
+                        let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170,
+                            "pattern binding `{}` is named the same as one \
+                            of the variants of the type `{}`",
+                            ident, ty_path);
+                        err.span_suggestion_with_applicability(
+                            p.span,
+                            "to match on the variant, qualify the path",
+                            format!("{}::{}", ty_path, ident),
+                            Applicability::MachineApplicable
+                        );
+                        err.emit();
+                    }
+                }
+            } else {
+                cx.tcx.sess.delay_span_bug(p.span, "missing binding mode");
             }
         }
         true
@@ -517,12 +516,12 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
     let mut by_ref_span = None;
     for pat in pats {
         pat.each_binding(|_, hir_id, span, _path| {
-            let bm = *cx.tables
-                        .pat_binding_modes()
-                        .get(hir_id)
-                        .expect("missing binding mode");
-            if let ty::BindByReference(..) = bm {
-                by_ref_span = Some(span);
+            if let Some(&bm) = cx.tables.pat_binding_modes().get(hir_id) {
+                if let ty::BindByReference(..) = bm {
+                    by_ref_span = Some(span);
+                }
+            } else {
+                cx.tcx.sess.delay_span_bug(pat.span, "missing binding mode");
             }
         })
     }
@@ -553,18 +552,18 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
     for pat in pats {
         pat.walk(|p| {
             if let PatKind::Binding(_, _, _, ref sub) = p.node {
-                let bm = *cx.tables
-                            .pat_binding_modes()
-                            .get(p.hir_id)
-                            .expect("missing binding mode");
-                match bm {
-                    ty::BindByValue(..) => {
-                        let pat_ty = cx.tables.node_id_to_type(p.hir_id);
-                        if pat_ty.moves_by_default(cx.tcx, cx.param_env, pat.span) {
-                            check_move(p, sub.as_ref().map(|p| &**p));
+                if let Some(&bm) = cx.tables.pat_binding_modes().get(p.hir_id) {
+                    match bm {
+                        ty::BindByValue(..) => {
+                            let pat_ty = cx.tables.node_id_to_type(p.hir_id);
+                            if pat_ty.moves_by_default(cx.tcx, cx.param_env, pat.span) {
+                                check_move(p, sub.as_ref().map(|p| &**p));
+                            }
                         }
+                        _ => {}
                     }
-                    _ => {}
+                } else {
+                    cx.tcx.sess.delay_span_bug(pat.span, "missing binding mode");
                 }
             }
             true
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 4d0e3e826e8..636969e2632 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -743,8 +743,10 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                         );
                         *self.const_to_pat(instance, val, expr.hir_id, lit.span).kind
                     },
-                    Err(()) => {
-                        self.errors.push(PatternError::FloatBug);
+                    Err(e) => {
+                        if e == LitToConstError::UnparseableFloat {
+                            self.errors.push(PatternError::FloatBug);
+                        }
                         PatternKind::Wild
                     },
                 }
@@ -764,8 +766,10 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                         );
                         *self.const_to_pat(instance, val, expr.hir_id, lit.span).kind
                     },
-                    Err(()) => {
-                        self.errors.push(PatternError::FloatBug);
+                    Err(e) => {
+                        if e == LitToConstError::UnparseableFloat {
+                            self.errors.push(PatternError::FloatBug);
+                        }
                         PatternKind::Wild
                     },
                 }
@@ -1118,12 +1122,18 @@ pub fn compare_const_vals<'a, 'tcx>(
     fallback()
 }
 
+#[derive(PartialEq)]
+enum LitToConstError {
+    UnparseableFloat,
+    Propagated,
+}
+
 // FIXME: Combine with rustc_mir::hair::cx::const_eval_literal
 fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           ty: Ty<'tcx>,
                           neg: bool)
-                          -> Result<&'tcx ty::Const<'tcx>, ()> {
+                          -> Result<&'tcx ty::Const<'tcx>, LitToConstError> {
     use syntax::ast::*;
 
     use rustc::mir::interpret::*;
@@ -1152,7 +1162,10 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
                 ty::TyInt(other) => Int::Signed(other),
                 ty::TyUint(UintTy::Usize) => Int::Unsigned(tcx.sess.target.usize_ty),
                 ty::TyUint(other) => Int::Unsigned(other),
-                _ => bug!(),
+                ty::TyError => { // Avoid ICE (#51963)
+                    return Err(LitToConstError::Propagated);
+                }
+                _ => bug!("literal integer type with bad type ({:?})", ty.sty),
             };
             // This converts from LitKind::Int (which is sign extended) to
             // Scalar::Bytes (which is zero extended)
@@ -1182,14 +1195,14 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
             })
         },
         LitKind::Float(n, fty) => {
-            parse_float(n, fty, neg)?
+            parse_float(n, fty, neg).map_err(|_| LitToConstError::UnparseableFloat)?
         }
         LitKind::FloatUnsuffixed(n) => {
             let fty = match ty.sty {
                 ty::TyFloat(fty) => fty,
                 _ => bug!()
             };
-            parse_float(n, fty, neg)?
+            parse_float(n, fty, neg).map_err(|_| LitToConstError::UnparseableFloat)?
         }
         LitKind::Bool(b) => ConstValue::Scalar(Scalar::Bits {
             bits: b as u128,
diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs
index c99f1e9da43..eff0dbe1235 100644
--- a/src/librustc_passes/loops.rs
+++ b/src/librustc_passes/loops.rs
@@ -17,7 +17,7 @@ use rustc::hir::{self, Destination};
 use syntax::ast;
 use syntax_pos::Span;
 
-#[derive(Clone, Copy, PartialEq)]
+#[derive(Clone, Copy, Debug, PartialEq)]
 enum LoopKind {
     Loop(hir::LoopSource),
     WhileLoop,
@@ -34,12 +34,13 @@ impl LoopKind {
     }
 }
 
-#[derive(Clone, Copy, PartialEq)]
+#[derive(Clone, Copy, Debug, PartialEq)]
 enum Context {
     Normal,
     Loop(LoopKind),
     Closure,
     LabeledBlock,
+    AnonConst,
 }
 
 #[derive(Copy, Clone)]
@@ -71,6 +72,10 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
         self.with_context(Normal, |v| intravisit::walk_impl_item(v, i));
     }
 
+    fn visit_anon_const(&mut self, c: &'hir hir::AnonConst) {
+        self.with_context(AnonConst, |v| intravisit::walk_anon_const(v, c));
+    }
+
     fn visit_expr(&mut self, e: &'hir hir::Expr) {
         match e.node {
             hir::ExprWhile(ref e, ref b, _) => {
@@ -194,7 +199,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
                 .span_label(span, "cannot break inside of a closure")
                 .emit();
             }
-            Normal => {
+            Normal | AnonConst => {
                 struct_span_err!(self.sess, span, E0268, "`{}` outside of loop", name)
                 .span_label(span, "cannot break outside of a loop")
                 .emit();
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index fa78b38dbb7..646c4f17568 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3827,7 +3827,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     // this can only happen if the `break` was not
                     // inside a loop at all, which is caught by the
                     // loop-checking pass.
-                    assert!(self.tcx.sess.err_count() > 0);
+                    if self.tcx.sess.err_count() == 0 {
+                        self.tcx.sess.delay_span_bug(expr.span,
+                            "break was outside loop, but no error was emitted");
+                    }
 
                     // We still need to assign a type to the inner expression to
                     // prevent the ICE in #43162.
@@ -3960,7 +3963,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // is nil. This makes sense because infinite loops
                 // (which would have type !) are only possible iff we
                 // permit break with a value [1].
-                assert!(ctxt.coerce.is_some() || ctxt.may_break); // [1]
+                if ctxt.coerce.is_none() && !ctxt.may_break {
+                    // [1]
+                    self.tcx.sess.delay_span_bug(body.span, "no coercion, but loop may not break");
+                }
                 ctxt.coerce.map(|c| c.complete(self)).unwrap_or(self.tcx.mk_nil())
             }
             hir::ExprMatch(ref discrim, ref arms, match_src) => {
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index e489c4d4a46..68fcde0b165 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -1039,11 +1039,13 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
                 match sub_pat.node {
                     // `ref x` pattern
                     PatKind::Binding(..) => {
-                        let bm = *mc.tables.pat_binding_modes().get(sub_pat.hir_id)
-                                                               .expect("missing binding mode");
-                        if let ty::BindByReference(mutbl) = bm {
-                            self.link_region_from_node_type(sub_pat.span, sub_pat.hir_id,
-                                                            mutbl, &sub_cmt);
+                        if let Some(&bm) = mc.tables.pat_binding_modes().get(sub_pat.hir_id) {
+                            if let ty::BindByReference(mutbl) = bm {
+                                self.link_region_from_node_type(sub_pat.span, sub_pat.hir_id,
+                                                                mutbl, &sub_cmt);
+                            }
+                        } else {
+                            self.tcx.sess.delay_span_bug(sub_pat.span, "missing binding mode");
                         }
                     }
                     _ => {}
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index f7d1e407945..2445cae9860 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -257,13 +257,11 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
     fn visit_pat(&mut self, p: &'gcx hir::Pat) {
         match p.node {
             hir::PatKind::Binding(..) => {
-                let bm = *self.fcx
-                    .tables
-                    .borrow()
-                    .pat_binding_modes()
-                    .get(p.hir_id)
-                    .expect("missing binding mode");
-                self.tables.pat_binding_modes_mut().insert(p.hir_id, bm);
+                if let Some(&bm) = self.fcx.tables.borrow().pat_binding_modes().get(p.hir_id) {
+                    self.tables.pat_binding_modes_mut().insert(p.hir_id, bm);
+                } else {
+                    self.tcx().sess.delay_span_bug(p.span, "missing binding mode");
+                }
             }
             hir::PatKind::Struct(_, ref fields, _) => {
                 for field in fields {
diff --git a/src/test/ui/array-break-length.rs b/src/test/ui/array-break-length.rs
new file mode 100644
index 00000000000..c3cfff0e1f6
--- /dev/null
+++ b/src/test/ui/array-break-length.rs
@@ -0,0 +1,19 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    loop {
+        |_: [_; break]| {} //~ ERROR: `break` outside of loop
+    }
+
+    loop {
+        |_: [_; continue]| {} //~ ERROR: `continue` outside of loop
+    }
+}
diff --git a/src/test/ui/array-break-length.stderr b/src/test/ui/array-break-length.stderr
new file mode 100644
index 00000000000..114245b9cc7
--- /dev/null
+++ b/src/test/ui/array-break-length.stderr
@@ -0,0 +1,15 @@
+error[E0268]: `break` outside of loop
+  --> $DIR/array-break-length.rs:13:17
+   |
+LL |         |_: [_; break]| {} //~ ERROR: `break` outside of loop
+   |                 ^^^^^ cannot break outside of a loop
+
+error[E0268]: `continue` outside of loop
+  --> $DIR/array-break-length.rs:17:17
+   |
+LL |         |_: [_; continue]| {} //~ ERROR: `continue` outside of loop
+   |                 ^^^^^^^^ cannot break outside of a loop
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0268`.
diff --git a/src/test/ui/closure-array-break-length.rs b/src/test/ui/closure-array-break-length.rs
index 2e99921956a..8be5b925a39 100644
--- a/src/test/ui/closure-array-break-length.rs
+++ b/src/test/ui/closure-array-break-length.rs
@@ -11,7 +11,7 @@
 fn main() {
     |_: [_; continue]| {}; //~ ERROR: `continue` outside of loop
 
-    while |_: [_; continue]| {} {} //~ ERROR: `break` or `continue` with no label
+    while |_: [_; continue]| {} {} //~ ERROR: `continue` outside of loop
 
-    while |_: [_; break]| {} {} //~ ERROR: `break` or `continue` with no label
+    while |_: [_; break]| {} {} //~ ERROR: `break` outside of loop
 }
diff --git a/src/test/ui/closure-array-break-length.stderr b/src/test/ui/closure-array-break-length.stderr
index 139153992e2..f62b1354370 100644
--- a/src/test/ui/closure-array-break-length.stderr
+++ b/src/test/ui/closure-array-break-length.stderr
@@ -4,19 +4,18 @@ error[E0268]: `continue` outside of loop
 LL |     |_: [_; continue]| {}; //~ ERROR: `continue` outside of loop
    |             ^^^^^^^^ cannot break outside of a loop
 
-error[E0590]: `break` or `continue` with no label in the condition of a `while` loop
+error[E0268]: `continue` outside of 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
+LL |     while |_: [_; continue]| {} {} //~ ERROR: `continue` outside of loop
+   |                   ^^^^^^^^ cannot break outside of a loop
 
-error[E0590]: `break` or `continue` with no label in the condition of a `while` loop
+error[E0268]: `break` outside of 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
+LL |     while |_: [_; break]| {} {} //~ ERROR: `break` outside of loop
+   |                   ^^^^^ cannot break outside of a loop
 
 error: aborting due to 3 previous errors
 
-Some errors occurred: E0268, E0590.
-For more information about an error, try `rustc --explain E0268`.
+For more information about this error, try `rustc --explain E0268`.
diff --git a/src/test/ui/issue-51714.rs b/src/test/ui/issue-51714.rs
index 96c5b92ddfd..2b9d51f81b9 100644
--- a/src/test/ui/issue-51714.rs
+++ b/src/test/ui/issue-51714.rs
@@ -9,11 +9,16 @@
 // except according to those terms.
 
 fn main() {
-    |_:  [_; return || {}] | {}
+    |_:  [_; return || {}] | {};
     //~^ ERROR return statement outside of function body
-}
 
-fn foo() {
     [(); return || {}];
     //~^ ERROR return statement outside of function body
+
+    [(); return |ice| {}];
+    //~^ ERROR return statement outside of function body
+
+    [(); return while let Some(n) = Some(0) {}];
+    //~^ ERROR return statement outside of function body
+    //~^^ ERROR irrefutable while-let pattern
 }
diff --git a/src/test/ui/issue-51714.stderr b/src/test/ui/issue-51714.stderr
index 746adea6b7e..ddc70bfb38e 100644
--- a/src/test/ui/issue-51714.stderr
+++ b/src/test/ui/issue-51714.stderr
@@ -1,15 +1,34 @@
 error[E0572]: return statement outside of function body
   --> $DIR/issue-51714.rs:12:14
    |
-LL |     |_:  [_; return || {}] | {}
+LL |     |_:  [_; return || {}] | {};
    |              ^^^^^^^^^^^^
 
 error[E0572]: return statement outside of function body
-  --> $DIR/issue-51714.rs:17:10
+  --> $DIR/issue-51714.rs:15:10
    |
 LL |     [(); return || {}];
    |          ^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error[E0572]: return statement outside of function body
+  --> $DIR/issue-51714.rs:18:10
+   |
+LL |     [(); return |ice| {}];
+   |          ^^^^^^^^^^^^^^^
+
+error[E0572]: return statement outside of function body
+  --> $DIR/issue-51714.rs:21:10
+   |
+LL |     [(); return while let Some(n) = Some(0) {}];
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0165]: irrefutable while-let pattern
+  --> $DIR/issue-51714.rs:21:27
+   |
+LL |     [(); return while let Some(n) = Some(0) {}];
+   |                           ^^^^^^^ irrefutable pattern
+
+error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0572`.
+Some errors occurred: E0165, E0572.
+For more information about an error, try `rustc --explain E0165`.
diff --git a/src/test/ui/return-match-array-const.rs b/src/test/ui/return-match-array-const.rs
new file mode 100644
index 00000000000..45fc571d79d
--- /dev/null
+++ b/src/test/ui/return-match-array-const.rs
@@ -0,0 +1,17 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    [(); return match 0 { n => n }]; //~ ERROR: return statement outside of function body
+
+    [(); return match 0 { 0 => 0 }]; //~ ERROR: return statement outside of function body
+
+    [(); return match () { 'a' => 0, _ => 0 }]; //~ ERROR: return statement outside of function body
+}
diff --git a/src/test/ui/return-match-array-const.stderr b/src/test/ui/return-match-array-const.stderr
new file mode 100644
index 00000000000..044dc8f5145
--- /dev/null
+++ b/src/test/ui/return-match-array-const.stderr
@@ -0,0 +1,21 @@
+error[E0572]: return statement outside of function body
+  --> $DIR/return-match-array-const.rs:12:10
+   |
+LL |     [(); return match 0 { n => n }]; //~ ERROR: return statement outside of function body
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0572]: return statement outside of function body
+  --> $DIR/return-match-array-const.rs:14:10
+   |
+LL |     [(); return match 0 { 0 => 0 }]; //~ ERROR: return statement outside of function body
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0572]: return statement outside of function body
+  --> $DIR/return-match-array-const.rs:16:10
+   |
+LL |     [(); return match () { 'a' => 0, _ => 0 }]; //~ ERROR: return statement outside of function body
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0572`.