Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

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

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in 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