Unnamed repository; edit this file 'description' to name the repository.
feat: allow attributes on all expressions
Attrs are syntactically valid on any expression, even if they are not
allowed semantically everywhere yet.
20 files changed, 303 insertions, 335 deletions
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index 759f2cc865..a34c18d6d0 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs @@ -650,8 +650,10 @@ impl ExprCollector<'_> { self.statements_in_scope.push(Statement::Let { pat, type_ref, initializer }); } ast::Stmt::ExprStmt(stmt) => { - if self.check_cfg(&stmt).is_none() { - return; + if let Some(expr) = stmt.expr() { + if self.check_cfg(&expr).is_none() { + return; + } } let has_semi = stmt.semicolon_token().is_some(); // Note that macro could be expended to multiple statements diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index d0b07f5931..3d0ad6735e 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs @@ -63,7 +63,7 @@ pub(crate) mod entry_points { pub(crate) use types::type_; pub(crate) fn expr(p: &mut Parser) { - let _ = expressions::expr_with_attrs(p); + let _ = expressions::expr(p); } pub(crate) fn stmt(p: &mut Parser) { diff --git a/crates/parser/src/grammar/attributes.rs b/crates/parser/src/grammar/attributes.rs index 80d7b09b3e..574629f31a 100644 --- a/crates/parser/src/grammar/attributes.rs +++ b/crates/parser/src/grammar/attributes.rs @@ -41,7 +41,7 @@ pub(super) fn meta(p: &mut Parser) { match p.current() { T![=] => { p.bump(T![=]); - if expressions::expr(p).0.is_none() { + if !expressions::expr(p) { p.error("expected expression"); } } diff --git a/crates/parser/src/grammar/expressions.rs b/crates/parser/src/grammar/expressions.rs index 30d3d4421a..645101e2f7 100644 --- a/crates/parser/src/grammar/expressions.rs +++ b/crates/parser/src/grammar/expressions.rs @@ -13,35 +13,19 @@ pub(super) enum StmtWithSemi { const EXPR_FIRST: TokenSet = LHS_FIRST; -pub(super) fn expr(p: &mut Parser) -> (Option<CompletedMarker>, BlockLike) { +pub(super) fn expr(p: &mut Parser) -> bool { let r = Restrictions { forbid_structs: false, prefer_stmt: false }; - expr_bp(p, r, 1) + expr_bp(p, None, r, 1).is_some() } -pub(super) fn expr_with_attrs(p: &mut Parser) -> bool { - let m = p.start(); - let has_attrs = p.at(T![#]); - attributes::outer_attrs(p); - - let (cm, _block_like) = expr(p); - let success = cm.is_some(); - - match (has_attrs, cm) { - (true, Some(cm)) => cm.extend_to(p, m), - _ => m.abandon(p), - } - - success -} - -pub(super) fn expr_stmt(p: &mut Parser) -> (Option<CompletedMarker>, BlockLike) { +pub(super) fn expr_stmt(p: &mut Parser, m: Option<Marker>) -> Option<(CompletedMarker, BlockLike)> { let r = Restrictions { forbid_structs: false, prefer_stmt: true }; - expr_bp(p, r, 1) + expr_bp(p, m, r, 1) } fn expr_no_struct(p: &mut Parser) { let r = Restrictions { forbid_structs: true, prefer_stmt: false }; - expr_bp(p, r, 1); + expr_bp(p, None, r, 1); } pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) { @@ -53,7 +37,6 @@ pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) { // #[C] #[D] {} // #[D] return (); // } - let has_attrs = p.at(T![#]); attributes::outer_attrs(p); if p.at(T![let]) { @@ -68,61 +51,39 @@ pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) { Err(m) => m, }; - let (cm, blocklike) = expr_stmt(p); - let kind = cm.as_ref().map(|cm| cm.kind()).unwrap_or(ERROR); - - if has_attrs { - if matches!(kind, BIN_EXPR | RANGE_EXPR) { - // test_err attr_on_expr_not_allowed + if let Some((cm, blocklike)) = expr_stmt(p, Some(m)) { + if !(p.at(T!['}']) || (prefer_expr && p.at(EOF))) { + // test no_semi_after_block // fn foo() { - // #[A] 1 + 2; - // #[B] if true {}; + // if true {} + // loop {} + // match () {} + // while true {} + // for _ in () {} + // {} + // {} + // macro_rules! test { + // () => {} + // } + // test!{} // } - p.error(format!("attributes are not allowed on {:?}", kind)); - } - } - - if p.at(T!['}']) || (prefer_expr && p.at(EOF)) { - // test attr_on_last_expr_in_block - // fn foo() { - // { #[A] bar!()? } - // #[B] &() - // } - match cm { - Some(cm) => cm.extend_to(p, m), - None => m.abandon(p), - } - } else { - // test no_semi_after_block - // fn foo() { - // if true {} - // loop {} - // match () {} - // while true {} - // for _ in () {} - // {} - // {} - // macro_rules! test { - // () => {} - // } - // test!{} - // } - - match with_semi { - StmtWithSemi::No => (), - StmtWithSemi::Optional => { - p.eat(T![;]); - } - StmtWithSemi::Yes => { - if blocklike.is_block() { + let m = cm.precede(p); + match with_semi { + StmtWithSemi::No => (), + StmtWithSemi::Optional => { p.eat(T![;]); - } else { - p.expect(T![;]); + } + StmtWithSemi::Yes => { + if blocklike.is_block() { + p.eat(T![;]); + } else { + p.expect(T![;]); + } } } - } - m.complete(p, EXPR_STMT); + m.complete(p, EXPR_STMT); + } } // test let_stmt @@ -138,7 +99,7 @@ pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) { if p.eat(T![=]) { // test let_stmt_init // fn f() { let x = 92; } - expressions::expr_with_attrs(p); + expressions::expr(p); } match with_semi { @@ -234,20 +195,34 @@ fn current_op(p: &Parser) -> (u8, SyntaxKind) { } // Parses expression with binding power of at least bp. -fn expr_bp(p: &mut Parser, mut r: Restrictions, bp: u8) -> (Option<CompletedMarker>, BlockLike) { +fn expr_bp( + p: &mut Parser, + m: Option<Marker>, + mut r: Restrictions, + bp: u8, +) -> Option<(CompletedMarker, BlockLike)> { + let m = m.unwrap_or_else(|| { + let m = p.start(); + attributes::outer_attrs(p); + m + }); let mut lhs = match lhs(p, r) { Some((lhs, blocklike)) => { + let lhs = lhs.extend_to(p, m); if r.prefer_stmt && blocklike.is_block() { // test stmt_bin_expr_ambiguity // fn f() { // let _ = {1} & 2; // {1} &2; // } - return (Some(lhs), BlockLike::Block); + return Some((lhs, BlockLike::Block)); } lhs } - None => return (None, BlockLike::NotBlock), + None => { + m.abandon(p); + return None; + } }; loop { @@ -285,10 +260,10 @@ fn expr_bp(p: &mut Parser, mut r: Restrictions, bp: u8) -> (Option<CompletedMark } } - expr_bp(p, Restrictions { prefer_stmt: false, ..r }, op_bp + 1); + expr_bp(p, None, Restrictions { prefer_stmt: false, ..r }, op_bp + 1); lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR }); } - (Some(lhs), BlockLike::NotBlock) + Some((lhs, BlockLike::NotBlock)) } const LHS_FIRST: TokenSet = @@ -341,9 +316,10 @@ fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> m = p.start(); p.bump(op); if p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{'])) { - expr_bp(p, r, 2); + expr_bp(p, None, r, 2); } - return Some((m.complete(p, RANGE_EXPR), BlockLike::NotBlock)); + let cm = m.complete(p, RANGE_EXPR); + return Some((cm, BlockLike::NotBlock)); } } @@ -353,12 +329,15 @@ fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> // {p}.x = 10; // } let (lhs, blocklike) = atom::atom_expr(p, r)?; - return Some(postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block()))); + let (cm, block_like) = + postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block())); + return Some((cm, block_like)); } }; // parse the interior of the unary expression - expr_bp(p, r, 255); - Some((m.complete(p, kind), BlockLike::NotBlock)) + expr_bp(p, None, r, 255); + let cm = m.complete(p, kind); + Some((cm, BlockLike::NotBlock)) } fn postfix_expr( @@ -536,7 +515,7 @@ fn arg_list(p: &mut Parser) { // fn main() { // foo(#[attr] 92) // } - if !expr_with_attrs(p) { + if !expr(p) { break; } if !p.at(T![')']) && !p.expect(T![,]) { diff --git a/crates/parser/src/grammar/expressions/atom.rs b/crates/parser/src/grammar/expressions/atom.rs index f0048aa301..f6e9a5f1b3 100644 --- a/crates/parser/src/grammar/expressions/atom.rs +++ b/crates/parser/src/grammar/expressions/atom.rs @@ -176,7 +176,7 @@ fn tuple_expr(p: &mut Parser) -> CompletedMarker { // test tuple_attrs // const A: (i64, i64) = (1, #[cfg(test)] 2); - if !expr_with_attrs(p) { + if !expr(p) { break; } @@ -209,7 +209,7 @@ fn array_expr(p: &mut Parser) -> CompletedMarker { // test array_attrs // const A: &[i64] = &[1, #[cfg(test)] 2]; - if !expr_with_attrs(p) { + if !expr(p) { break; } @@ -438,7 +438,10 @@ fn match_arm(p: &mut Parser) { match_guard(p); } p.expect(T![=>]); - let blocklike = expr_stmt(p).1; + let blocklike = match expr_stmt(p, None) { + Some((_, blocklike)) => blocklike, + None => BlockLike::NotBlock, + }; // test match_arms_commas // fn foo() { @@ -619,14 +622,14 @@ fn meta_var_expr(p: &mut Parser) -> CompletedMarker { assert!(p.at(L_DOLLAR)); let m = p.start(); p.bump(L_DOLLAR); - let (completed, _is_block) = - expr_bp(p, Restrictions { forbid_structs: false, prefer_stmt: false }, 1); + let expr = expr_bp(p, None, Restrictions { forbid_structs: false, prefer_stmt: false }, 1); - match (completed, p.current()) { - (Some(it), R_DOLLAR) => { + match (expr, p.current()) { + (Some((cm, _)), R_DOLLAR) => { p.bump(R_DOLLAR); + // FIXME: this leaves the dollar hanging in the air... m.abandon(p); - it + cm } _ => { while !p.at(R_DOLLAR) { diff --git a/crates/parser/src/parser.rs b/crates/parser/src/parser.rs index ff2af130be..1f9961bb92 100644 --- a/crates/parser/src/parser.rs +++ b/crates/parser/src/parser.rs @@ -339,7 +339,7 @@ impl CompletedMarker { } /// Extends this completed marker *to the left* up to `m`. - pub(crate) fn extend_to(self, p: &mut Parser, mut m: Marker) { + pub(crate) fn extend_to(self, p: &mut Parser, mut m: Marker) -> CompletedMarker { m.bomb.defuse(); let idx = m.pos as usize; match &mut p.events[idx] { @@ -348,6 +348,7 @@ impl CompletedMarker { } _ => unreachable!(), } + self } pub(crate) fn kind(&self) -> SyntaxKind { diff --git a/crates/syntax/test_data/parser/err/0009_broken_struct_type_parameter.rast b/crates/syntax/test_data/parser/err/0009_broken_struct_type_parameter.rast index dacf71aa16..2d4c689c7c 100644 --- a/crates/syntax/test_data/parser/err/0009_broken_struct_type_parameter.rast +++ b/crates/syntax/test_data/parser/err/0009_broken_struct_type_parameter.rast @@ -26,9 +26,8 @@ [email protected] - [email protected] ":" + [email protected] ":" @@ -55,4 +54,3 @@ error 15..15: expected an item error 17..17: expected an item error 24..24: expected SEMICOLON error 24..24: expected expression -error 25..25: expected SEMICOLON diff --git a/crates/syntax/test_data/parser/err/0022_bad_exprs.rast b/crates/syntax/test_data/parser/err/0022_bad_exprs.rast index 71fb19783a..7e6d82bfb4 100644 --- a/crates/syntax/test_data/parser/err/0022_bad_exprs.rast +++ b/crates/syntax/test_data/parser/err/0022_bad_exprs.rast @@ -24,9 +24,8 @@ [email protected] - [email protected] "," + [email protected] "," [email protected] "struct" @@ -71,15 +70,13 @@ [email protected] - [email protected] "," + [email protected] "," [email protected] "impl" - [email protected] "," + [email protected] "," [email protected] "let" @@ -122,16 +119,13 @@ [email protected] - [email protected] "," + [email protected] "," - [email protected] "]" - [email protected] "," + [email protected] "]" + [email protected] "," [email protected] "trait" @@ -149,7 +143,6 @@ error 16..16: expected expression error 17..17: expected R_BRACK error 17..17: expected SEMICOLON error 17..17: expected expression -error 18..18: expected SEMICOLON error 25..25: expected a name error 26..26: expected `;`, `{`, or `(` error 30..30: expected pattern @@ -157,22 +150,17 @@ error 31..31: expected SEMICOLON error 53..53: expected expression error 54..54: expected SEMICOLON error 54..54: expected expression -error 55..55: expected SEMICOLON error 60..60: expected type error 60..60: expected `{` error 60..60: expected expression -error 61..61: expected SEMICOLON error 65..65: expected pattern error 65..65: expected SEMICOLON error 65..65: expected expression error 92..92: expected expression error 93..93: expected SEMICOLON error 93..93: expected expression -error 94..94: expected SEMICOLON error 95..95: expected expression -error 96..96: expected SEMICOLON error 96..96: expected expression -error 97..97: expected SEMICOLON error 103..103: expected a name error 104..104: expected `{` error 108..108: expected pattern diff --git a/crates/syntax/test_data/parser/err/0024_many_type_parens.rast b/crates/syntax/test_data/parser/err/0024_many_type_parens.rast index be4a62940b..d29f12c1e5 100644 --- a/crates/syntax/test_data/parser/err/0024_many_type_parens.rast +++ b/crates/syntax/test_data/parser/err/0024_many_type_parens.rast @@ -143,10 +143,9 @@ [email protected] [email protected] "'a" - [email protected] ">" - [email protected] ";" + [email protected] ">" + [email protected] ";" [email protected] "\n " [email protected] "let" @@ -173,13 +172,11 @@ [email protected] [email protected] "Sized" - [email protected] ")" + [email protected] ")" - [email protected] "+" + [email protected] "+" @@ -288,10 +285,9 @@ [email protected] [email protected] "Sized" - [email protected] ">" - [email protected] ";" + [email protected] ">" + [email protected] ";" [email protected] "\n" [email protected] "\n" @@ -306,9 +302,7 @@ error 141..141: expected R_ANGLE error 141..141: expected SEMICOLON error 146..146: expected SEMICOLON error 146..146: expected expression -error 147..147: expected SEMICOLON error 148..148: expected expression -error 149..149: expected SEMICOLON error 155..155: expected type error 158..158: expected IN_KW error 165..165: expected expression diff --git a/crates/syntax/test_data/parser/err/0043_weird_blocks.rast b/crates/syntax/test_data/parser/err/0043_weird_blocks.rast index e24f01e292..797a089648 100644 --- a/crates/syntax/test_data/parser/err/0043_weird_blocks.rast +++ b/crates/syntax/test_data/parser/err/0043_weird_blocks.rast @@ -51,12 +51,11 @@ [email protected] - [email protected] "'label" - [email protected] ":" + [email protected] "'label" + [email protected] ":" [email protected] "92" @@ -69,4 +68,3 @@ error 24..24: expected existential, fn, trait or impl error 41..41: expected existential, fn, trait or impl error 56..56: expected a block error 75..75: expected a loop -error 75..75: expected SEMICOLON diff --git a/crates/syntax/test_data/parser/inline/err/0002_misplaced_label_err.rast b/crates/syntax/test_data/parser/inline/err/0002_misplaced_label_err.rast index 97bb5059d7..3774dd0733 100644 --- a/crates/syntax/test_data/parser/inline/err/0002_misplaced_label_err.rast +++ b/crates/syntax/test_data/parser/inline/err/0002_misplaced_label_err.rast @@ -11,12 +11,11 @@ [email protected] [email protected] "\n " - [email protected] "'loop" - [email protected] ":" + [email protected] "'loop" + [email protected] ":" [email protected] "impl" @@ -24,6 +23,5 @@ [email protected] [email protected] "\n" error 22..22: expected a loop -error 22..22: expected SEMICOLON error 27..27: expected type error 27..27: expected `{` diff --git a/crates/syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rast b/crates/syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rast deleted file mode 100644 index 7b8b7284f9..0000000000 --- a/crates/syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rast +++ /dev/null @@ -1,60 +0,0 @@ - [email protected] "fn" - [email protected] " " - [email protected] "foo" - [email protected] "(" - [email protected] ")" - [email protected] " " - [email protected] "{" - [email protected] "\n " - [email protected] "#" - [email protected] "[" - [email protected] "A" - [email protected] "]" - [email protected] " " - [email protected] "1" - [email protected] " " - [email protected] "+" - [email protected] " " - [email protected] "2" - [email protected] ";" - [email protected] "\n " - [email protected] "#" - [email protected] "[" - [email protected] "B" - [email protected] "]" - [email protected] " " - [email protected] "if" - [email protected] " " - [email protected] "true" - [email protected] " " - [email protected] "{" - [email protected] "}" - [email protected] ";" - [email protected] "\n" - [email protected] "}" - [email protected] "\n" -error 24..24: attributes are not allowed on BIN_EXPR diff --git a/crates/syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rs b/crates/syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rs deleted file mode 100644 index d725a07ce9..0000000000 --- a/crates/syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn foo() { - #[A] 1 + 2; - #[B] if true {}; -} diff --git a/crates/syntax/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast b/crates/syntax/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast index 178204fece..2a4a52eeb5 100644 --- a/crates/syntax/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast +++ b/crates/syntax/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast @@ -12,17 +12,17 @@ [email protected] [email protected] "\n " - [email protected] "#" - [email protected] "[" - [email protected] "A" - [email protected] "]" - [email protected] " " + [email protected] "#" + [email protected] "[" + [email protected] "A" + [email protected] "]" + [email protected] " " @@ -34,17 +34,17 @@ [email protected] [email protected] "\n " - [email protected] "#" - [email protected] "[" - [email protected] "B" - [email protected] "]" - [email protected] " " + [email protected] "#" + [email protected] "[" + [email protected] "B" + [email protected] "]" + [email protected] " " @@ -55,42 +55,42 @@ [email protected] [email protected] "\n " - [email protected] "#" - [email protected] "[" - [email protected] "C" - [email protected] "]" - [email protected] " " - [email protected] "#" - [email protected] "[" - [email protected] "D" - [email protected] "]" - [email protected] " " + [email protected] "#" + [email protected] "[" + [email protected] "C" + [email protected] "]" + [email protected] " " + [email protected] "#" + [email protected] "[" + [email protected] "D" + [email protected] "]" + [email protected] " " [email protected] "\n " - [email protected] "#" - [email protected] "[" - [email protected] "D" - [email protected] "]" - [email protected] " " + [email protected] "#" + [email protected] "[" + [email protected] "D" + [email protected] "]" + [email protected] " " [email protected] "return" diff --git a/crates/syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.rast b/crates/syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.rast deleted file mode 100644 index 9daac234ac..0000000000 --- a/crates/syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.rast +++ /dev/null @@ -1,59 +0,0 @@ - [email protected] "fn" - [email protected] " " - [email protected] "foo" - [email protected] "(" - [email protected] ")" - [email protected] " " - [email protected] "{" - [email protected] "\n " - [email protected] "{" - [email protected] " " - [email protected] "#" - [email protected] "[" - [email protected] "A" - [email protected] "]" - [email protected] " " - [email protected] "bar" - [email protected] "!" - [email protected] "(" - [email protected] ")" - [email protected] "?" - [email protected] " " - [email protected] "}" - [email protected] "\n " - [email protected] "#" - [email protected] "[" - [email protected] "B" - [email protected] "]" - [email protected] " " - [email protected] "&" - [email protected] "(" - [email protected] ")" - [email protected] "\n" - [email protected] "}" - [email protected] "\n" diff --git a/crates/syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.rs b/crates/syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.rs deleted file mode 100644 index 9c5c8eb361..0000000000 --- a/crates/syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn foo() { - { #[A] bar!()? } - #[B] &() -} diff --git a/crates/syntax/test_data/parser/ok/0070_expr_attr_placement.rast b/crates/syntax/test_data/parser/ok/0070_expr_attr_placement.rast new file mode 100644 index 0000000000..925fa4cbf6 --- /dev/null +++ b/crates/syntax/test_data/parser/ok/0070_expr_attr_placement.rast @@ -0,0 +1,58 @@ + [email protected] "fn" + [email protected] " " + [email protected] "f" + [email protected] "(" + [email protected] ")" + [email protected] " " + [email protected] "{" + [email protected] "\n " + [email protected] "(" + [email protected] "#" + [email protected] "[" + [email protected] "a" + [email protected] "]" + [email protected] " " + [email protected] "lhs" + [email protected] "?" + [email protected] " " + [email protected] "+" + [email protected] " " + [email protected] "#" + [email protected] "[" + [email protected] "b" + [email protected] "]" + [email protected] " " + [email protected] "rhs" + [email protected] "." + [email protected] "await" + [email protected] ")" + [email protected] "\n" + [email protected] "}" + [email protected] "\n" diff --git a/crates/syntax/test_data/parser/ok/0070_expr_attr_placement.rs b/crates/syntax/test_data/parser/ok/0070_expr_attr_placement.rs new file mode 100644 index 0000000000..d8b7a3832a --- /dev/null +++ b/crates/syntax/test_data/parser/ok/0070_expr_attr_placement.rs @@ -0,0 +1,3 @@ +fn f() { + (#[a] lhs? + #[b] rhs.await) +} diff --git a/crates/syntax/test_data/parser/ok/0071_stmt_attr_placement.rast b/crates/syntax/test_data/parser/ok/0071_stmt_attr_placement.rast new file mode 100644 index 0000000000..3a00212e80 --- /dev/null +++ b/crates/syntax/test_data/parser/ok/0071_stmt_attr_placement.rast @@ -0,0 +1,69 @@ + [email protected] "fn" + [email protected] " " + [email protected] "foo" + [email protected] "(" + [email protected] ")" + [email protected] " " + [email protected] "{" + [email protected] "\n " + [email protected] "#" + [email protected] "[" + [email protected] "A" + [email protected] "]" + [email protected] " " + [email protected] "{" + [email protected] " " + [email protected] "#" + [email protected] "[" + [email protected] "B" + [email protected] "]" + [email protected] " " + [email protected] "bar" + [email protected] "!" + [email protected] "(" + [email protected] ")" + [email protected] "?" + [email protected] " " + [email protected] "}" + [email protected] "\n " + [email protected] "#" + [email protected] "[" + [email protected] "C" + [email protected] "]" + [email protected] " " + [email protected] "&" + [email protected] "(" + [email protected] ")" + [email protected] "\n" + [email protected] "}" + [email protected] "\n" diff --git a/crates/syntax/test_data/parser/ok/0071_stmt_attr_placement.rs b/crates/syntax/test_data/parser/ok/0071_stmt_attr_placement.rs new file mode 100644 index 0000000000..b4d5204bc0 --- /dev/null +++ b/crates/syntax/test_data/parser/ok/0071_stmt_attr_placement.rs @@ -0,0 +1,4 @@ +fn foo() { + #[A] { #[B] bar!()? } + #[C] &() +} |