Skip to content

pretty printer fails to include necessary parens around some block expressions #22450

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
pnkfelix opened this issue Feb 17, 2015 · 7 comments
Closed
Labels
A-pretty Area: Pretty printing (including `-Z unpretty`) C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@pnkfelix
Copy link
Member

The pretty printer fails to include necessary parens around some block expressions

In particular, consider this code (stored in /tmp/demo5.rs):

#![allow(unused_parens)]

macro_rules! add1_block {
    ($e:expr) => {
        { let val = 1; $e + val }
    }
}

macro_rules! add1_paren_block {
    ($e:expr) => {
        ({ let val = 1; $e + val })
    }
}

fn main() {
    let w = add1_block!(2);
    let x = { add1_block!(3) as u64 };
    let y = add1_paren_block!(4);
    let z = { add1_paren_block!(5) as u64 };

    println!("w: {} x: {} y: {} z: {}", w, x, y, z);
}

The above code compiles and runs, and you can even run it through the non-expanding pretty printer and compile that and run it:

% ./x86_64-apple-darwin/stage1/bin/rustc  /tmp/demo5.rs && ./demo5
w: 3 x: 4 y: 5 z: 6
% rustc -Z unstable-options --pretty=normal /tmp/demo5.rs -o /tmp/demo5_normal.rs && rustc /tmp/demo5_normal.rs && ./demo5_normal 
w: 3 x: 4 y: 5 z: 6
%  

However, if you apply --pretty=expanded, then the generated source fails to compile:

% rustc -Z unstable-options --pretty=expanded /tmp/demo5.rs -o /tmp/demo5_expanded.rs && rustc /tmp/demo5_expanded.rs && ./demo5_expanded
/tmp/demo5_expanded.rs:12:40: 12:42 error: expected identifier, found keyword `as`
/tmp/demo5_expanded.rs:12     let x = { { let val = 1; 3 + val } as u64 };
                                                                 ^~
/tmp/demo5_expanded.rs:12:43: 12:46 error: expected one of `!`, `.`, `::`, `;`, `{`, `}`, or an operator, found `u64`
/tmp/demo5_expanded.rs:12     let x = { { let val = 1; 3 + val } as u64 };
                                                                    ^~~
% 

The reason for this is that the use of add1_block within a cast as the last expression of a block is interpreted as a statement, rather than part of an expression. So you need to wrap it in parentheses (the way that add1_paren_block does) if you want the generated output source to be robust enough to be recompiled.

@pnkfelix
Copy link
Member Author

(If you are wondering why it is so important to be able to recompile the source generated by --pretty=expanded, the easy answer is: It is what we do in our own pretty test suite (where we make sure that the output parses and typechecks, but do not run it through trans.)

@pnkfelix
Copy link
Member Author

(oh, and in case its not clear: the workaround presented by add1_paren_block above is actually not a satisfactory workaround at all, because of #22451.)

@steveklabnik steveklabnik added the A-pretty Area: Pretty printing (including `-Z unpretty`) label Feb 17, 2015
@pnkfelix
Copy link
Member Author

see also #20937

@steveklabnik
Copy link
Member

Triage: no change

@Mark-Simulacrum
Copy link
Member

Note: the specific issue here is related to #17930, since that suggests that } as u64 should be allowed.

@Mark-Simulacrum Mark-Simulacrum added the C-bug Category: This is a bug. label Jul 22, 2017
@steveklabnik
Copy link
Member

Triage: no change

@jonas-schievink jonas-schievink added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Apr 18, 2020
@dtolnay
Copy link
Member

dtolnay commented Dec 28, 2023

Fixed by #119105. Output of rustc --edition=2021 -Zunpretty=expanded main.rs:

Before: invalid syntax.

#![feature(prelude_import)]
#![allow(unused_parens)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;

macro_rules! add1_block { ($e:expr) => { { let val = 1; $e + val } } }

macro_rules! add1_paren_block { ($e:expr) => { ({ let val = 1; $e + val }) } }

fn main() {
    let w = { let val = 1; 2 + val };
    let x = { { let val = 1; 3 + val } as u64 };
    let y = ({ let val = 1; 4 + val });
    let z = { ({ let val = 1; 5 + val }) as u64 };

    {
        ::std::io::_print(format_args!("w: {0} x: {1} y: {2} z: {3}\n", w, x,
                y, z));
    };
}
error: expected expression, found `as`
   |
14 |     let x = { { let val = 1; 3 + val } as u64 };
   |                                        ^^ expected expression
   |
help: parentheses are required to parse this as an expression
   |
14 |     let x = { ({ let val = 1; 3 + val }) as u64 };
   |               +                        +

After: valid.

#![feature(prelude_import)]
#![allow(unused_parens)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;

macro_rules! add1_block { ($e:expr) => { { let val = 1; $e + val } } }

macro_rules! add1_paren_block { ($e:expr) => { ({ let val = 1; $e + val }) } }

fn main() {
    let w = { let val = 1; 2 + val };
    let x = { ({ let val = 1; 3 + val }) as u64 };
    let y = ({ let val = 1; 4 + val });
    let z = { ({ let val = 1; 5 + val }) as u64 };

    {
        ::std::io::_print(format_args!("w: {0} x: {1} y: {2} z: {3}\n", w, x,
                y, z));
    };
}

@dtolnay dtolnay closed this as completed Dec 28, 2023
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
A-pretty Area: Pretty printing (including `-Z unpretty`) C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

5 participants