rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
97.82k stars 12.66k forks source link

`warn(semicolon_in_expressions_from_macros)` interacts poorly with macros invalid in expression context #109236

Open CAD97 opened 1 year ago

CAD97 commented 1 year ago

Code

/*
[package]
edition = "2021"
*/

macro_rules! statement {
    () => {
        ();
        let _ = ();
    };
}

fn main() {
    let _ = statement!();
}

Current output

error: macro expansion ignores token `let` and any following
  --> src\main.rs:LL:CC
   |
LL |         let _ = ();
   |         ^^^
...
LL |     let _ = statement!();
   |             ------------ caused by the macro expansion here
   |
   = note: the usage of `statement!` is likely invalid in expression context

warning: trailing semicolon in macro used in expression position
  --> src\main.rs:LL:CC
   |
LL |         ();
   |           ^
...
LL |     let _ = statement!();
   |             ------------ in this macro invocation
   |
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
   = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default
   = note: this warning originates in the macro `statement` (in Nightly builds, run with -Z macro-backtrace for more info)

Desired output

error: macro invalid in expression context
  --> src\main.rs:LL:CC
   |
LL |     let _ = statement!();
   |             ------------ expression position macro expansion here
   |
  ::: src\main.rs:LL:CC
   |
LL |         ();
   |           - macro expands to a statement terminated here...
LL |         let _ = ();
   |         --- ... and continues producing further tokens
   |
   = note: macros expanding to statement(s) can only be used in statement position
   = help: if the macro expansion should be an expression, try wrapping it in a block
   |
LL |     () => {{
   |            +
...
LL |     }};
   |      +

Rationale and extra context

(example desired are probably a bit overly verbose; I erred on the side of suggesting giving more information)

[[rustexplorer]](https://www.rustexplorer.com/b#%2F*%0A%5Bpackage%5D%0Aedition%20%3D%20%222021%22%0A*%2F%0A%0Amacro_rules!%20statement%20%7B%0A%20%20%20%20()%20%3D%3E%20%7B%0A%20%20%20%20%20%20%20%20()%3B%0A%20%20%20%20%20%20%20%20let%20_%20%3D%20()%3B%0A%20%20%20%20%7D%3B%0A%7D%0A%0Afn%20main()%20%7B%0A%20%20%20%20let%20_%20%3D%20statement!()%3B%0A%7D%0A)

Other cases

Interestingly enough, the warning seems to only be emitted when the macro definition is local; just the error is shown if the macro is defined in an upstream crate. If we're rewording the local error, though, the external one should be reworded similarly, e.g.

error: macro invalid in expression context
  --> src\main.rs:LL:CC
   |
LL |     let _ = statement!();
   |             ------------ expression position macro expansion here
   |
   = note: macro expands to one or more statements

For the local single statement case, presented as an error:

error: macro invalid in expression context
  --> src\main.rs:LL:CC
   |
LL |     let _ = statement!();
   |             ------------ expression position macro expansion here
   |
  ::: src\main.rs:LL:CC
   |
LL |         ();
   |           ^ this semicolon makes the expansion a statement
   |
   = note: macros expanding to statement(s) can only be used in statement position
   = help: if the macro expansion should be an expression, remove the semicolon
   |
LL |         ()
   |           ~
   |
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
   = note: `#[deny(semicolon_in_expressions_from_macros)]` on by default

Note also that the external single statement macro case does not currently warn. Reworded to fit this pattern,

warning: macro invalid in expression context
  --> src\main.rs:LL:CC
   |
LL |     let _ = statement!();
   |             ------------ expression position macro expansion here
   |
   = note: macro expands to a single semicolon-terminated expression statement
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
   = note: `#[warn(semicolon_in_expressions_from_external_macros)]` on by default

error: macro invalid in expression context
  --> src\main.rs:LL:CC
   |
LL |     let _ = statement!();
   |             ------------ expression position macro expansion here
   |
   = note: macro expands to one or more statements
   = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
   = note: `#[forbid(semicolon_in_expressions_from_external_macros)]` enabled

Anything else?

$ rustc -Vv
rustc 1.70.0-nightly (ab654863c 2023-03-15)
binary: rustc
commit-hash: ab654863c3d50482f260cf862647f1fe0ff5e010
commit-date: 2023-03-15
host: x86_64-pc-windows-msvc
release: 1.70.0-nightly
LLVM version: 15.0.7
CAD97 commented 1 year ago

@rustbot modify labels +D-verbose