Do not attemt to continue parsing after pub ident

Try to identify the following code in order to provide better
diagnostics, but return the error to bail out early during the parse.
This commit is contained in:
Esteban Küber 2017-11-21 08:03:02 -08:00
parent 7c0387e36a
commit c82e9e8e1e
19 changed files with 75 additions and 283 deletions

View file

@ -1757,7 +1757,7 @@ impl<'a> LoweringContext<'a> {
bounds,
items)
}
ItemKind::Placeholder | ItemKind::MacroDef(..) | ItemKind::Mac(..) => {
ItemKind::MacroDef(..) | ItemKind::Mac(..) => {
panic!("Shouldn't still be around")
}
}

View file

@ -113,7 +113,6 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
return visit::walk_item(self, i);
}
ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()),
ItemKind::Placeholder |
ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) =>
DefPathData::ValueNs(i.ident.name.as_str()),
ItemKind::MacroDef(..) => DefPathData::MacroDef(i.ident.name.as_str()),

View file

@ -269,7 +269,7 @@ impl<'a> Resolver<'a> {
self.define(parent, ident, TypeNS, imported_binding);
}
ItemKind::GlobalAsm(..) | ItemKind::Placeholder => {}
ItemKind::GlobalAsm(..) => {}
ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root

View file

@ -1947,8 +1947,7 @@ impl<'a> Resolver<'a> {
}
}
ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) | ItemKind::GlobalAsm(_) |
ItemKind::Placeholder => {
ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) | ItemKind::GlobalAsm(_) => {
// do nothing, these are just around to be encoded
}

View file

@ -548,7 +548,6 @@ impl Sig for ast::Item {
// FIXME should implement this (e.g., pub use).
ast::ItemKind::Use(_) => Err("import"),
ast::ItemKind::Mac(..) | ast::ItemKind::MacroDef(_) => Err("Macro"),
ast::ItemKind::Placeholder => Err("placeholder"),
}
}
}

View file

@ -1977,7 +1977,6 @@ pub enum ItemKind {
/// A macro definition.
MacroDef(MacroDef),
Placeholder,
}
impl ItemKind {
@ -1999,7 +1998,6 @@ impl ItemKind {
ItemKind::Mac(..) |
ItemKind::MacroDef(..) |
ItemKind::Impl(..) |
ItemKind::Placeholder |
ItemKind::AutoImpl(..) => "item"
}
}

View file

@ -935,7 +935,6 @@ pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind {
),
ItemKind::Mac(m) => ItemKind::Mac(folder.fold_mac(m)),
ItemKind::MacroDef(def) => ItemKind::MacroDef(folder.fold_macro_def(def)),
ItemKind::Placeholder => ItemKind::Placeholder,
}
}

View file

