Skip to content

Parenthesize block-like expressions in index base of pretty printer#154057

Merged
rust-bors[bot] merged 3 commits intorust-lang:mainfrom
aytey:fix-block-index-paren
Apr 9, 2026
Merged

Parenthesize block-like expressions in index base of pretty printer#154057
rust-bors[bot] merged 3 commits intorust-lang:mainfrom
aytey:fix-block-index-paren

Conversation

@aytey
Copy link
Copy Markdown
Contributor

@aytey aytey commented Mar 18, 2026

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:

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:

fn main() { let _: &[u8] = { &{ [0u8; 4] }[..] }; }
error: expected one of `.`, `;`, `?`, `}`, or an operator, found `[`

Fixed output after this change:

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.

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Mar 18, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Mar 18, 2026

r? @BoxyUwU

rustbot has assigned @BoxyUwU.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler
  • compiler expanded to 69 candidates
  • Random selection from 16 candidates

@rustbot

This comment has been minimized.

@aytey aytey force-pushed the fix-block-index-paren branch from ea61981 to 3a4869b Compare March 18, 2026 20:27
@BoxyUwU
Copy link
Copy Markdown
Member

BoxyUwU commented Mar 23, 2026

r? compiler

@rustbot rustbot assigned jackh726 and unassigned BoxyUwU Mar 23, 2026
@fmease
Copy link
Copy Markdown
Member

fmease commented Apr 8, 2026

r? fmease

@rustbot rustbot assigned fmease and unassigned jackh726 Apr 8, 2026
Copy link
Copy Markdown
Member

@fmease fmease left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! One minor request

View changes since this review

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also fix Call exprs? They exhibit the same behavior. E.g.,

macro_rules! group { ($e:expr) => { $e } }
fn scope() { &group!({ drop })(0); }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fmease all done: 56f43b5

@fmease fmease added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Apr 8, 2026
aytey added 2 commits April 8, 2026 13:06
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.
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.
@aytey aytey force-pushed the fix-block-index-paren branch from 3a4869b to 56f43b5 Compare April 8, 2026 13:52
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Apr 8, 2026

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

Copy link
Copy Markdown
Member

@fmease fmease Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

View changes since the review

tests/pretty/block-index-paren.rstests/pretty/block-index-or-call-paren.rs or sth. like that?

Then I'll put it into the queue.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done: 27e3d26

@fmease
Copy link
Copy Markdown
Member

fmease commented Apr 8, 2026

Thanks! @bors r+ rollup

@rust-bors
Copy link
Copy Markdown
Contributor

rust-bors bot commented Apr 8, 2026

📌 Commit 27e3d26 has been approved by fmease

It is now in the queue for this repository.

@rust-bors rust-bors bot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Apr 8, 2026
rust-bors bot pushed a commit that referenced this pull request Apr 8, 2026
…uwer

Rollup of 6 pull requests

Successful merges:

 - #154912 (Remove `BuiltinLintDiag`)
 - #154598 (test `#[naked]` with `#[link_section = "..."]` on windows)
 - #154719 (Hexagon inline asm: add reg_pair, vreg, vreg_pair, and qreg register classes)
 - #154057 (Parenthesize block-like expressions in index base of pretty printer)
 - #154893 (make `expected_literal` positive)
 - #155002 (Clarify that `core::range` ranges do not have special syntax)
@rust-bors rust-bors bot merged commit 8be4c46 into rust-lang:main Apr 9, 2026
11 checks passed
@rustbot rustbot added this to the 1.96.0 milestone Apr 9, 2026
rust-timer added a commit that referenced this pull request Apr 9, 2026
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants