Skip to content

Commit 8be4c46

Browse files
Rollup merge of #154057 - aytey:fix-block-index-paren, r=fmease
Parenthesize block-like expressions in index base of pretty printer The AST pretty printer produces invalid Rust when a block expression is the base of an index operation inside a macro expansion. This is a gap in the parenthesization fix from #119105 — the `FixupContext` approach handles statement position but not the case where a block-index is nested inside another expression. The following is a correct program: ```rust macro_rules! block_arr { () => {{ [0u8; 4] }}; } macro_rules! as_slice { () => {{ &block_arr!()[..] }}; } fn main() { let _: &[u8] = as_slice!(); } ``` But `rustc -Zunpretty=expanded` produces output that is not valid Rust, because the closing brace of `{ [0u8; 4] }` creates a statement boundary, causing the parser to treat `[..]` as a separate expression: ```rust fn main() { let _: &[u8] = { &{ [0u8; 4] }[..] }; } ``` ``` error: expected one of `.`, `;`, `?`, `}`, or an operator, found `[` ``` Fixed output after this change: ```rust fn main() { let _: &[u8] = { &({ [0u8; 4] })[..] }; } ``` Since `{ ... }[...]` never parses as indexing a block regardless of context, the fix unconditionally parenthesizes "complete" expressions (block, match, if, loop, etc.) when they appear as the base of an index operation.
2 parents 3fb712c + 27e3d26 commit 8be4c46

3 files changed

Lines changed: 46 additions & 2 deletions

File tree

compiler/rustc_ast_pretty/src/pprust/state/expr.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,15 @@ impl<'a> State<'a> {
235235
// In order to call a named field, needs parens: `(self.fun)()`
236236
// But not for an unnamed field: `self.0()`
237237
ast::ExprKind::Field(_, name) => !name.is_numeric(),
238-
_ => func_fixup.precedence(func) < ExprPrecedence::Unambiguous,
238+
// Block-like expressions (block, match, if, loop, ...) never
239+
// parse as the callee of a call, regardless of context: the
240+
// closing brace ends the expression and `(args)` becomes a
241+
// separate tuple. Parenthesize them so the call survives a
242+
// pretty-print round trip.
243+
_ => {
244+
func_fixup.precedence(func) < ExprPrecedence::Unambiguous
245+
|| classify::expr_is_complete(func)
246+
}
239247
};
240248

241249
self.print_expr_cond_paren(func, needs_paren, func_fixup);
@@ -677,7 +685,8 @@ impl<'a> State<'a> {
677685
let expr_fixup = fixup.leftmost_subexpression_with_operator(true);
678686
self.print_expr_cond_paren(
679687
expr,
680-
expr_fixup.precedence(expr) < ExprPrecedence::Unambiguous,
688+
expr_fixup.precedence(expr) < ExprPrecedence::Unambiguous
689+
|| classify::expr_is_complete(expr),
681690
expr_fixup,
682691
);
683692
self.word("[");
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//@ pretty-mode:expanded
2+
//@ pp-exact:block-index-paren.pp
3+
4+
macro_rules! block_arr {
5+
() => {{ [0u8; 4] }};
6+
}
7+
8+
macro_rules! as_slice {
9+
() => {{ &block_arr!()[..] }};
10+
}
11+
12+
macro_rules! group {
13+
($e:expr) => { $e };
14+
}
15+
16+
fn scope() { &group!({ drop })(0); }
17+
18+
fn main() { let _: &[u8] = as_slice!(); }

tests/pretty/block-index-paren.pp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#![feature(prelude_import)]
2+
#![no_std]
3+
extern crate std;
4+
#[prelude_import]
5+
use ::std::prelude::rust_2015::*;
6+
//@ pretty-mode:expanded
7+
//@ pp-exact:block-index-paren.pp
8+
9+
macro_rules! block_arr { () => {{ [0u8; 4] }}; }
10+
11+
macro_rules! as_slice { () => {{ &block_arr!()[..] }}; }
12+
13+
macro_rules! group { ($e:expr) => { $e }; }
14+
15+
fn scope() { &({ drop })(0); }
16+
17+
fn main() { let _: &[u8] = { &({ [0u8; 4] })[..] }; }

0 commit comments

Comments
 (0)