From b621820dc4727677f14bee0ac5e2fa5e424ed22e Mon Sep 17 00:00:00 2001 From: John Clements Date: Tue, 30 Apr 2013 12:02:56 -0700 Subject: [PATCH] detect unused attrs in one more place, allow parsing to continue for all changed a bunch of fatal()'s into err()'s, to allow parsing to proceed. --- src/libsyntax/parse/mod.rs | 16 +++++++ src/libsyntax/parse/parser.rs | 61 ++++++++++++++---------- src/test/compile-fail/attr-before-ext.rs | 4 +- src/test/compile-fail/attr-before-let.rs | 4 +- 4 files changed, 57 insertions(+), 28 deletions(-) diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index f9cf421429c..7aff9f6745c 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -612,4 +612,20 @@ fn parser_done(p: Parser){ string_to_expr(@~"3 + 4"); string_to_expr(@~"a::z.froob(b,@(987+3))"); } + + #[test] fn attrs_fix_bug () { + string_to_item(@~"pub fn mk_file_writer(path: &Path, flags: &[FileFlag]) + -> Result<@Writer, ~str> { + #[cfg(windows)] + fn wb() -> c_int { + (O_WRONLY | libc::consts::os::extra::O_BINARY) as c_int + } + + #[cfg(unix)] + fn wb() -> c_int { O_WRONLY as c_int } + + let mut fflags: c_int = wb(); +}"); + } + } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a7ba67901e8..fddeea93024 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2588,20 +2588,22 @@ fn parse_name_and_ty(&self, }) } - // parse a statement. may include decl - fn parse_stmt(&self, first_item_attrs: ~[attribute]) -> @stmt { + // parse a statement. may include decl. + // precondition: any attributes are parsed already + fn parse_stmt(&self, item_attrs: ~[attribute]) -> @stmt { maybe_whole!(self, nt_stmt); fn check_expected_item(p: &Parser, current_attrs: &[attribute]) { // If we have attributes then we should have an item if !current_attrs.is_empty() { - p.fatal(~"expected item after attrs"); + p.span_err(*p.last_span, + ~"expected item after attributes"); } } let lo = self.span.lo; if self.is_keyword("let") { - check_expected_item(self, first_item_attrs); + check_expected_item(self, item_attrs); self.expect_keyword("let"); let decl = self.parse_let(); return @spanned(lo, decl.span.hi, stmt_decl(decl, self.get_id())); @@ -2614,7 +2616,7 @@ fn check_expected_item(p: &Parser, current_attrs: &[attribute]) { // to the macro clause of parse_item_or_view_item. This // could use some cleanup, it appears to me. - check_expected_item(self, first_item_attrs); + check_expected_item(self, item_attrs); // Potential trouble: if we allow macros with paths instead of // idents, we'd need to look ahead past the whole path here... @@ -2650,9 +2652,6 @@ fn check_expected_item(p: &Parser, current_attrs: &[attribute]) { } } else { - let item_attrs = vec::append(first_item_attrs, - self.parse_outer_attributes()); - match self.parse_item_or_view_item(/*bad*/ copy item_attrs, false) { iovi_item(i) => { @@ -2727,6 +2726,7 @@ fn parse_block_tail_(&self, lo: BytePos, s: blk_check_mode, let mut stmts = ~[]; let mut expr = None; + // wouldn't it be more uniform to parse view items only, here? let ParsedItemsAndViewItems { attrs_remaining: attrs_remaining, view_items: view_items, @@ -2741,23 +2741,29 @@ fn parse_block_tail_(&self, lo: BytePos, s: blk_check_mode, stmt_decl(decl, self.get_id()))); } - let mut initial_attrs = attrs_remaining; + let mut attributes_box = attrs_remaining; - if *self.token == token::RBRACE && !vec::is_empty(initial_attrs) { - self.fatal(~"expected item"); - } - - while *self.token != token::RBRACE { + while (*self.token != token::RBRACE) { + // parsing items even when they're not allowed lets us give + // better error messages and recover more gracefully. + attributes_box.push_all(self.parse_outer_attributes()); match *self.token { token::SEMI => { + if !vec::is_empty(attributes_box) { + self.span_err(*self.last_span,~"expected item after attributes"); + attributes_box = ~[]; + } self.bump(); // empty } + token::RBRACE => { + // fall through and out. + } _ => { - let stmt = self.parse_stmt(initial_attrs); - initial_attrs = ~[]; + let stmt = self.parse_stmt(attributes_box); + attributes_box = ~[]; match stmt.node { stmt_expr(e, stmt_id) => { - // Expression without semicolon + // expression without semicolon match *self.token { token::SEMI => { self.bump(); @@ -2773,7 +2779,7 @@ fn parse_block_tail_(&self, lo: BytePos, s: blk_check_mode, self.fatal( fmt!( "expected `;` or `}` after \ - expression but found `%s`", + expression but found `%s`", self.token_to_str(&t) ) ); @@ -2782,9 +2788,8 @@ fn parse_block_tail_(&self, lo: BytePos, s: blk_check_mode, } } } - stmt_mac(ref m, _) => { - // Statement macro; might be an expr + // statement macro; might be an expr match *self.token { token::SEMI => { self.bump(); @@ -2803,8 +2808,7 @@ fn parse_block_tail_(&self, lo: BytePos, s: blk_check_mode, _ => { stmts.push(stmt); } } } - - _ => { // All other kinds of statements: + _ => { // all other kinds of statements: stmts.push(stmt); if classify::stmt_ends_with_semi(stmt) { @@ -2815,6 +2819,11 @@ fn parse_block_tail_(&self, lo: BytePos, s: blk_check_mode, } } } + + if !vec::is_empty(attributes_box) { + self.span_err(*self.last_span,~"expected item after attributes"); + } + let hi = self.span.hi; self.bump(); let bloc = ast::blk_ { @@ -3519,7 +3528,7 @@ fn parse_mod_items(&self, term: token::Token, if first && attrs_remaining_len > 0u { // We parsed attributes for the first item but didn't find it - self.fatal(~"expected item"); + self.span_err(*self.last_span,~"expected item after attributes"); } ast::_mod { view_items: view_items, items: items } @@ -3724,11 +3733,15 @@ fn parse_foreign_mod_items(&self, first_item_attrs: ~[attribute]) -> foreign_mod { let ParsedItemsAndViewItems { - attrs_remaining: _, + attrs_remaining: attrs_remaining, view_items: view_items, items: _, foreign_items: foreign_items } = self.parse_foreign_items(first_item_attrs, true); + if (! attrs_remaining.is_empty()) { + self.span_err(*self.last_span, + ~"expected item after attributes"); + } assert!(*self.token == token::RBRACE); ast::foreign_mod { sort: sort, diff --git a/src/test/compile-fail/attr-before-ext.rs b/src/test/compile-fail/attr-before-ext.rs index 2675b865e90..cf0f4a6240e 100644 --- a/src/test/compile-fail/attr-before-ext.rs +++ b/src/test/compile-fail/attr-before-ext.rs @@ -9,6 +9,6 @@ // except according to those terms. fn main() { - #[attr] - debug!("hi"); //~ ERROR expected item after attrs + #[attr] //~ ERROR expected item after attributes + debug!("hi"); } diff --git a/src/test/compile-fail/attr-before-let.rs b/src/test/compile-fail/attr-before-let.rs index 51ee903b1b1..acc9aa8a9a1 100644 --- a/src/test/compile-fail/attr-before-let.rs +++ b/src/test/compile-fail/attr-before-let.rs @@ -9,6 +9,6 @@ // except according to those terms. fn main() { - #[attr] - let _i = 0; //~ ERROR expected item + #[attr] //~ ERROR expected item + let _i = 0; }