rust-lang / rust

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

Compilation error using a macro as a const generic argument (Rust 1.51 beta) #83198

Open jgallagher opened 3 years ago

jgallagher commented 3 years ago

(Playground link: https://play.rust-lang.org/?version=beta&mode=debug&edition=2018&gist=402577a37bb1cddc21d5bf4768594e65)

I tried this code:

macro_rules! expand_to_usize {
    () => {
        5usize
    }
}

fn print_const_generic_arg<const N: usize>() {
    println!("N = {}", N);
}

fn main() {
    // works
    print_const_generic_arg::<10>();

    // works
    const X: usize = expand_to_usize!();
    print_const_generic_arg::<X>();

    // doesn't work:
    print_const_generic_arg::<expand_to_usize!()>();
}

I expected to see this happen: Code compiles and prints

N = 10
N = 5
N = 5

Instead, this happened: The final call fails to compile with error messages that seem to be contradictory:

error: expected type, found `5usize`
  --> src/main.rs:3:9
   |
3  |         5usize
   |         ^^^^^^ expected type
...
20 |     print_const_generic_arg::<expand_to_usize!()>();
   |                               ------------------
   |                               |
   |                               this macro call doesn't expand to a type
   |                               in this macro invocation
   |
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0747]: type provided when a constant was expected
  --> src/main.rs:20:31
   |
20 |     print_const_generic_arg::<expand_to_usize!()>();
   |                               ^^^^^^^^^^^^^^^^^^

error: aborting due to 2 previous errors

Meta

Locally where I ran into this:

rustc --version --verbose:

rustc 1.51.0-beta.4 (4d25f4607 2021-03-05)

The playground says it's on 1.51.0-beta.6 and has the same error.

jgallagher commented 3 years ago

Update: Wrapping the macro in {} makes the code work as I expected, but warns that the braces are unnecessary:

warning: unnecessary braces around const expression
  --> src/main.rs:20:31
   |
20 |     print_const_generic_arg::<{expand_to_usize!()}>();
   |                               ^^^^^^^^^^^^^^^^^^^^ help: remove these braces
   |
   = note: `#[warn(unused_braces)]` on by default

I haven't been following min_const_generics super closely, but should braces be required to use a macro like this? If so perhaps this bug is more of a compiler diagnostic issue - without braces gives confusing errors instead of recommending adding braces (?), but with braces gives an (erroneous?) warning about unnecessary braces.

estebank commented 3 years ago

I think the lang team needs to determine which of the two behaviors the implementation should follow: require braces around macros or treat macros the same way as literals.

marshrayms commented 8 months ago

I encountered this today on stable 1.75.0, and was confused when I couldn't find any documentation about this behavior.

Here's my repro with various test cases on Rust Playground.

It's not just literals in const generic params though.