Skip to content

Rustc pretty printer generates syntactically invalid output for some binary operators #98790

Closed
@dtolnay

Description

@dtolnay
// repro.rs

macro_rules! repro {
    () => {
        match () {
            () => true,
        }
    };
}

pub fn repro() -> bool {
    repro!() | true
}
$ rustc --edition=2021 -Zunpretty=expanded lib.rs 
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
macro_rules! repro { () => { match() { () => true, } } ; }

pub fn repro() -> bool { match () { () => true, } | true }

Another manifestation of the exact same pretty printer bug (in case this one is easier to incorporate into the test suite):

macro_rules! stringify_item {
    ($item:item) => {
        stringify!($item)
    };
}

macro_rules! repro {
    ($expr:expr) => {
        stringify_item! {
            pub fn repro() -> bool {
                $expr
            }
        }
    };
}

fn main() {
    println!("{}", repro!(match () { () => true } | true));
}
$ cargo run
pub fn repro() -> bool { match () { () => true, } | true }

The repro function in each of these outputs is syntactically invalid code, which is not what -Zunpretty=expanded or stringify! should be creating.

error: expected one of `...`, `..=`, `..`, `:`, or `|`, found `}`
 --> src/lib.rs:1:58
  |
1 | pub fn repro() -> bool { match () { () => true, } | true }
  |                                                          ^ expected one of `...`, `..=`, `..`, `:`, or `|`
  |
help: parentheses are required to parse this as an expression
  |
1 | pub fn repro() -> bool { (match () { () => true, }) | true }
  |                          +                        +

error[E0308]: mismatched types
 --> src/lib.rs:1:26
  |
1 | pub fn repro() -> bool { match () { () => true, } | true }
  |                          ^^^^^^^^^^^^^^^^^^^^^^^^- help: consider using a semicolon here
  |                          |
  |                          expected `()`, found `bool`

The correct output in both cases would be either of the following syntactically valid outputs:

pub fn repro() -> bool { (match () { () => true, }) | true }
pub fn repro() -> bool { (match () { () => true, } | true) }

The rustc pretty printer already does parenthesis insertion in similar scenarios so it is a bug that it is not doing it here. For example:

// lib.rs

struct Struct {}

macro_rules! repro {
    () => {
        Struct {}
    };
}

pub fn repro() -> bool {
    match repro!() {
        _ => {}
    }
}
$ rustc --edition=2021 -Zunpretty=expanded src/lib.rs 
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
struct Struct {}

macro_rules! repro { () => { Struct {} } ; }

pub fn repro() -> bool { match (Struct {}) { _ => {} } }

Notice that the pretty printer put parens around Struct {} because match Struct {} { _ => {} } would not have been valid syntax.

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions