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

Rust 2021 (seemingly) mistakenly warns 'panic message contains braces' #87621

Closed
mocsy opened this issue Jul 30, 2021 · 8 comments
Closed

Rust 2021 (seemingly) mistakenly warns 'panic message contains braces' #87621

mocsy opened this issue Jul 30, 2021 · 8 comments
Assignees
Labels
A-edition-2021 Area: The 2021 edition A-lint Area: Lints (warnings about flaws in source code) such as unused_mut. C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@mocsy
Copy link

mocsy commented Jul 30, 2021

Later versions of rust mistake macros like https://crates.io/crates/contracts requires as a panic message.

Given the following code: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=babeae07316ceb37dd7291ff889e9ea3

<code>

The current output is:

warning: panic message contains braces
  --> src/main.rs:4:16
   |
4 |     #[requires(key.starts_with('{'))]
   |                ^^^
   |
   = note: `#[warn(non_fmt_panic)]` on by default
   = note: this message is not used as a format string, but will be in Rust 2021
help: add a "{}" format string to use the message literally
   |
4 |     #[requires("{}", key.starts_with('{'))]
   |                ^^^^^

Ideally the output should look like:
Nothing, it's not a panic message, it's an expression.

<proposed output>
@mocsy mocsy added A-diagnostics Area: Messages for errors, warnings, and lints T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jul 30, 2021
@jonas-schievink jonas-schievink added A-lint Area: Lints (warnings about flaws in source code) such as unused_mut. C-bug Category: This is a bug. and removed A-diagnostics Area: Messages for errors, warnings, and lints labels Jul 30, 2021
@ehuss
Copy link
Contributor

ehuss commented Jul 30, 2021

Hm, I'm uncertain how that should be handled.

The requires attribute essentially expands to:

assert!(expr, concat!("Pre-condition of parse violated: ", stringify!(key.starts_with('{'))))

which expands to

assert!(expr, "Pre-condition of parse violated: key.starts_with('{')")

