Skip to content

Commit b621820

Browse files
committed
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.
1 parent 05ab83e commit b621820

File tree

4 files changed

+57
-28
lines changed

4 files changed

+57
-28
lines changed

src/libsyntax/parse/mod.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,4 +612,20 @@ mod test {
612612
string_to_expr(@~"3 + 4");
613613
string_to_expr(@~"a::z.froob(b,@(987+3))");
614614
}
615+
616+
#[test] fn attrs_fix_bug () {
617+
string_to_item(@~"pub fn mk_file_writer(path: &Path, flags: &[FileFlag])
618+
-> Result<@Writer, ~str> {
619+
#[cfg(windows)]
620+
fn wb() -> c_int {
621+
(O_WRONLY | libc::consts::os::extra::O_BINARY) as c_int
622+
}
623+
624+
#[cfg(unix)]
625+
fn wb() -> c_int { O_WRONLY as c_int }
626+
627+
let mut fflags: c_int = wb();
628+
}");
629+
}
630+
615631
}

src/libsyntax/parse/parser.rs

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2588,20 +2588,22 @@ pub impl Parser {
25882588
})
25892589
}
25902590

2591-
// parse a statement. may include decl
2592-
fn parse_stmt(&self, first_item_attrs: ~[attribute]) -> @stmt {
2591+
// parse a statement. may include decl.
2592+
// precondition: any attributes are parsed already
2593+
fn parse_stmt(&self, item_attrs: ~[attribute]) -> @stmt {
25932594
maybe_whole!(self, nt_stmt);
25942595

25952596
fn check_expected_item(p: &Parser, current_attrs: &[attribute]) {
25962597
// If we have attributes then we should have an item
25972598
if !current_attrs.is_empty() {
2598-
p.fatal(~"expected item after attrs");
2599+
p.span_err(*p.last_span,
2600+
~"expected item after attributes");
25992601
}
26002602
}
26012603

26022604
let lo = self.span.lo;
26032605
if self.is_keyword("let") {
2604-
check_expected_item(self, first_item_attrs);
2606+
check_expected_item(self, item_attrs);
26052607
self.expect_keyword("let");
26062608
let decl = self.parse_let();
26072609
return @spanned(lo, decl.span.hi, stmt_decl(decl, self.get_id()));
@@ -2614,7 +2616,7 @@ pub impl Parser {
26142616
// to the macro clause of parse_item_or_view_item. This
26152617
// could use some cleanup, it appears to me.
26162618

2617-
check_expected_item(self, first_item_attrs);
2619+
check_expected_item(self, item_attrs);
26182620

26192621
// Potential trouble: if we allow macros with paths instead of
26202622
// idents, we'd need to look ahead past the whole path here...
@@ -2650,9 +2652,6 @@ pub impl Parser {
26502652
}
26512653

26522654
} else {
2653-
let item_attrs = vec::append(first_item_attrs,
2654-
self.parse_outer_attributes());
2655-
26562655
match self.parse_item_or_view_item(/*bad*/ copy item_attrs,
26572656
false) {
26582657
iovi_item(i) => {
@@ -2727,6 +2726,7 @@ pub impl Parser {
27272726
let mut stmts = ~[];
27282727
let mut expr = None;
27292728

2729+
// wouldn't it be more uniform to parse view items only, here?
27302730
let ParsedItemsAndViewItems {
27312731
attrs_remaining: attrs_remaining,
27322732
view_items: view_items,
@@ -2741,23 +2741,29 @@ pub impl Parser {
27412741
stmt_decl(decl, self.get_id())));
27422742
}
27432743

2744-
let mut initial_attrs = attrs_remaining;
2745-
2746-
if *self.token == token::RBRACE && !vec::is_empty(initial_attrs) {
2747-
self.fatal(~"expected item");
2748-
}
2744+
let mut attributes_box = attrs_remaining;
27492745

2750-
while *self.token != token::RBRACE {
2746+
while (*self.token != token::RBRACE) {
2747+
// parsing items even when they're not allowed lets us give
2748+
// better error messages and recover more gracefully.
2749+
attributes_box.push_all(self.parse_outer_attributes());
27512750
match *self.token {
27522751
token::SEMI => {
2752+
if !vec::is_empty(attributes_box) {
2753+
self.span_err(*self.last_span,~"expected item after attributes");
2754+
attributes_box = ~[];
2755+
}
27532756
self.bump(); // empty
27542757
}
2758+
token::RBRACE => {
2759+
// fall through and out.
2760+
}
27552761
_ => {
2756-
let stmt = self.parse_stmt(initial_attrs);
2757-
initial_attrs = ~[];
2762+
let stmt = self.parse_stmt(attributes_box);
2763+
attributes_box = ~[];
27582764
match stmt.node {
27592765
stmt_expr(e, stmt_id) => {
2760-
// Expression without semicolon
2766+
// expression without semicolon
27612767
match *self.token {
27622768
token::SEMI => {
27632769
self.bump();
@@ -2773,7 +2779,7 @@ pub impl Parser {
27732779
self.fatal(
27742780
fmt!(
27752781
"expected `;` or `}` after \
2776-
expression but found `%s`",
2782+
expression but found `%s`",
27772783
self.token_to_str(&t)
27782784
)
27792785
);
@@ -2782,9 +2788,8 @@ pub impl Parser {
27822788
}
27832789
}
27842790
}
2785-
27862791
stmt_mac(ref m, _) => {
2787-
// Statement macro; might be an expr
2792+
// statement macro; might be an expr
27882793
match *self.token {
27892794
token::SEMI => {
27902795
self.bump();
@@ -2803,8 +2808,7 @@ pub impl Parser {
28032808
_ => { stmts.push(stmt); }
28042809
}
28052810
}
2806-
2807-
_ => { // All other kinds of statements:
2811+
_ => { // all other kinds of statements:
28082812
stmts.push(stmt);
28092813

28102814
if classify::stmt_ends_with_semi(stmt) {
@@ -2815,6 +2819,11 @@ pub impl Parser {
28152819
}
28162820
}
28172821
}
2822+
2823+
if !vec::is_empty(attributes_box) {
2824+
self.span_err(*self.last_span,~"expected item after attributes");
2825+
}
2826+
28182827
let hi = self.span.hi;
28192828
self.bump();
28202829
let bloc = ast::blk_ {
@@ -3519,7 +3528,7 @@ pub impl Parser {
35193528

35203529
if first && attrs_remaining_len > 0u {
35213530
// We parsed attributes for the first item but didn't find it
3522-
self.fatal(~"expected item");
3531+
self.span_err(*self.last_span,~"expected item after attributes");
35233532
}
35243533

35253534
ast::_mod { view_items: view_items, items: items }
@@ -3724,11 +3733,15 @@ pub impl Parser {
37243733
first_item_attrs: ~[attribute])
37253734
-> foreign_mod {
37263735
let ParsedItemsAndViewItems {
3727-
attrs_remaining: _,
3736+
attrs_remaining: attrs_remaining,
37283737
view_items: view_items,
37293738
items: _,
37303739
foreign_items: foreign_items
37313740
} = self.parse_foreign_items(first_item_attrs, true);
3741+
if (! attrs_remaining.is_empty()) {
3742+
self.span_err(*self.last_span,
3743+
~"expected item after attributes");
3744+
}
37323745
assert!(*self.token == token::RBRACE);
37333746
ast::foreign_mod {
37343747
sort: sort,

src/test/compile-fail/attr-before-ext.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@
99
// except according to those terms.
1010

1111
fn main() {
12-
#[attr]
13-
debug!("hi"); //~ ERROR expected item after attrs
12+
#[attr] //~ ERROR expected item after attributes
13+
debug!("hi");
1414
}

src/test/compile-fail/attr-before-let.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@
99
// except according to those terms.
1010

1111
fn main() {
12-
#[attr]
13-
let _i = 0; //~ ERROR expected item
12+
#[attr] //~ ERROR expected item
13+
let _i = 0;
1414
}

0 commit comments

Comments
 (0)