From aaf3e318fc33edcc6dbf0920998c3f27d00dd818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 13 Dec 2017 23:05:49 -0800 Subject: [PATCH 1/2] Do not emit type errors on recovered blocks When a parse error occurs on a block, the parser will recover and create a block with the statements collected until that point. Now a flag stating that a recovery has been performed in this block is propagated so that the type checker knows that the type of the block (which will be identified as `()`) shouldn't be checked against the expectation to reduce the amount of irrelevant diagnostic errors shown to the user. --- src/librustc/diagnostics.rs | 21 +++++++------ src/librustc/hir/lowering.rs | 4 +++ src/librustc/hir/mod.rs | 5 +++ src/librustc/ich/impls_hir.rs | 2 ++ src/librustc_driver/pretty.rs | 6 ++-- src/librustc_typeck/check/mod.rs | 7 ++++- src/libsyntax/ast.rs | 1 + src/libsyntax/ext/build.rs | 1 + src/libsyntax/fold.rs | 3 +- src/libsyntax/parse/mod.rs | 1 + src/libsyntax/parse/parser.rs | 7 +++-- src/libsyntax_ext/deriving/mod.rs | 1 + src/test/compile-fail/issue-34334.rs | 1 - src/test/parse-fail/issue-22647.rs | 1 - .../keywords-followed-by-double-colon.rs | 8 +++-- src/test/parse-fail/mut-patterns.rs | 1 - .../pprust-expr-roundtrip.rs | 1 + src/test/ui/impossible_range.rs | 12 ++++--- src/test/ui/impossible_range.stderr | 8 ++--- src/test/ui/issue-44406.stderr | 2 -- src/test/ui/macro-context.stderr | 2 -- .../ui/mismatched_types/recovered-block.rs | 31 +++++++++++++++++++ .../mismatched_types/recovered-block.stderr | 18 +++++++++++ src/test/ui/resolve/token-error-correct.rs | 1 - .../ui/resolve/token-error-correct.stderr | 8 +---- 25 files changed, 112 insertions(+), 41 deletions(-) create mode 100644 src/test/ui/mismatched_types/recovered-block.rs create mode 100644 src/test/ui/mismatched_types/recovered-block.stderr diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 85ae529ae32..7b48e7801df 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -359,18 +359,21 @@ lifetime elision rules (see below). Here are some simple examples of where you'll run into this error: ```compile_fail,E0106 -struct Foo { x: &bool } // error -struct Foo<'a> { x: &'a bool } // correct +struct Foo1 { x: &bool } + // ^ expected lifetime parameter +struct Foo2<'a> { x: &'a bool } // correct -struct Bar { x: Foo } - ^^^ expected lifetime parameter -struct Bar<'a> { x: Foo<'a> } // correct +struct Bar1 { x: Foo2 } + // ^^^^ expected lifetime parameter +struct Bar2<'a> { x: Foo2<'a> } // correct -enum Bar { A(u8), B(&bool), } // error -enum Bar<'a> { A(u8), B(&'a bool), } // correct +enum Baz1 { A(u8), B(&bool), } + // ^ expected lifetime parameter +enum Baz2<'a> { A(u8), B(&'a bool), } // correct -type MyStr = &str; // error -type MyStr<'a> = &'a str; // correct +type MyStr1 = &str; + // ^ expected lifetime parameter +type MyStr2<'a> = &'a str; // correct ``` Lifetime elision is a special, limited kind of inference for lifetimes in diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 847cf64ce6a..ece239516cf 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1835,6 +1835,7 @@ impl<'a> LoweringContext<'a> { rules: self.lower_block_check_mode(&b.rules), span: b.span, targeted_by_break, + recovered: b.recovered, }) } @@ -2691,6 +2692,7 @@ impl<'a> LoweringContext<'a> { rules: hir::DefaultBlock, span, targeted_by_break: false, + recovered: blk.recovered, }); P(self.expr_block(blk, ThinVec::new())) } @@ -3507,6 +3509,7 @@ impl<'a> LoweringContext<'a> { rules: hir::DefaultBlock, span, targeted_by_break: false, + recovered: false, } } @@ -3610,6 +3613,7 @@ impl<'a> LoweringContext<'a> { stmts, expr: Some(expr), targeted_by_break: false, + recovered: false, }); self.expr_block(block, attrs) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 5e132865ca8..144a3fea971 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -625,6 +625,11 @@ pub struct Block { /// currently permitted in Rust itself, but it is generated as /// part of `catch` statements. pub targeted_by_break: bool, + /// If true, don't emit return value type errors as the parser had + /// to recover from a parse error so this block will not have an + /// appropriate type. A parse error will have been emitted so the + /// compilation will never succeed if this is true. + pub recovered: bool, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 02a394f9634..b0c7ce3cf23 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -378,12 +378,14 @@ impl<'gcx> HashStable> for hir::Block { rules, span, targeted_by_break, + recovered, } = *self; stmts.hash_stable(hcx, hasher); expr.hash_stable(hcx, hasher); rules.hash_stable(hcx, hasher); span.hash_stable(hcx, hasher); + recovered.hash_stable(hcx, hasher); targeted_by_break.hash_stable(hcx, hasher); } } diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 769ade5dbcc..4b51a0fbb83 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -729,6 +729,7 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> { fn fold_block(&mut self, b: P) -> P { fn expr_to_block(rules: ast::BlockCheckMode, + recovered: bool, e: Option>, sess: &Session) -> P { P(ast::Block { @@ -744,12 +745,13 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> { rules, id: sess.next_node_id(), span: syntax_pos::DUMMY_SP, + recovered, }) } if !self.within_static_or_const { - let empty_block = expr_to_block(BlockCheckMode::Default, None, self.sess); + let empty_block = expr_to_block(BlockCheckMode::Default, false, None, self.sess); let loop_expr = P(ast::Expr { node: ast::ExprKind::Loop(empty_block, None), id: self.sess.next_node_id(), @@ -757,7 +759,7 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> { attrs: ast::ThinVec::new(), }); - expr_to_block(b.rules, Some(loop_expr), self.sess) + expr_to_block(b.rules, b.recovered, Some(loop_expr), self.sess) } else { fold::noop_fold_block(b, self) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 14296e78ddd..ee0da4b8f36 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4279,7 +4279,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // // #41425 -- label the implicit `()` as being the // "found type" here, rather than the "expected type". - if !self.diverges.get().always() { + // + // #44579 -- if the block was recovered during parsing, + // the type would be nonsensical and it is not worth it + // to perform the type check, so we avoid generating the + // diagnostic output. + if !self.diverges.get().always() && !blk.recovered { coerce.coerce_forced_unit(self, &self.misc(blk.span), &mut |err| { if let Some(expected_ty) = expected.only_has_type(self) { self.consider_hint_about_removing_semicolon(blk, diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 1d399f159c8..a8bc8f7e0ce 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -468,6 +468,7 @@ pub struct Block { /// Distinguishes between `unsafe { ... }` and `{ ... }` pub rules: BlockCheckMode, pub span: Span, + pub recovered: bool, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 9a96432f11d..8aeebecf661 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -594,6 +594,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { id: ast::DUMMY_NODE_ID, rules: BlockCheckMode::Default, span, + recovered: false, }) } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 6f973e2bcfa..279add5d299 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -851,11 +851,12 @@ fn noop_fold_bounds(bounds: TyParamBounds, folder: &mut T) } pub fn noop_fold_block(b: P, folder: &mut T) -> P { - b.map(|Block {id, stmts, rules, span}| Block { + b.map(|Block {id, stmts, rules, span, recovered}| Block { id: folder.new_id(id), stmts: stmts.move_flat_map(|s| folder.fold_stmt(s).into_iter()), rules, span: folder.new_span(span), + recovered, }) } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 89a54989f96..f96c7e8598f 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -931,6 +931,7 @@ mod tests { id: ast::DUMMY_NODE_ID, rules: ast::BlockCheckMode::Default, // no idea span: sp(15,21), + recovered: false, })), vis: ast::Visibility::Inherited, span: sp(0,21)}))); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d9434539246..bb46cef5ee2 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4371,13 +4371,15 @@ impl<'a> Parser<'a> { /// Precondition: already parsed the '{'. fn parse_block_tail(&mut self, lo: Span, s: BlockCheckMode) -> PResult<'a, P> { let mut stmts = vec![]; + let mut recovered = false; while !self.eat(&token::CloseDelim(token::Brace)) { let stmt = match self.parse_full_stmt(false) { Err(mut err) => { err.emit(); - self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Break); + self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore); self.eat(&token::CloseDelim(token::Brace)); + recovered = true; break; } Ok(stmt) => stmt, @@ -4396,12 +4398,13 @@ impl<'a> Parser<'a> { id: ast::DUMMY_NODE_ID, rules: s, span: lo.to(self.prev_span), + recovered, })) } /// Parse a statement, including the trailing semicolon. pub fn parse_full_stmt(&mut self, macro_legacy_warnings: bool) -> PResult<'a, Option> { - let mut stmt = match self.parse_stmt_(macro_legacy_warnings) { + let mut stmt = match self.parse_stmt_without_recovery(macro_legacy_warnings)? { Some(stmt) => stmt, None => return Ok(None), }; diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index a6696b53369..a3246a21d5a 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -158,5 +158,6 @@ fn call_intrinsic(cx: &ExtCtxt, id: ast::DUMMY_NODE_ID, rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated), span, + recovered: false, })) } diff --git a/src/test/compile-fail/issue-34334.rs b/src/test/compile-fail/issue-34334.rs index 95b5fabc81e..a752a36ade2 100644 --- a/src/test/compile-fail/issue-34334.rs +++ b/src/test/compile-fail/issue-34334.rs @@ -11,5 +11,4 @@ fn main () { let sr: Vec<(u32, _, _) = vec![]; //~ ERROR expected one of `,` or `>`, found `=` let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect(); - //~^ ERROR cannot find value `sr` in this scope } diff --git a/src/test/parse-fail/issue-22647.rs b/src/test/parse-fail/issue-22647.rs index 3da9d1a8712..1ace57edba3 100644 --- a/src/test/parse-fail/issue-22647.rs +++ b/src/test/parse-fail/issue-22647.rs @@ -16,7 +16,6 @@ fn main() { println!("Y {}",x); return x; }; - //~^ ERROR expected item, found `;` caller(bar_handler); } diff --git a/src/test/parse-fail/keywords-followed-by-double-colon.rs b/src/test/parse-fail/keywords-followed-by-double-colon.rs index bb8a1dfdb19..7a5b48c5f00 100644 --- a/src/test/parse-fail/keywords-followed-by-double-colon.rs +++ b/src/test/parse-fail/keywords-followed-by-double-colon.rs @@ -11,6 +11,10 @@ // compile-flags: -Z parse-only fn main() { - struct::foo(); //~ ERROR expected identifier - mut::baz(); //~ ERROR expected expression, found keyword `mut` + struct::foo(); + //~^ ERROR expected identifier +} +fn bar() { + mut::baz(); + //~^ ERROR expected expression, found keyword `mut` } diff --git a/src/test/parse-fail/mut-patterns.rs b/src/test/parse-fail/mut-patterns.rs index ffb45597552..71d826c67f8 100644 --- a/src/test/parse-fail/mut-patterns.rs +++ b/src/test/parse-fail/mut-patterns.rs @@ -15,5 +15,4 @@ pub fn main() { struct Foo { x: isize } let mut Foo { x: x } = Foo { x: 3 }; //~ ERROR: expected one of `:`, `;`, `=`, or `@`, found `{` - //~^ ERROR expected item, found `=` } diff --git a/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs b/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs index e84a982f7b3..5afa9a217e0 100644 --- a/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs @@ -131,6 +131,7 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P)) { id: DUMMY_NODE_ID, rules: BlockCheckMode::Default, span: DUMMY_SP, + recovered: false, }); iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None))); }, diff --git a/src/test/ui/impossible_range.rs b/src/test/ui/impossible_range.rs index 330a9213bc7..5c72c506e6b 100644 --- a/src/test/ui/impossible_range.rs +++ b/src/test/ui/impossible_range.rs @@ -17,11 +17,13 @@ pub fn main() { 0..; ..1; 0..1; - ..=; //~ERROR inclusive range with no end - 0..=; //~ERROR inclusive range with no end - ..=1; - 0..=1; + //~^HELP bounded at the end } - +fn _foo1() { + ..=1; + 0..=1; + 0..=; //~ERROR inclusive range with no end + //~^HELP bounded at the end +} diff --git a/src/test/ui/impossible_range.stderr b/src/test/ui/impossible_range.stderr index 75c6d859621..e0e26bc4db0 100644 --- a/src/test/ui/impossible_range.stderr +++ b/src/test/ui/impossible_range.stderr @@ -1,15 +1,15 @@ error[E0586]: inclusive range with no end - --> $DIR/impossible_range.rs:21:8 + --> $DIR/impossible_range.rs:20:8 | -21 | ..=; //~ERROR inclusive range with no end +20 | ..=; //~ERROR inclusive range with no end | ^ | = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) error[E0586]: inclusive range with no end - --> $DIR/impossible_range.rs:22:9 + --> $DIR/impossible_range.rs:27:9 | -22 | 0..=; //~ERROR inclusive range with no end +27 | 0..=; //~ERROR inclusive range with no end | ^ | = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) diff --git a/src/test/ui/issue-44406.stderr b/src/test/ui/issue-44406.stderr index 2e71b001d7a..dd6435a954e 100644 --- a/src/test/ui/issue-44406.stderr +++ b/src/test/ui/issue-44406.stderr @@ -13,5 +13,3 @@ error: expected type, found keyword `true` 18 | foo!(true); //~ ERROR expected type, found keyword | ^^^^ expecting a type here because of type ascription -error: aborting due to 2 previous errors - diff --git a/src/test/ui/macro-context.stderr b/src/test/ui/macro-context.stderr index 37d99913d97..2be89b67d11 100644 --- a/src/test/ui/macro-context.stderr +++ b/src/test/ui/macro-context.stderr @@ -43,5 +43,3 @@ error: expected expression, found reserved keyword `typeof` 26 | m!(); | ----- in this macro invocation -error: aborting due to 4 previous errors - diff --git a/src/test/ui/mismatched_types/recovered-block.rs b/src/test/ui/mismatched_types/recovered-block.rs new file mode 100644 index 00000000000..f3e3579f2bc --- /dev/null +++ b/src/test/ui/mismatched_types/recovered-block.rs @@ -0,0 +1,31 @@ +// Copyright 2017 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. + +use std::env; + +pub struct Foo { + text: String +} + +pub fn foo() -> Foo { + let args: Vec = env::args().collect(); + let text = args[1].clone(); + + pub Foo { text } +} +//~^^ ERROR missing `struct` for struct definition + +pub fn bar() -> Foo { + fn + Foo { text: "".to_string() } +} +//~^^ ERROR expected one of `(` or `<`, found `{` + +fn main() {} diff --git a/src/test/ui/mismatched_types/recovered-block.stderr b/src/test/ui/mismatched_types/recovered-block.stderr new file mode 100644 index 00000000000..dcaf2812f59 --- /dev/null +++ b/src/test/ui/mismatched_types/recovered-block.stderr @@ -0,0 +1,18 @@ +error: missing `struct` for struct definition + --> $DIR/recovered-block.rs:21:8 + | +21 | pub Foo { text } + | ^ +help: add `struct` here to parse `Foo` as a public struct + | +21 | pub struct Foo { text } + | ^^^^^^ + +error: expected one of `(` or `<`, found `{` + --> $DIR/recovered-block.rs:27:9 + | +27 | Foo { text: "".to_string() } + | ^ expected one of `(` or `<` here + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/resolve/token-error-correct.rs b/src/test/ui/resolve/token-error-correct.rs index f8b5e670b84..c88f823839d 100644 --- a/src/test/ui/resolve/token-error-correct.rs +++ b/src/test/ui/resolve/token-error-correct.rs @@ -16,4 +16,3 @@ fn main() { } //~^ ERROR: incorrect close delimiter: `}` //~| ERROR: incorrect close delimiter: `}` -//~| ERROR: expected expression, found `)` diff --git a/src/test/ui/resolve/token-error-correct.stderr b/src/test/ui/resolve/token-error-correct.stderr index 0e396f6254a..e26f0e85aa6 100644 --- a/src/test/ui/resolve/token-error-correct.stderr +++ b/src/test/ui/resolve/token-error-correct.stderr @@ -28,11 +28,5 @@ error: expected expression, found `;` 14 | foo(bar(; | ^ -error: expected expression, found `)` - --> $DIR/token-error-correct.rs:16:1 - | -16 | } - | ^ - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors From d90d5d19da1126c5e66ede7d23bcfd8e18601a8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 21 Dec 2017 15:09:26 -0800 Subject: [PATCH 2/2] Mark clippy as broken --- src/tools/toolstate.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/toolstate.toml b/src/tools/toolstate.toml index b29e505c3b0..6901343e367 100644 --- a/src/tools/toolstate.toml +++ b/src/tools/toolstate.toml @@ -26,7 +26,7 @@ miri = "Broken" # ping @Manishearth @llogiq @mcarton @oli-obk -clippy = "Testing" +clippy = "Broken" # ping @nrc rls = "Broken"