This ends up with a bare { in the panic string. Indeed this code will fail to compile in 2021.

The contracts crate could be updated to generate the assert macros with the proper formatting (assert!(expr, "{}", "the message")). However, it would be desirable if that was not required. I'm not entirely familiar with proc-macro edition hygiene. I would actually expect this to not warn at all, since I would expect the code generated by the proc-macro to be tagged with the 2018 edition.

@ehuss ehuss added the A-edition-2021 Area: The 2021 edition label Jul 30, 2021
@nikomatsakis
Copy link
Contributor

Indeed, I think that proc-macro hygiene doesn't work all that well. To make it work, presumably, one would have to use the proper spans -- and this is a bit questionable, because the span for this time probably comes from the Rust 2021 crate, but the Rust 2018 crate is the one turning it into a string.

In general, macro selection etc is not especially hygiene friendly, so I'm not totally sure how this winds up interacting.

@m-ou-se
Copy link
Member

m-ou-se commented Jul 30, 2021

Aw, I put effort into making sure the suggestions are handled correctly in macro expansions as well, but apparently it doesn't work here at all. (Suggesting the "{}", in the macro call.) I'll take a look at improving that.

However, it would be desirable if that was not required. I'm not entirely familiar with proc-macro edition hygiene. I would actually expect this to not warn at all, since I would expect the code generated by the proc-macro to be tagged with the 2018 edition.

It does see this as a 2015/2018 panic. The hygiene works correctly. This warning is for 2015/2018 code. In 2021 code, such a panic/assert call wouldn't compile at all.

@m-ou-se m-ou-se self-assigned this Jul 30, 2021
@ehuss
Copy link
Contributor

ehuss commented Jul 30, 2021

It does see this as a 2015/2018 panic. The hygiene works correctly. This warning is for 2015/2018 code. In 2021 code, such a panic/assert call wouldn't compile at all.

So, just to clarify: The issue is that contracts uses quote_spanned, which tags that entire section of code with the edition of the caller (2021 in this case)? (At least, in my limited testing, it seems to not fail if I use quote! instead of quote_spanned!).

Also, I noticed that calling any macro (macro_rules, proc_macro, etc.) from another crate triggers the warning. I don't think it should be doing that, though, since there's nothing the caller can do about it, and it doesn't actually fail? That is, defining a macro in 2018 like this:

#[macro_export]
macro_rules! foo {
    () => {assert!(true, "{")};
}

And calling that from a 2021 crate triggers a warning, but there's nothing to do since it works correctly.

@Nemo157
Copy link
Member

Nemo157 commented Jul 30, 2021

It does see this as a 2015/2018 panic. The hygiene works correctly. This warning is for 2015/2018 code. In 2021 code, such a panic/assert call wouldn't compile at all.

Testing the playground code in an edition = "2021" crate it fails to compile, so I don't think the hygiene is correct (but it sounds like that is an implementation issue that contracts is applying the incorrect span to the panic! macro call).

@m-ou-se
Copy link
Member

m-ou-se commented Jul 31, 2021

So, just to clarify: The issue is that contracts uses quote_spanned, which tags that entire section of code with the edition of the caller (2021 in this case)? (At least, in my limited testing, it seems to not fail if I use quote! instead of quote_spanned!).

Ah, yes. The span of the format string itself doesn't really matter, but the call site of the assert!() call itself does matter. So if they used quote_spanned only for the format string, but regular quote for the surrounding tokens, it'd be fine.

Also, I noticed that calling any macro (macro_rules, proc_macro, etc.) from another crate triggers the warning.

Yeah it shouldn't give warnings you can't fix in your current crate, so that part is a bug. It's a bit tricky, because if you have e.g.

macro_rules! mypanic {
    ($($t:tt)*) => { assert!(false, $($t:tt)*) };
}

then a warning about mypanic!("{}") probably missing an argument (even though it compiles) is still good. Surprised to see that your example still ends up in a warning. I thought I had handled those cases, but apparently I misremember.

@m-ou-se
Copy link
Member

m-ou-se commented Aug 12, 2021

Warning about issues that are entirely in another crate is solved by #87965
(It still warns about mypanic!("{}") in the example above, but not if a!() expands to a panic including format string that would trigger the lint.)

The problem with #[requires(key.starts_with('{'))] with the contracts crate isn't really something to solve fully: That proc macro applies the same span to all tokens, effectively claiming that not the macro but the user wrote assert!(expr, concat!(...)), in exactly the spot where the user wrote key.starts_with('{'). The compiler trusts that information, and repots to the user that the assert!() 'that the user wrote' is incorrect. The proper fix is to fix the contracts crate to not claim the assert!( part was written by the user. #87967 is a band aid to detect the most basic cases like this and avoid giving an invalid suggestion.

Manishearth added a commit to Manishearth/rust that referenced this issue Aug 12, 2021
…stebank

Silence non_fmt_panic from external macros.

This stops the non_fmt_panic lint from triggering if a macro from another crate is entirely responsible. In those cases there's nothing that the current crate can/should do.

See also rust-lang#87621 (comment)
GuillaumeGomez added a commit to GuillaumeGomez/rust that referenced this issue Aug 15, 2021
…pans, r=cjgillot

Detect fake spans in non_fmt_panic lint.

This addresses rust-lang#87621

Some proc_macros claim that the user wrote all of the tokens it outputs, by applying a span from the input to all of the produced tokens. That can result in confusing suggestions, as in rust-lang#87621. This is a simple patch that avoids suggesting anything for `panic!("{}")` if the span of `"{}"` and `panic!(..)` are identical, which is normally not possible.
GuillaumeGomez added a commit to GuillaumeGomez/rust that referenced this issue Aug 15, 2021
…pans, r=cjgillot

Detect fake spans in non_fmt_panic lint.

This addresses rust-lang#87621

Some proc_macros claim that the user wrote all of the tokens it outputs, by applying a span from the input to all of the produced tokens. That can result in confusing suggestions, as in rust-lang#87621. This is a simple patch that avoids suggesting anything for `panic!("{}")` if the span of `"{}"` and `panic!(..)` are identical, which is normally not possible.
camsteffen added a commit to camsteffen/rust that referenced this issue Aug 15, 2021
…pans, r=cjgillot

Detect fake spans in non_fmt_panic lint.

This addresses rust-lang#87621

Some proc_macros claim that the user wrote all of the tokens it outputs, by applying a span from the input to all of the produced tokens. That can result in confusing suggestions, as in rust-lang#87621. This is a simple patch that avoids suggesting anything for `panic!("{}")` if the span of `"{}"` and `panic!(..)` are identical, which is normally not possible.
m-ou-se added a commit to m-ou-se/rust that referenced this issue Aug 16, 2021
…pans, r=cjgillot

Detect fake spans in non_fmt_panic lint.

This addresses rust-lang#87621

Some proc_macros claim that the user wrote all of the tokens it outputs, by applying a span from the input to all of the produced tokens. That can result in confusing suggestions, as in rust-lang#87621. This is a simple patch that avoids suggesting anything for `panic!("{}")` if the span of `"{}"` and `panic!(..)` are identical, which is normally not possible.
m-ou-se added a commit to m-ou-se/rust that referenced this issue Aug 16, 2021
…pans, r=cjgillot

Detect fake spans in non_fmt_panic lint.

This addresses rust-lang#87621

Some proc_macros claim that the user wrote all of the tokens it outputs, by applying a span from the input to all of the produced tokens. That can result in confusing suggestions, as in rust-lang#87621. This is a simple patch that avoids suggesting anything for `panic!("{}")` if the span of `"{}"` and `panic!(..)` are identical, which is normally not possible.
@m-ou-se
Copy link
Member

m-ou-se commented Aug 30, 2021

The latest nightly no longer produces the wrong suggestion.

The error is still produced, but that's not a problem that rustc can solve. That's up to the contracts crate, to use the right spans.

Closing this.

@m-ou-se m-ou-se closed this as completed Aug 30, 2021
2021 Edition Blockers automation moved this from Not-really blockers (?) to Completed items Aug 30, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-edition-2021 Area: The 2021 edition A-lint Area: Lints (warnings about flaws in source code) such as unused_mut. C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
2021 Edition Blockers
  
Completed items
Development

No branches or pull requests

6 participants