@ -72,50 +72,6 @@ bitflags! {
type ItemInfo = (Ident, ItemKind, Option<Vec<Attribute> >);
enum HasRecovered<'a, T> {
Success(T),
Recovered(T, DiagnosticBuilder<'a>),
}
impl<'a, T> HasRecovered<'a, T> {
fn new(t: T, err: Option<DiagnosticBuilder<'a>>) -> HasRecovered<'a, T> {
if let Some(err) = err {
HasRecovered::Recovered(t, err)
} else {
HasRecovered::Success(t)
}
}
fn map<O, F: FnOnce(T) -> O>(self, f: F) -> HasRecovered<'a, O> {
let (t, e) = self.full_unwrap();
HasRecovered::new(f(t), e)
}
fn emit(self) -> T {
match self {
HasRecovered::Recovered(t, mut err) => {
err.emit();
t
}
HasRecovered::Success(t) => t,
}
}
fn full_unwrap(self) -> (T, Option<DiagnosticBuilder<'a>>) {
match self {
HasRecovered::Recovered(t, err) => (t, Some(err)),
HasRecovered::Success(t) => (t, None),
}
}
fn into_result(self) -> PResult<'a, T> {
match self {
HasRecovered::Recovered(_, err) => Err(err),
HasRecovered::Success(t) => Ok(t),
}
}
}
/// How to parse a path.
#[derive(Copy, Clone, PartialEq)]
pub enum PathStyle {
@ -1411,7 +1367,6 @@ impl<'a> Parser<'a> {
debug!("parse_trait_methods(): parsing provided method");
*at_end = true;
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
let body = body.emit();
attrs.extend(inner_attrs.iter().cloned());
Some(body)
}
@ -2447,7 +2402,7 @@ impl<'a> Parser<'a> {
let mut attrs = outer_attrs;
attrs.extend(self.parse_inner_attributes()?);
let blk = self.parse_block_tail(lo, blk_mode)?.emit();
let blk = self.parse_block_tail(lo, blk_mode)?;
return Ok(self.mk_expr(blk.span, ExprKind::Block(blk), attrs));
}
@ -3204,7 +3159,7 @@ impl<'a> Parser<'a> {
let hi = self.prev_span;
Ok(self.mk_expr(span_lo.to(hi),
ExprKind::ForLoop(pat, expr, loop_block.emit(), opt_ident),
ExprKind::ForLoop(pat, expr, loop_block, opt_ident),
attrs))
}
@ -3217,7 +3172,6 @@ impl<'a> Parser<'a> {
}
let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
let body = body.emit();
attrs.extend(iattrs);
let span = span_lo.to(body.span);
return Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_ident), attrs));
@ -3233,7 +3187,6 @@ impl<'a> Parser<'a> {
let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
attrs.extend(iattrs);
let body = body.emit();
let span = span_lo.to(body.span);
return Ok(self.mk_expr(span, ExprKind::WhileLet(pat, expr, body, opt_ident), attrs));
}
@ -3243,7 +3196,6 @@ impl<'a> Parser<'a> {
span_lo: Span,
mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
let body = body.emit();
attrs.extend(iattrs);
let span = span_lo.to(body.span);
Ok(self.mk_expr(span, ExprKind::Loop(body, opt_ident), attrs))
@ -3254,7 +3206,6 @@ impl<'a> Parser<'a> {
-> PResult<'a, P<Expr>>
{
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
let body = body.emit();
attrs.extend(iattrs);
Ok(self.mk_expr(span_lo.to(body.span), ExprKind::Catch(body), attrs))
}
@ -4301,14 +4252,14 @@ impl<'a> Parser<'a> {
return Err(e);
}
Ok(self.parse_block_tail(lo, BlockCheckMode::Default)?.emit())
Ok(self.parse_block_tail(lo, BlockCheckMode::Default)?)
}
/// Parse a block. Inner attrs are allowed.
fn parse_inner_attrs_and_block(&mut self)
-> PResult<'a, (Vec<Attribute>, HasRecovered<'a, P<Block>>)>
-> PResult<'a, (Vec<Attribute>, P<Block>)>
{
maybe_whole!(self, NtBlock, |x| (Vec::new(), HasRecovered::Success(x)));
maybe_whole!(self, NtBlock, |x| (Vec::new(), x));
let lo = self.span;
self.expect(&token::OpenDelim(token::Brace))?;
@ -4319,15 +4270,14 @@ impl<'a> Parser<'a> {
/// Parse the rest of a block expression or function body
/// Precondition: already parsed the '{'.
fn parse_block_tail(&mut self, lo: Span, s: BlockCheckMode)
-> PResult<'a, HasRecovered<'a, P<Block>>>
-> PResult<'a, P<Block>>
{
let mut stmts = vec![];
let mut error = None;
while !self.eat(&token::CloseDelim(token::Brace)) {
let stmt = match self.parse_full_stmt(false) {
Err(err) => {
error = Some(err);
Err(mut err) => {
err.emit();
self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Break);
break;
}
@ -4342,14 +4292,12 @@ impl<'a> Parser<'a> {
continue;
};
}
let block = HasRecovered::new(P(ast::Block {
Ok(P(ast::Block {
stmts,
id: ast::DUMMY_NODE_ID,
rules: s,
span: lo.to(self.prev_span),
}), error);
Ok(block)
}))
}
/// Parse a statement, including the trailing semicolon.
@ -4984,22 +4932,11 @@ impl<'a> Parser<'a> {
constness: Spanned<Constness>,
abi: abi::Abi)
-> PResult<'a, ItemInfo> {
self.parse_item_fn_recoverable(unsafety, constness, abi)?.into_result()
}
fn parse_item_fn_recoverable(&mut self,
unsafety: Unsafety,
constness: Spanned<Constness>,
abi: abi::Abi)
-> PResult<'a, HasRecovered<'a, ItemInfo>> {
let (ident, mut generics) = self.parse_fn_header()?;
let decl = self.parse_fn_decl(false)?;
generics.where_clause = self.parse_where_clause()?;
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
Ok(body.map(|body| (ident,
ItemKind::Fn(decl, unsafety, constness, abi, generics, body),
Some(inner_attrs))))
Ok((ident, ItemKind::Fn(decl, unsafety, constness, abi, generics, body), Some(inner_attrs)))
}
/// true if we are looking at `const ID`, false for things like `const fn` etc
@ -5183,7 +5120,6 @@ impl<'a> Parser<'a> {
generics.where_clause = self.parse_where_clause()?;
*at_end = true;
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
let body = body.into_result()?;
Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(ast::MethodSig {
abi,
unsafety,
@ -6369,49 +6305,31 @@ impl<'a> Parser<'a> {
let mut err = self.diagnostic()
.struct_span_err(sp, "missing `struct` for struct definition");
err.span_suggestion_short(sp, &msg, " struct ".into());
err.emit();
self.consume_block(token::Brace);
let prev_span = self.prev_span;
let item = self.mk_item(lo.to(prev_span),
ident,
ItemKind::Placeholder,
visibility,
vec![]);
return Ok(Some(item));
return Err(err);
} else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) {
let ident = self.parse_ident().unwrap();
self.consume_block(token::Paren);
let (kw, ambiguous) = if self.check(&token::OpenDelim(token::Brace)) {
self.consume_block(token::Brace);
("fn", false)
let (kw, kw_name, ambiguous) = if self.check(&token::RArrow) ||
self.check(&token::OpenDelim(token::Brace))
{
("fn", "method", false)
} else if self.check(&token::Colon) {
let kw = "struct";
(kw, false)
(kw, kw, false)
} else {
("fn` or `struct", true)
("fn` or `struct", "method or struct", true)
};
let msg = format!("missing `{}`{}", kw,
if ambiguous {
"".to_string()
} else {
format!(" for {} definition", kw)
});
let msg = format!("missing `{}` for {} definition", kw, kw_name);
let mut err = self.diagnostic().struct_span_err(sp, &msg);
if !ambiguous {
let suggestion = format!("add `{kw}` here to parse `{}` as a public {kw}",
let suggestion = format!("add `{}` here to parse `{}` as a public {}",
kw,
ident,
kw=kw);
kw_name);
err.span_suggestion_short(sp, &suggestion, format!(" {} ", kw));
}
err.emit();
let prev_span = self.prev_span;
let item = self.mk_item(lo.to(prev_span),
ident,
ItemKind::Placeholder,
visibility,
vec![]);
return Ok(Some(item));
return Err(err);
}
}
self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, visibility)

View file

@ -1386,12 +1386,6 @@ impl<'a> State<'a> {
self.s.word(";")?;
self.end()?;
}
ast::ItemKind::Placeholder => {
self.s.word("<placeholder ")?;
self.print_ident(item.ident)?;
self.s.word(">")?;
self.end()?;
}
}
self.ann.post(self, NodeItem(item))
}

View file

@ -307,7 +307,6 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
}
ItemKind::Mac(ref mac) => visitor.visit_mac(mac),
ItemKind::MacroDef(ref ts) => visitor.visit_mac_def(ts, item.id),
ItemKind::Placeholder => (),
}
walk_list!(visitor, visit_attribute, &item.attrs);
}

