From 574d8774b9e34c7d9fb07e81caaa67ccc382a0a0 Mon Sep 17 00:00:00 2001 From: "Andrew V. Teylu" Date: Wed, 18 Mar 2026 20:23:30 +0000 Subject: [PATCH 1/3] Parenthesize block-like expressions in index base of pretty printer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 existing `FixupContext` parenthesization machinery — the 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. --- compiler/rustc_ast_pretty/src/pprust/state/expr.rs | 3 ++- tests/pretty/block-index-paren.pp | 13 +++++++++++++ tests/pretty/block-index-paren.rs | 12 ++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 tests/pretty/block-index-paren.pp create mode 100644 tests/pretty/block-index-paren.rs diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index ad602d5196dc..f0f8dfa0a67e 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -677,7 +677,8 @@ pub(super) fn print_expr_outer_attr_style( let expr_fixup = fixup.leftmost_subexpression_with_operator(true); self.print_expr_cond_paren( expr, - expr_fixup.precedence(expr) < ExprPrecedence::Unambiguous, + expr_fixup.precedence(expr) < ExprPrecedence::Unambiguous + || classify::expr_is_complete(expr), expr_fixup, ); self.word("["); diff --git a/tests/pretty/block-index-paren.pp b/tests/pretty/block-index-paren.pp new file mode 100644 index 000000000000..65c61bd68e14 --- /dev/null +++ b/tests/pretty/block-index-paren.pp @@ -0,0 +1,13 @@ +#![feature(prelude_import)] +#![no_std] +extern crate std; +#[prelude_import] +use ::std::prelude::rust_2015::*; +//@ pretty-mode:expanded +//@ pp-exact:block-index-paren.pp + +macro_rules! block_arr { () => {{ [0u8; 4] }}; } + +macro_rules! as_slice { () => {{ &block_arr!()[..] }}; } + +fn main() { let _: &[u8] = { &({ [0u8; 4] })[..] }; } diff --git a/tests/pretty/block-index-paren.rs b/tests/pretty/block-index-paren.rs new file mode 100644 index 000000000000..7ec05059fc1d --- /dev/null +++ b/tests/pretty/block-index-paren.rs @@ -0,0 +1,12 @@ +//@ pretty-mode:expanded +//@ pp-exact:block-index-paren.pp + +macro_rules! block_arr { + () => {{ [0u8; 4] }}; +} + +macro_rules! as_slice { + () => {{ &block_arr!()[..] }}; +} + +fn main() { let _: &[u8] = as_slice!(); } From 56f43b5142ff41a450e85ff241778fe45eb988e2 Mon Sep 17 00:00:00 2001 From: "Andrew V. Teylu" Date: Wed, 8 Apr 2026 14:52:01 +0100 Subject: [PATCH 2/3] Parenthesize block-like expressions in call callee of pretty printer When a macro expands to a call whose callee is a block (or other "complete" expression like `match`, `if`, `loop`), the AST pretty printer emits the callee without parentheses. In statement position the closing brace ends the expression and the argument list is parsed as a separate tuple expression, producing a parse error. --- compiler/rustc_ast_pretty/src/pprust/state/expr.rs | 10 +++++++++- tests/pretty/block-index-paren.pp | 4 ++++ tests/pretty/block-index-paren.rs | 6 ++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index f0f8dfa0a67e..701152e9f952 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -235,7 +235,15 @@ fn print_expr_call(&mut self, func: &ast::Expr, args: &[Box], fixup: // In order to call a named field, needs parens: `(self.fun)()` // But not for an unnamed field: `self.0()` ast::ExprKind::Field(_, name) => !name.is_numeric(), - _ => func_fixup.precedence(func) < ExprPrecedence::Unambiguous, + // Block-like expressions (block, match, if, loop, ...) never + // parse as the callee of a call, regardless of context: the + // closing brace ends the expression and `(args)` becomes a + // separate tuple. Parenthesize them so the call survives a + // pretty-print round trip. + _ => { + func_fixup.precedence(func) < ExprPrecedence::Unambiguous + || classify::expr_is_complete(func) + } }; self.print_expr_cond_paren(func, needs_paren, func_fixup); diff --git a/tests/pretty/block-index-paren.pp b/tests/pretty/block-index-paren.pp index 65c61bd68e14..e5ad92be082f 100644 --- a/tests/pretty/block-index-paren.pp +++ b/tests/pretty/block-index-paren.pp @@ -10,4 +10,8 @@ macro_rules! block_arr { () => {{ [0u8; 4] }}; } macro_rules! as_slice { () => {{ &block_arr!()[..] }}; } +macro_rules! group { ($e:expr) => { $e }; } + +fn scope() { &({ drop })(0); } + fn main() { let _: &[u8] = { &({ [0u8; 4] })[..] }; } diff --git a/tests/pretty/block-index-paren.rs b/tests/pretty/block-index-paren.rs index 7ec05059fc1d..71e1cdff7b79 100644 --- a/tests/pretty/block-index-paren.rs +++ b/tests/pretty/block-index-paren.rs @@ -9,4 +9,10 @@ macro_rules! as_slice { () => {{ &block_arr!()[..] }}; } +macro_rules! group { + ($e:expr) => { $e }; +} + +fn scope() { &group!({ drop })(0); } + fn main() { let _: &[u8] = as_slice!(); } From 27e3d26dfb6c81ed25c39ce55c1440950e0920c2 Mon Sep 17 00:00:00 2001 From: "Andrew V. Teylu" Date: Wed, 8 Apr 2026 15:01:38 +0100 Subject: [PATCH 3/3] rename test --- .../pretty/{block-index-paren.rs => block-index-or-call-paren.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/pretty/{block-index-paren.rs => block-index-or-call-paren.rs} (100%) diff --git a/tests/pretty/block-index-paren.rs b/tests/pretty/block-index-or-call-paren.rs similarity index 100% rename from tests/pretty/block-index-paren.rs rename to tests/pretty/block-index-or-call-paren.rs