From c6bbee802abb174243fac490782baa680e4f67b4 Mon Sep 17 00:00:00 2001 From: varkor Date: Sun, 1 Jul 2018 17:23:48 +0100 Subject: [PATCH 1/9] Fix a bug with return in anonymous consts --- src/librustc_typeck/check/writeback.rs | 12 +++++------- src/test/ui/issue-51714.rs | 5 +++++ src/test/ui/issue-51714.stderr | 8 +++++++- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index f7d1e40794580..2445cae98607a 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/issue-51714.rs b/src/test/ui/issue-51714.rs index 96c5b92ddfdcc..c0e62dcc9cefe 100644 --- a/src/test/ui/issue-51714.rs +++ b/src/test/ui/issue-51714.rs @@ -17,3 +17,8 @@ fn foo() { [(); return || {}]; //~^ ERROR return statement outside of function body } + +fn bar() { + [(); return |ice| {}]; + //~^ ERROR return statement outside of function body +} diff --git a/src/test/ui/issue-51714.stderr b/src/test/ui/issue-51714.stderr index 746adea6b7ed7..3e61df8062d1d 100644 --- a/src/test/ui/issue-51714.stderr +++ b/src/test/ui/issue-51714.stderr @@ -10,6 +10,12 @@ error[E0572]: return statement outside of function body LL | [(); return || {}]; | ^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error[E0572]: return statement outside of function body + --> $DIR/issue-51714.rs:22:10 + | +LL | [(); return |ice| {}]; + | ^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0572`. From 7ad1c62d38294e145aa65425a08b5accac121cd3 Mon Sep 17 00:00:00 2001 From: varkor Date: Sun, 1 Jul 2018 17:24:07 +0100 Subject: [PATCH 2/9] Fix an ICE using break and continue as array lengths --- src/librustc_driver/driver.rs | 1 + src/librustc_mir/build/scope.rs | 6 +++--- src/librustc_passes/loops.rs | 7 ++++++- src/test/ui/array-break-length.rs | 19 +++++++++++++++++++ src/test/ui/array-break-length.stderr | 15 +++++++++++++++ src/test/ui/closure-array-break-length.rs | 2 ++ src/test/ui/closure-array-break-length.stderr | 16 ++++++++++++++-- 7 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/array-break-length.rs create mode 100644 src/test/ui/array-break-length.stderr diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index feeac9d938b6a..c4e196628915b 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1211,6 +1211,7 @@ where .set(derive_registrar::find(&hir_map)); time(sess, "loop checking", || loops::check_crate(sess, &hir_map)); + sess.abort_if_errors(); let mut local_providers = ty::query::Providers::default(); default_provide(&mut local_providers); diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index b9d6486d9174a..502091e519201 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_passes/loops.rs b/src/librustc_passes/loops.rs index c99f1e9da439f..898acf48d3df8 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -40,6 +40,7 @@ enum Context { 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/test/ui/array-break-length.rs b/src/test/ui/array-break-length.rs new file mode 100644 index 0000000000000..c3cfff0e1f642 --- /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 or the MIT license +// , 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 0000000000000..114245b9cc77b --- /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 2e99921956ab2..727113e328fef 100644 --- a/src/test/ui/closure-array-break-length.rs +++ b/src/test/ui/closure-array-break-length.rs @@ -12,6 +12,8 @@ fn main() { |_: [_; continue]| {}; //~ ERROR: `continue` outside of loop while |_: [_; continue]| {} {} //~ ERROR: `break` or `continue` with no label + //~^ ERROR: `continue` outside of loop while |_: [_; break]| {} {} //~ ERROR: `break` or `continue` with no label + //~^ 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 139153992e274..a337645fb7e8f 100644 --- a/src/test/ui/closure-array-break-length.stderr +++ b/src/test/ui/closure-array-break-length.stderr @@ -10,13 +10,25 @@ 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[E0268]: `continue` outside of loop + --> $DIR/closure-array-break-length.rs:14:19 + | +LL | while |_: [_; continue]| {} {} //~ ERROR: `break` or `continue` with no label + | ^^^^^^^^ cannot break outside of a loop + error[E0590]: `break` or `continue` with no label in the condition of a `while` loop - --> $DIR/closure-array-break-length.rs:16:19 + --> $DIR/closure-array-break-length.rs:17: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 +error[E0268]: `break` outside of loop + --> $DIR/closure-array-break-length.rs:17:19 + | +LL | while |_: [_; break]| {} {} //~ ERROR: `break` or `continue` with no label + | ^^^^^ cannot break outside of a loop + +error: aborting due to 5 previous errors Some errors occurred: E0268, E0590. For more information about an error, try `rustc --explain E0268`. From 998141f8ef8225704f8641ef0372c686bcbd2c5f Mon Sep 17 00:00:00 2001 From: varkor Date: Sun, 1 Jul 2018 17:40:36 +0100 Subject: [PATCH 3/9] Fix another return-const ICE --- src/librustc_mir/hair/pattern/check_match.rs | 51 ++++++++++---------- src/test/ui/issue-51714.rs | 9 ++-- src/test/ui/issue-51714.stderr | 14 ++++-- 3 files changed, 39 insertions(+), 35 deletions(-) diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index e04cdcfa02773..a7806131f2c89 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 diff --git a/src/test/ui/issue-51714.rs b/src/test/ui/issue-51714.rs index c0e62dcc9cefe..f8d12b991eaef 100644 --- a/src/test/ui/issue-51714.rs +++ b/src/test/ui/issue-51714.rs @@ -9,16 +9,15 @@ // 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 -} -fn bar() { [(); return |ice| {}]; //~^ ERROR return statement outside of function body + + [(); return while let Some(n) = Some(0) {}]; + //~^ ERROR return statement outside of function body } diff --git a/src/test/ui/issue-51714.stderr b/src/test/ui/issue-51714.stderr index 3e61df8062d1d..c8764564dca38 100644 --- a/src/test/ui/issue-51714.stderr +++ b/src/test/ui/issue-51714.stderr @@ -1,21 +1,27 @@ 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[E0572]: return statement outside of function body - --> $DIR/issue-51714.rs:22:10 + --> $DIR/issue-51714.rs:18:10 | LL | [(); return |ice| {}]; | ^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error[E0572]: return statement outside of function body + --> $DIR/issue-51714.rs:21:10 + | +LL | [(); return while let Some(n) = Some(0) {}]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0572`. From b00050f4cf7d602566afd511b66ae6645f92987d Mon Sep 17 00:00:00 2001 From: varkor Date: Sun, 1 Jul 2018 17:56:06 +0100 Subject: [PATCH 4/9] Add more safeguards to "missing binding mode" errors --- src/librustc/middle/expr_use_visitor.rs | 53 +++++++++++--------- src/librustc_borrowck/borrowck/unused.rs | 18 +++---- src/librustc_mir/build/mod.rs | 13 ++--- src/librustc_mir/hair/pattern/check_match.rs | 32 ++++++------ src/librustc_typeck/check/regionck.rs | 12 +++-- 5 files changed, 67 insertions(+), 61 deletions(-) diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 6ccf09f4dfc4f..a83aa47fd4f13 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_borrowck/borrowck/unused.rs b/src/librustc_borrowck/borrowck/unused.rs index 294ae1e63a9ee..475ff0b744349 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 4db5c8e9278e5..cdf0079e2ae83 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/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index a7806131f2c89..18ae7c7745915 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -516,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"); } }) } @@ -552,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_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index e489c4d4a46be..68fcde0b1657a 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"); } } _ => {} From 30fde047804b6555ad982e7d55fea9e54815ea39 Mon Sep 17 00:00:00 2001 From: varkor Date: Sun, 1 Jul 2018 18:31:07 +0100 Subject: [PATCH 5/9] Clean up error messages regarding break/continue inside consts --- src/librustc/hir/lowering.rs | 60 +++++++++++-------- src/test/ui/closure-array-break-length.rs | 6 +- src/test/ui/closure-array-break-length.stderr | 23 ++----- 3 files changed, 42 insertions(+), 47 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index e59e50ae9e698..2365bdda932fb 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -103,6 +103,7 @@ pub struct LoweringContext<'a> { loop_scopes: Vec, 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, } } @@ -3440,13 +3441,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/test/ui/closure-array-break-length.rs b/src/test/ui/closure-array-break-length.rs index 727113e328fef..8be5b925a399e 100644 --- a/src/test/ui/closure-array-break-length.rs +++ b/src/test/ui/closure-array-break-length.rs @@ -11,9 +11,7 @@ fn main() { |_: [_; continue]| {}; //~ ERROR: `continue` outside of loop - while |_: [_; continue]| {} {} //~ ERROR: `break` or `continue` with no label - //~^ ERROR: `continue` outside of loop + while |_: [_; continue]| {} {} //~ ERROR: `continue` outside of loop - while |_: [_; break]| {} {} //~ ERROR: `break` or `continue` with no label - //~^ ERROR: `break` outside of loop + 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 a337645fb7e8f..f62b135437092 100644 --- a/src/test/ui/closure-array-break-length.stderr +++ b/src/test/ui/closure-array-break-length.stderr @@ -4,31 +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 - --> $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[E0268]: `continue` outside of loop --> $DIR/closure-array-break-length.rs:14:19 | -LL | while |_: [_; continue]| {} {} //~ ERROR: `break` or `continue` with no label +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 - --> $DIR/closure-array-break-length.rs:17:19 - | -LL | while |_: [_; break]| {} {} //~ ERROR: `break` or `continue` with no label - | ^^^^^ unlabeled `break` in the condition of a `while` loop - error[E0268]: `break` outside of loop - --> $DIR/closure-array-break-length.rs:17:19 + --> $DIR/closure-array-break-length.rs:16:19 | -LL | while |_: [_; break]| {} {} //~ ERROR: `break` or `continue` with no label +LL | while |_: [_; break]| {} {} //~ ERROR: `break` outside of loop | ^^^^^ cannot break outside of a loop -error: aborting due to 5 previous errors +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`. From 0195714836d1b2fb754452ad5fc400c7bfa3c9bc Mon Sep 17 00:00:00 2001 From: varkor Date: Sun, 1 Jul 2018 20:57:23 +0100 Subject: [PATCH 6/9] Fix ICEs with match/return expressions inside array lengths --- src/librustc/ty/layout.rs | 5 ++++- src/librustc_mir/hair/pattern/mod.rs | 24 ++++++++++++++------- src/test/ui/return-match-array-const.rs | 17 +++++++++++++++ src/test/ui/return-match-array-const.stderr | 21 ++++++++++++++++++ 4 files changed, 58 insertions(+), 9 deletions(-) create mode 100644 src/test/ui/return-match-array-const.rs create mode 100644 src/test/ui/return-match-array-const.stderr diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index f5c2a0c3f9f05..0763c8af5d037 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1118,9 +1118,12 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { ty::TyParam(_) => { return Err(LayoutError::Unknown(ty)); } - ty::TyGeneratorWitness(..) | ty::TyInfer(_) | ty::TyError => { + ty::TyGeneratorWitness(..) | ty::TyInfer(_) => { bug!("LayoutDetails::compute: unexpected type `{}`", ty) } + ty::TyError => { + return Err(LayoutError::Unknown(ty)); + } }) } diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 4d0e3e826e878..2291387792b0e 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(float_bug) => { + if float_bug { + 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(float_bug) => { + if float_bug { + self.errors.push(PatternError::FloatBug); + } PatternKind::Wild }, } @@ -1123,7 +1127,7 @@ 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>, bool> { use syntax::ast::*; use rustc::mir::interpret::*; @@ -1152,7 +1156,11 @@ 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 + return Err(false); + } + _ => bug!("{:?}", ty.sty), }; // This converts from LitKind::Int (which is sign extended) to // Scalar::Bytes (which is zero extended) @@ -1182,14 +1190,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(|_| true)? } 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(|_| true)? } LitKind::Bool(b) => ConstValue::Scalar(Scalar::Bits { bits: b as u128, 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 0000000000000..45fc571d79d56 --- /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 or the MIT license +// , 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 0000000000000..044dc8f51455f --- /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`. From 90eee7dff21e6fa7be553cc3863aaeb8a73db442 Mon Sep 17 00:00:00 2001 From: varkor Date: Sun, 1 Jul 2018 21:07:21 +0100 Subject: [PATCH 7/9] Remove early error abort --- src/librustc_driver/driver.rs | 1 - src/test/ui/issue-51714.rs | 1 + src/test/ui/issue-51714.stderr | 11 +++++++++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index c4e196628915b..feeac9d938b6a 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1211,7 +1211,6 @@ where .set(derive_registrar::find(&hir_map)); time(sess, "loop checking", || loops::check_crate(sess, &hir_map)); - sess.abort_if_errors(); let mut local_providers = ty::query::Providers::default(); default_provide(&mut local_providers); diff --git a/src/test/ui/issue-51714.rs b/src/test/ui/issue-51714.rs index f8d12b991eaef..2b9d51f81b988 100644 --- a/src/test/ui/issue-51714.rs +++ b/src/test/ui/issue-51714.rs @@ -20,4 +20,5 @@ fn main() { [(); 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 c8764564dca38..ddc70bfb38e01 100644 --- a/src/test/ui/issue-51714.stderr +++ b/src/test/ui/issue-51714.stderr @@ -22,6 +22,13 @@ error[E0572]: return statement outside of function body LL | [(); return while let Some(n) = Some(0) {}]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +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`. From 4d66b65850cba7302c79c031f9fa61e7162aca43 Mon Sep 17 00:00:00 2001 From: varkor Date: Sun, 1 Jul 2018 23:40:03 +0100 Subject: [PATCH 8/9] Fix issue-50585 test --- src/librustc_passes/loops.rs | 4 ++-- src/librustc_typeck/check/mod.rs | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index 898acf48d3df8..eff0dbe1235ff 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,7 +34,7 @@ impl LoopKind { } } -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] enum Context { Normal, Loop(LoopKind), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index fa78b38dbb7a8..646c4f17568f0 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) => { From adf4ef7b98212e1295e7cbc68a7133e67f9af846 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 2 Jul 2018 02:12:19 +0100 Subject: [PATCH 9/9] Use LitToConstError rather than bool for errors --- src/librustc/ty/layout.rs | 5 +---- src/librustc_mir/hair/pattern/mod.rs | 27 ++++++++++++++++----------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 0763c8af5d037..a32fdbb285d12 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1115,13 +1115,10 @@ 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(_) => { bug!("LayoutDetails::compute: unexpected type `{}`", ty) } - ty::TyError => { + ty::TyParam(_) | ty::TyError => { return Err(LayoutError::Unknown(ty)); } }) diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 2291387792b0e..636969e263222 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -743,8 +743,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ); *self.const_to_pat(instance, val, expr.hir_id, lit.span).kind }, - Err(float_bug) => { - if float_bug { + Err(e) => { + if e == LitToConstError::UnparseableFloat { self.errors.push(PatternError::FloatBug); } PatternKind::Wild @@ -766,8 +766,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ); *self.const_to_pat(instance, val, expr.hir_id, lit.span).kind }, - Err(float_bug) => { - if float_bug { + Err(e) => { + if e == LitToConstError::UnparseableFloat { self.errors.push(PatternError::FloatBug); } PatternKind::Wild @@ -1122,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>, bool> { + -> Result<&'tcx ty::Const<'tcx>, LitToConstError> { use syntax::ast::*; use rustc::mir::interpret::*; @@ -1156,11 +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), - ty::TyError => { - // Avoid ICE - return Err(false); + ty::TyError => { // Avoid ICE (#51963) + return Err(LitToConstError::Propagated); } - _ => bug!("{:?}", ty.sty), + _ => 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) @@ -1190,14 +1195,14 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, }) }, LitKind::Float(n, fty) => { - parse_float(n, fty, neg).map_err(|_| true)? + 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).map_err(|_| true)? + parse_float(n, fty, neg).map_err(|_| LitToConstError::UnparseableFloat)? } LitKind::Bool(b) => ConstValue::Scalar(Scalar::Bits { bits: b as u128,