View file

@ -16,4 +16,4 @@ struct Foo {
pub(crate) () foo: usize,
}
fn main() {}

View file

@ -8,32 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub Struct {
y: usize,
pub foo(s: usize) { bar() }
fn main() {
foo(2);
}
pub Y {
x: usize,
pub struct X {
foo();
}
pub Z {
x->foo(),
}
pub foo(foo) {
foo
}
pub struct X {
foo();
}
pub Z {
x->foo(),
}
fn main(){}

View file

@ -0,0 +1,13 @@
error: missing `fn` for method definition
--> $DIR/pub-ident-fn-2.rs:11:4
|
11 | pub foo(s: usize) { bar() }
| ^
|
help: add `fn` here to parse `foo` as a public method
|
11 | pub fn foo(s: usize) { bar() }
| ^^
error: aborting due to previous error

View file

@ -8,32 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub Struct {
y: usize,
}
pub S();
pub Y {
x: usize,
}
pub struct X {
foo();
}
pub Z {
x->foo(),
}
pub foo(foo) {
foo
}
pub struct X {
foo();
}
pub Z {
x->foo(),
}
fn main(){}
fn main() {}

View file

@ -0,0 +1,8 @@
error: missing `fn` or `struct` for method or struct definition
--> $DIR/pub-ident-fn-or-struct-2.rs:11:4
|
11 | pub S();
| ^
error: aborting due to previous error

View file

@ -0,0 +1,13 @@
// 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 <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.
pub S (foo) bar
fn main() {}

View file

@ -0,0 +1,8 @@
error: missing `fn` or `struct` for method or struct definition
--> $DIR/pub-ident-fn-or-struct.rs:11:4
|
11 | pub S (foo) bar
| ^
error: aborting due to previous error

View file

@ -1,36 +0,0 @@
error: this file contains an un-closed delimiter
--> $DIR/pub-ident-missing-kw-unclosed-block.rs:29:13
|
39 | fn main(){}
| ^
|
help: did you mean to close this delimiter?
--> $DIR/pub-ident-missing-kw-unclosed-block.rs:5:7
|
15 | pub Y {
| ^
error: missing `struct` for struct definition
--> $DIR/pub-ident-missing-kw-unclosed-block.rs:1:4
|
11 | pub Struct {
| ^
|
help: add `struct` here to parse `Struct` as a public struct
|
11 | pub struct Struct {
| ^^^^^^
error: missing `struct` for struct definition
--> $DIR/pub-ident-missing-kw-unclosed-block.rs:5:4
|
15 | pub Y {
| ^
|
help: add `struct` here to parse `Y` as a public struct
|
15 | pub struct Y {
| ^^^^^^
error: aborting due to 3 previous errors

View file

@ -1,69 +0,0 @@
error: missing `struct` for struct definition
--> $DIR/pub-ident-missing-kw.rs:11:4
|
11 | pub Struct {
| ^
|
help: add `struct` here to parse `Struct` as a public struct
|
11 | pub struct Struct {
| ^^^^^^
error: missing `struct` for struct definition
--> $DIR/pub-ident-missing-kw.rs:15:4
|
15 | pub Y {
| ^
|
help: add `struct` here to parse `Y` as a public struct
|
15 | pub struct Y {
| ^^^^^^
error: expected `:`, found `(`
--> $DIR/pub-ident-missing-kw.rs:20:8
|
20 | foo();
| ^
error: missing `struct` for struct definition
--> $DIR/pub-ident-missing-kw.rs:23:4
|
23 | pub Z {
| ^
|
help: add `struct` here to parse `Z` as a public struct
|
23 | pub struct Z {
| ^^^^^^
error: missing `fn` for fn definition
--> $DIR/pub-ident-missing-kw.rs:27:4
|
27 | pub foo(foo) {
| ^
|
help: add `fn` here to parse `foo` as a public fn
|
27 | pub fn foo(foo) {
| ^^
error: expected `:`, found `(`
--> $DIR/pub-ident-missing-kw.rs:32:8
|
32 | foo();
| ^
error: missing `struct` for struct definition
--> $DIR/pub-ident-missing-kw.rs:35:4
|
35 | pub Z {
| ^
|
help: add `struct` here to parse `Z` as a public struct
|
35 | pub struct Z {
| ^^^^^^
error: aborting due to 7 previous errors