rust-lang/rustfmt

Incorrectly strips r# prefix from labels

Closed this issue · 5 comments

Rust playground: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=051766b3584e787d3abab1d2f18424bb

The following code:

'r#if: {
  break 'r#if;
}

when run through either stable or nightly rustfmt will incorrectly be formatted into this:

'r#if: {
  break 'if;
}

which rustc will complain because 'if is an invalid label name:

error: invalid label name `'if`
 --> src/main.rs:5:15
  |
5 |         break 'if;
  |               ^^^

Note that this still does occur if the label name is not a keyword:

'r#a: {
  break 'r#a;
}

is formatted into

'r#a: {
  break 'a;
}

However this does not cause an error.

Versions of rustfmt (from rust-playground)
1.8.0-stable (2024-11-26 90b35a6239)
and
1.8.0-nightly (2024-11-30 7442931d49)

@Raspberry1111 thanks for the report. Has it always been possible to use r# in labels?

Judging from this pull request: rust-lang/rust#126452 they were added in version 1.83 which is coincidentally the current stable release

Testing this with rustc +1.82 --edition 2021 test.rs gives:

error: expected `while`, `for`, `loop` or `{` after a label
 --> test.rs:4:7
  |
4 |     'r#if: {
  |       ^ expected `while`, `for`, `loop` or `{` after a label
  |
help: add `'` to close the char literal
  |
4 |     'r'#if: {
  |       +

error: expected one of `.`, `:`, `;`, `?`, `for`, `loop`, `while`, `}`, or an operator, found `#`
 --> test.rs:4:7
  |
4 |     'r#if: {
  |       ^ expected one of 9 possible tokens

error: expected `while`, `for`, `loop` or `{` after a label
  --> test.rs:10:7
   |
10 |     'r#a: {
   |       ^ expected `while`, `for`, `loop` or `{` after a label
   |
help: add `'` to close the char literal
   |
10 |     'r'#a: {
   |       +

error: expected one of `.`, `:`, `;`, `?`, `for`, `loop`, `while`, `}`, or an operator, found `#`
  --> test.rs:10:7
   |
10 |     'r#a: {
   |       ^ expected one of 9 possible tokens

error: aborting due to 4 previous errors

Running rustc +1.83 --edition 2021 test.rs produces no errors

Thanks for the extra info. Yeah, I can reproduce this using the latest commit 9f8fcc2, and running rustfmt from source with cargo run --bin rustfmt -- --edition=2021:

input:

fn broken() {
    'r#if: {
        break 'r#if;
    }
}

fn works() {
    'r#a: {
        break 'r#a;
    }
}

output:

fn broken() {
    'r#if: {
        break 'if;
    }
}

fn works() {
    'r#a: {
        break 'a;
    }
}

Looks like break and continue formatting need to be updated to use the span of the Label, and not just the identifier like rust-lang/rust#126452:

rustfmt/src/expr.rs

Lines 201 to 213 in 9f8fcc2

ast::ExprKind::Continue(ref opt_label) => {
let id_str = match *opt_label {
Some(label) => format!(" {}", label.ident),
None => String::new(),
};
Ok(format!("continue{id_str}"))
}
ast::ExprKind::Break(ref opt_label, ref opt_expr) => {
let id_str = match *opt_label {
Some(label) => format!(" {}", label.ident),
None => String::new(),
};

@rustbot claim
I haven't contribute rustfmt yet but I'd like to work on this issue!

ytmimi commented

@sobatha that's great! Let me know if you need any help getting started.