Skip to content

Commit 3466c9b

Browse files
committed
rustc: Parse fn inner attributes. Closes #1506
1 parent 17585cc commit 3466c9b

File tree

6 files changed

+134
-30
lines changed

6 files changed

+134
-30
lines changed

src/comp/syntax/parse/parser.rs

+96-29
Original file line numberDiff line numberDiff line change
@@ -1531,21 +1531,32 @@ fn parse_let(p: parser) -> @ast::decl {
15311531
ret @spanned(lo, p.last_span.hi, ast::decl_local(locals));
15321532
}
15331533

1534-
fn parse_stmt(p: parser) -> @ast::stmt {
1534+
fn parse_stmt(p: parser, first_item_attrs: [ast::attribute]) -> @ast::stmt {
1535+
fn check_expected_item(p: parser, current_attrs: [ast::attribute]) {
1536+
// If we have attributes then we should have an item
1537+
if vec::is_not_empty(current_attrs) {
1538+
p.fatal("expected item");
1539+
}
1540+
}
1541+
15351542
let lo = p.span.lo;
1536-
if eat_word(p, "let") {
1543+
if is_word(p, "let") {
1544+
check_expected_item(p, first_item_attrs);
1545+
expect_word(p, "let");
15371546
let decl = parse_let(p);
15381547
ret @spanned(lo, decl.span.hi, ast::stmt_decl(decl, p.get_id()));
15391548
} else {
15401549
let item_attrs;
1541-
alt parse_outer_attrs_or_ext(p) {
1550+
alt parse_outer_attrs_or_ext(p, first_item_attrs) {
15421551
none. { item_attrs = []; }
15431552
some(left(attrs)) { item_attrs = attrs; }
15441553
some(right(ext)) {
15451554
ret @spanned(lo, ext.span.hi, ast::stmt_expr(ext, p.get_id()));
15461555
}
15471556
}
15481557

1558+
let item_attrs = first_item_attrs + item_attrs;
1559+
15491560
alt parse_item(p, item_attrs) {
15501561
some(i) {
15511562
let hi = i.span.hi;
@@ -1555,10 +1566,7 @@ fn parse_stmt(p: parser) -> @ast::stmt {
15551566
none() { /* fallthrough */ }
15561567
}
15571568

1558-
// If we have attributes then we should have an item
1559-
if vec::len(item_attrs) > 0u {
1560-
ret p.fatal("expected item");
1561-
}
1569+
check_expected_item(p, item_attrs);
15621570

15631571
// Remainder are line-expr stmts.
15641572
let e = parse_expr_res(p, RESTRICT_STMT_EXPR);
@@ -1605,16 +1613,37 @@ fn stmt_ends_with_semi(stmt: ast::stmt) -> bool {
16051613
}
16061614

16071615
fn parse_block(p: parser) -> ast::blk {
1616+
let (attrs, blk) = parse_inner_attrs_and_block(p, false);
1617+
assert vec::is_empty(attrs);
1618+
ret blk;
1619+
}
1620+
1621+
fn parse_inner_attrs_and_block(
1622+
p: parser, parse_attrs: bool) -> ([ast::attribute], ast::blk) {
1623+
1624+
fn maybe_parse_inner_attrs_and_next(
1625+
p: parser, parse_attrs: bool) ->
1626+
{inner: [ast::attribute], next: [ast::attribute]} {
1627+
if parse_attrs {
1628+
parse_inner_attrs_and_next(p)
1629+
} else {
1630+
{inner: [], next: []}
1631+
}
1632+
}
1633+
16081634
let lo = p.span.lo;
16091635
if eat_word(p, "unchecked") {
16101636
expect(p, token::LBRACE);
1611-
be parse_block_tail(p, lo, ast::unchecked_blk);
1637+
let {inner, next} = maybe_parse_inner_attrs_and_next(p, parse_attrs);
1638+
ret (inner, parse_block_tail_(p, lo, ast::unchecked_blk, next));
16121639
} else if eat_word(p, "unsafe") {
16131640
expect(p, token::LBRACE);
1614-
be parse_block_tail(p, lo, ast::unsafe_blk);
1641+
let {inner, next} = maybe_parse_inner_attrs_and_next(p, parse_attrs);
1642+
ret (inner, parse_block_tail_(p, lo, ast::unsafe_blk, next));
16151643
} else {
16161644
expect(p, token::LBRACE);
1617-
be parse_block_tail(p, lo, ast::default_blk);
1645+
let {inner, next} = maybe_parse_inner_attrs_and_next(p, parse_attrs);
1646+
ret (inner, parse_block_tail_(p, lo, ast::default_blk, next));
16181647
}
16191648
}
16201649

@@ -1630,15 +1659,28 @@ fn parse_block_no_value(p: parser) -> ast::blk {
16301659
// necessary, and this should take a qualifier.
16311660
// some blocks start with "#{"...
16321661
fn parse_block_tail(p: parser, lo: uint, s: ast::blk_check_mode) -> ast::blk {
1633-
let stmts = [], expr = none;
1634-
let view_items = parse_view_import_only(p);
1662+
parse_block_tail_(p, lo, s, [])
1663+
}
1664+
1665+
fn parse_block_tail_(p: parser, lo: uint, s: ast::blk_check_mode,
1666+
first_item_attrs: [ast::attribute]) -> ast::blk {
1667+
let stmts = [];
1668+
let expr = none;
1669+
let view_items = maybe_parse_view_import_only(p, first_item_attrs);
1670+
let initial_attrs = first_item_attrs;
1671+
1672+
if p.token == token::RBRACE && !vec::is_empty(initial_attrs) {
1673+
p.fatal("expected item");
1674+
}
1675+
16351676
while p.token != token::RBRACE {
16361677
alt p.token {
16371678
token::SEMI. {
16381679
p.bump(); // empty
16391680
}
16401681
_ {
1641-
let stmt = parse_stmt(p);
1682+
let stmt = parse_stmt(p, initial_attrs);
1683+
initial_attrs = [];
16421684
alt stmt.node {
16431685
ast::stmt_expr(e, stmt_id) { // Expression without semicolon:
16441686
alt p.token {
@@ -1751,7 +1793,8 @@ fn parse_item_fn(p: parser, purity: ast::purity,
17511793
let lo = p.last_span.lo;
17521794
let t = parse_fn_header(p);
17531795
let decl = parse_fn_decl(p, purity);
1754-
let body = parse_block(p);
1796+
let (inner_attrs, body) = parse_inner_attrs_and_block(p, true);
1797+
let attrs = attrs + inner_attrs;
17551798
ret mk_item(p, lo, body.span.hi, t.ident,
17561799
ast::item_fn(decl, t.tps, body), attrs);
17571800
}
@@ -1832,8 +1875,7 @@ fn parse_item_res(p: parser, attrs: [ast::attribute]) -> @ast::item {
18321875
fn parse_mod_items(p: parser, term: token::token,
18331876
first_item_attrs: [ast::attribute]) -> ast::_mod {
18341877
// Shouldn't be any view items since we've already parsed an item attr
1835-
let view_items =
1836-
if vec::len(first_item_attrs) == 0u { parse_view(p) } else { [] };
1878+
let view_items = maybe_parse_view(p, first_item_attrs);
18371879
let items: [@ast::item] = [];
18381880
let initial_attrs = first_item_attrs;
18391881
while p.token != term {
@@ -2134,14 +2176,20 @@ fn parse_item(p: parser, attrs: [ast::attribute]) -> option::t<@ast::item> {
21342176
// extensions, which both begin with token.POUND
21352177
type attr_or_ext = option::t<either::t<[ast::attribute], @ast::expr>>;
21362178

2137-
fn parse_outer_attrs_or_ext(p: parser) -> attr_or_ext {
2179+
fn parse_outer_attrs_or_ext(
2180+
p: parser,
2181+
first_item_attrs: [ast::attribute]) -> attr_or_ext {
2182+
let expect_item_next = vec::is_not_empty(first_item_attrs);
21382183
if p.token == token::POUND {
21392184
let lo = p.span.lo;
2140-
p.bump();
2141-
if p.token == token::LBRACKET {
2185+
if p.look_ahead(1u) == token::LBRACKET {
2186+
p.bump();
21422187
let first_attr = parse_attribute_naked(p, ast::attr_outer, lo);
21432188
ret some(left([first_attr] + parse_outer_attributes(p)));
2144-
} else if !(p.token == token::LT || p.token == token::LBRACKET) {
2189+
} else if !(p.look_ahead(1u) == token::LT
2190+
|| p.look_ahead(1u) == token::LBRACKET
2191+
|| expect_item_next) {
2192+
p.bump();
21452193
ret some(right(parse_syntax_ext_naked(p, lo)));
21462194
} else { ret none; }
21472195
} else { ret none; }
@@ -2182,6 +2230,10 @@ fn parse_inner_attrs_and_next(p: parser) ->
21822230
let inner_attrs: [ast::attribute] = [];
21832231
let next_outer_attrs: [ast::attribute] = [];
21842232
while p.token == token::POUND {
2233+
if p.look_ahead(1u) != token::LBRACKET {
2234+
// This is an extension
2235+
break;
2236+
}
21852237
let attr = parse_attribute(p, ast::attr_inner);
21862238
if p.token == token::SEMI {
21872239
p.bump();
@@ -2377,22 +2429,37 @@ fn is_view_item(p: parser) -> bool {
23772429
}
23782430
}
23792431

2380-
fn parse_view(p: parser) -> [@ast::view_item] {
2381-
parse_view_while(p, is_view_item)
2432+
fn maybe_parse_view(
2433+
p: parser,
2434+
first_item_attrs: [ast::attribute]) -> [@ast::view_item] {
2435+
2436+
maybe_parse_view_while(p, first_item_attrs, is_view_item)
23822437
}
23832438

2384-
fn parse_view_import_only(p: parser) -> [@ast::view_item] {
2385-
parse_view_while(p, bind is_word(_, "import"))
2439+
fn maybe_parse_view_import_only(
2440+
p: parser,
2441+
first_item_attrs: [ast::attribute]) -> [@ast::view_item] {
2442+
2443+
maybe_parse_view_while(p, first_item_attrs, bind is_word(_, "import"))
23862444
}
23872445

2388-
fn parse_view_while(p: parser, f: fn@(parser) -> bool) -> [@ast::view_item] {
2389-
let items = [];
2390-
while f(p) { items += [parse_view_item(p)]; }
2391-
ret items;
2446+
fn maybe_parse_view_while(
2447+
p: parser,
2448+
first_item_attrs: [ast::attribute],
2449+
f: fn@(parser) -> bool) -> [@ast::view_item] {
2450+
2451+
if vec::len(first_item_attrs) == 0u {
2452+
let items = [];
2453+
while f(p) { items += [parse_view_item(p)]; }
2454+
ret items;
2455+
} else {
2456+
// Shouldn't be any view items since we've already parsed an item attr
2457+
ret [];
2458+
}
23922459
}
23932460

23942461
fn parse_native_view(p: parser) -> [@ast::view_item] {
2395-
parse_view_while(p, is_view_item)
2462+
maybe_parse_view_while(p, [], is_view_item)
23962463
}
23972464

23982465
fn parse_crate_from_source_file(input: str, cfg: ast::crate_cfg,

src/comp/syntax/print/pprust.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ fn print_item(s: ps, &&item: @ast::item) {
366366
ast::item_fn(decl, typarams, body) {
367367
print_fn(s, decl, item.ident, typarams);
368368
word(s.s, " ");
369-
print_block(s, body);
369+
print_block_with_attrs(s, body, item.attrs);
370370
}
371371
ast::item_mod(_mod) {
372372
head(s, "mod");
@@ -551,10 +551,20 @@ fn print_block(s: ps, blk: ast::blk) {
551551
print_possibly_embedded_block(s, blk, block_normal, indent_unit);
552552
}
553553

554+
fn print_block_with_attrs(s: ps, blk: ast::blk, attrs: [ast::attribute]) {
555+
print_possibly_embedded_block_(s, blk, block_normal, indent_unit, attrs);
556+
}
557+
554558
tag embed_type { block_macro; block_block_fn; block_normal; }
555559

556560
fn print_possibly_embedded_block(s: ps, blk: ast::blk, embedded: embed_type,
557561
indented: uint) {
562+
print_possibly_embedded_block_(
563+
s, blk, embedded, indented, []);
564+
}
565+
566+
fn print_possibly_embedded_block_(s: ps, blk: ast::blk, embedded: embed_type,
567+
indented: uint, attrs: [ast::attribute]) {
558568
alt blk.node.rules {
559569
ast::unchecked_blk. { word(s.s, "unchecked"); }
560570
ast::unsafe_blk. { word(s.s, "unsafe"); }
@@ -570,6 +580,8 @@ fn print_possibly_embedded_block(s: ps, blk: ast::blk, embedded: embed_type,
570580
block_normal. { bopen(s); }
571581
}
572582

583+
print_inner_attributes(s, attrs);
584+
573585
for vi in blk.node.view_items { print_view_item(s, vi); }
574586
for st: @ast::stmt in blk.node.stmts {
575587
print_stmt(s, *st);
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
fn main() {
2+
#[attr]
3+
#debug("hi"); //! ERROR expected item
4+
}
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
fn main() {
2+
#[attr]
3+
let _i = 0; //! ERROR expected item
4+
}

src/test/pretty/attr-fn-inner.rs

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// pp-exact
2+
// Testing that both the inner item and next outer item are
3+
// preserved, and that the first outer item parsed in main is not
4+
// accidentally carried over to each inner function
5+
6+
fn main() {
7+
#[inner_attr];
8+
#[outer_attr]
9+
fn f() { }
10+
11+
#[outer_attr]
12+
fn g() { }
13+
}

src/test/run-pass/item-attributes.rs

+4
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,10 @@ mod test_literals {
183183
mod m { }
184184
}
185185

186+
fn test_fn_inner() {
187+
#[inner_fn_attr];
188+
}
189+
186190
fn main() { }
187191

188192
//

0 commit comments

Comments
 (0)