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, bounds,
items) items)
} }
ItemKind::Placeholder | ItemKind::MacroDef(..) | ItemKind::Mac(..) => { ItemKind::MacroDef(..) | ItemKind::Mac(..) => {
panic!("Shouldn't still be around") 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); return visit::walk_item(self, i);
} }
ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()), ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()),
ItemKind::Placeholder |
ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) => ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) =>
DefPathData::ValueNs(i.ident.name.as_str()), DefPathData::ValueNs(i.ident.name.as_str()),
ItemKind::MacroDef(..) => DefPathData::MacroDef(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); self.define(parent, ident, TypeNS, imported_binding);
} }
ItemKind::GlobalAsm(..) | ItemKind::Placeholder => {} ItemKind::GlobalAsm(..) => {}
ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root 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::ExternCrate(_) | ItemKind::MacroDef(..) | ItemKind::GlobalAsm(_) => {
ItemKind::Placeholder => {
// do nothing, these are just around to be encoded // 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). // FIXME should implement this (e.g., pub use).
ast::ItemKind::Use(_) => Err("import"), ast::ItemKind::Use(_) => Err("import"),
ast::ItemKind::Mac(..) | ast::ItemKind::MacroDef(_) => Err("Macro"), 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. /// A macro definition.
MacroDef(MacroDef), MacroDef(MacroDef),
Placeholder,
} }
impl ItemKind { impl ItemKind {
@ -1999,7 +1998,6 @@ impl ItemKind {
ItemKind::Mac(..) | ItemKind::Mac(..) |
ItemKind::MacroDef(..) | ItemKind::MacroDef(..) |
ItemKind::Impl(..) | ItemKind::Impl(..) |
ItemKind::Placeholder |
ItemKind::AutoImpl(..) => "item" 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::Mac(m) => ItemKind::Mac(folder.fold_mac(m)),
ItemKind::MacroDef(def) => ItemKind::MacroDef(folder.fold_macro_def(def)), 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> >); 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. /// How to parse a path.
#[derive(Copy, Clone, PartialEq)] #[derive(Copy, Clone, PartialEq)]
pub enum PathStyle { pub enum PathStyle {
@ -1411,7 +1367,6 @@ impl<'a> Parser<'a> {
debug!("parse_trait_methods(): parsing provided method"); debug!("parse_trait_methods(): parsing provided method");
*at_end = true; *at_end = true;
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
let body = body.emit();
attrs.extend(inner_attrs.iter().cloned()); attrs.extend(inner_attrs.iter().cloned());
Some(body) Some(body)
} }
@ -2447,7 +2402,7 @@ impl<'a> Parser<'a> {
let mut attrs = outer_attrs; let mut attrs = outer_attrs;
attrs.extend(self.parse_inner_attributes()?); 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)); return Ok(self.mk_expr(blk.span, ExprKind::Block(blk), attrs));
} }
@ -3204,7 +3159,7 @@ impl<'a> Parser<'a> {
let hi = self.prev_span; let hi = self.prev_span;
Ok(self.mk_expr(span_lo.to(hi), 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)) attrs))
} }
@ -3217,7 +3172,6 @@ impl<'a> Parser<'a> {
} }
let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
let (iattrs, body) = self.parse_inner_attrs_and_block()?; let (iattrs, body) = self.parse_inner_attrs_and_block()?;
let body = body.emit();
attrs.extend(iattrs); attrs.extend(iattrs);
let span = span_lo.to(body.span); let span = span_lo.to(body.span);
return Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_ident), attrs)); 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 expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
let (iattrs, body) = self.parse_inner_attrs_and_block()?; let (iattrs, body) = self.parse_inner_attrs_and_block()?;
attrs.extend(iattrs); attrs.extend(iattrs);
let body = body.emit();
let span = span_lo.to(body.span); let span = span_lo.to(body.span);
return Ok(self.mk_expr(span, ExprKind::WhileLet(pat, expr, body, opt_ident), attrs)); 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, span_lo: Span,
mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
let (iattrs, body) = self.parse_inner_attrs_and_block()?; let (iattrs, body) = self.parse_inner_attrs_and_block()?;
let body = body.emit();
attrs.extend(iattrs); attrs.extend(iattrs);
let span = span_lo.to(body.span); let span = span_lo.to(body.span);
Ok(self.mk_expr(span, ExprKind::Loop(body, opt_ident), attrs)) Ok(self.mk_expr(span, ExprKind::Loop(body, opt_ident), attrs))
@ -3254,7 +3206,6 @@ impl<'a> Parser<'a> {
-> PResult<'a, P<Expr>> -> PResult<'a, P<Expr>>
{ {
let (iattrs, body) = self.parse_inner_attrs_and_block()?; let (iattrs, body) = self.parse_inner_attrs_and_block()?;
let body = body.emit();
attrs.extend(iattrs); attrs.extend(iattrs);
Ok(self.mk_expr(span_lo.to(body.span), ExprKind::Catch(body), attrs)) Ok(self.mk_expr(span_lo.to(body.span), ExprKind::Catch(body), attrs))
} }
@ -4301,14 +4252,14 @@ impl<'a> Parser<'a> {
return Err(e); 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. /// Parse a block. Inner attrs are allowed.
fn parse_inner_attrs_and_block(&mut self) 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; let lo = self.span;
self.expect(&token::OpenDelim(token::Brace))?; self.expect(&token::OpenDelim(token::Brace))?;
@ -4319,15 +4270,14 @@ impl<'a> Parser<'a> {
/// Parse the rest of a block expression or function body /// Parse the rest of a block expression or function body
/// Precondition: already parsed the '{'. /// Precondition: already parsed the '{'.
fn parse_block_tail(&mut self, lo: Span, s: BlockCheckMode) 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 stmts = vec![];
let mut error = None;
while !self.eat(&token::CloseDelim(token::Brace)) { while !self.eat(&token::CloseDelim(token::Brace)) {
let stmt = match self.parse_full_stmt(false) { let stmt = match self.parse_full_stmt(false) {
Err(err) => { Err(mut err) => {
error = Some(err); err.emit();
self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Break); self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Break);
break; break;
} }
@ -4342,14 +4292,12 @@ impl<'a> Parser<'a> {
continue; continue;
}; };
} }
let block = HasRecovered::new(P(ast::Block { Ok(P(ast::Block {
stmts, stmts,
id: ast::DUMMY_NODE_ID, id: ast::DUMMY_NODE_ID,
rules: s, rules: s,
span: lo.to(self.prev_span), span: lo.to(self.prev_span),
}), error); }))
Ok(block)
} }
/// Parse a statement, including the trailing semicolon. /// Parse a statement, including the trailing semicolon.
@ -4984,22 +4932,11 @@ impl<'a> Parser<'a> {
constness: Spanned<Constness>, constness: Spanned<Constness>,
abi: abi::Abi) abi: abi::Abi)
-> PResult<'a, ItemInfo> { -> 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 (ident, mut generics) = self.parse_fn_header()?;
let decl = self.parse_fn_decl(false)?; let decl = self.parse_fn_decl(false)?;
generics.where_clause = self.parse_where_clause()?; generics.where_clause = self.parse_where_clause()?;
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
Ok(body.map(|body| (ident, Ok((ident, ItemKind::Fn(decl, unsafety, constness, abi, generics, body), Some(inner_attrs)))
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 /// 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()?; generics.where_clause = self.parse_where_clause()?;
*at_end = true; *at_end = true;
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; 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 { Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(ast::MethodSig {
abi, abi,
unsafety, unsafety,
@ -6369,49 +6305,31 @@ impl<'a> Parser<'a> {
let mut err = self.diagnostic() let mut err = self.diagnostic()
.struct_span_err(sp, "missing `struct` for struct definition"); .struct_span_err(sp, "missing `struct` for struct definition");
err.span_suggestion_short(sp, &msg, " struct ".into()); err.span_suggestion_short(sp, &msg, " struct ".into());
err.emit(); return Err(err);
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));
} else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) { } else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) {
let ident = self.parse_ident().unwrap(); let ident = self.parse_ident().unwrap();
self.consume_block(token::Paren); self.consume_block(token::Paren);
let (kw, ambiguous) = if self.check(&token::OpenDelim(token::Brace)) { let (kw, kw_name, ambiguous) = if self.check(&token::RArrow) ||
self.consume_block(token::Brace); self.check(&token::OpenDelim(token::Brace))
("fn", false) {
("fn", "method", false)
} else if self.check(&token::Colon) { } else if self.check(&token::Colon) {
let kw = "struct"; let kw = "struct";
(kw, false) (kw, kw, false)
} else { } else {
("fn` or `struct", true) ("fn` or `struct", "method or struct", true)
}; };
let msg = format!("missing `{}`{}", kw, let msg = format!("missing `{}` for {} definition", kw, kw_name);
if ambiguous {
"".to_string()
} else {
format!(" for {} definition", kw)
});
let mut err = self.diagnostic().struct_span_err(sp, &msg); let mut err = self.diagnostic().struct_span_err(sp, &msg);
if !ambiguous { 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, ident,
kw=kw); kw_name);
err.span_suggestion_short(sp, &suggestion, format!(" {} ", kw)); err.span_suggestion_short(sp, &suggestion, format!(" {} ", kw));
} }
err.emit(); return Err(err);
let prev_span = self.prev_span;
let item = self.mk_item(lo.to(prev_span),
ident,
ItemKind::Placeholder,
visibility,
vec![]);
return Ok(Some(item));
} }
} }
self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, visibility) 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.s.word(";")?;
self.end()?; 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)) 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::Mac(ref mac) => visitor.visit_mac(mac),
ItemKind::MacroDef(ref ts) => visitor.visit_mac_def(ts, item.id), ItemKind::MacroDef(ref ts) => visitor.visit_mac_def(ts, item.id),
ItemKind::Placeholder => (),
} }
walk_list!(visitor, visit_attribute, &item.attrs); walk_list!(visitor, visit_attribute, &item.attrs);
} }

View File

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

View File

@ -8,32 +8,8 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
pub Struct { pub foo(s: usize) { bar() }
y: usize,
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 // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
pub Struct { pub S();
y: usize,
}
pub Y { fn main() {}
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,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