6

I'm creating a macro called throw_error. I expected this to compile yet, it fails:

// Util structs + types

...

// Util macros

#[macro_export]
macro_rules! throw_error {
    () => {
        RaptorexError {
            message: String::new(),
            line: line!(),
            file: file!().to_owned(),
        }
    };

    ($($msg:tt),*) => {
        let mut final_msg = String::new();

        $(
            final_msg.push_str(&format!("{} ", $msg));
        )*

        // remove trailing whitespace
        final_msg.pop();

        RaptorexError {
            message: final_msg,
            line: line!(),
            file: file!(),
        }
    }
}

// Util functions

...

I get several errors from using the macro in my other code.

Erros:

error: macro expansion ignores token `final_msg` and any following
  --> /Users/henryboisdequin/Desktop/raptorex/raptorex_util/src/lib.rs:30:13
   |
30 |             final_msg.push_str(&format!("{} ", $msg));
   |             ^^^^^^^^^
   | 
  ::: compiler/src/parser/parser.rs:44:29
   |
44 |             _ => return Err(throw_error!("Unexpected token:", current_token)),
   |                             ------------------------------------------------- help: you might be missing a semicolon here: `;`
   |                             |
   |                             caused by the macro expansion here
   |
   = note: the usage of `throw_error!` is likely invalid in expression context

error[E0658]: `let` expressions in this position are experimental
  --> compiler/src/parser/parser.rs:44:29
   |
44 |             _ => return Err(throw_error!("Unexpected token:", current_token)),
   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
   = help: add `#![feature(let_chains)]` to the crate attributes to enable
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

error: `let` expressions are not supported here
  --> compiler/src/parser/parser.rs:44:29
   |
44 |             _ => return Err(throw_error!("Unexpected token:", current_token)),
   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: only supported directly in conditions of `if`- and `while`-expressions
   = note: as well as when nested within `&&` and parenthesis in those conditions
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

warning: unused imports: `DATA_TYPES`, `KEYWORDS`
 --> compiler/src/parser/parser.rs:3:28
  |
3 |     lexer::tokens::{Token, DATA_TYPES, KEYWORDS},
  |                            ^^^^^^^^^^  ^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

error[E0308]: mismatched types
  --> compiler/src/parser/parser.rs:44:29
   |
44 |             _ => return Err(throw_error!("Unexpected token:", current_token)),
   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `raptorex_util::RaptorexError`, found `bool`
   |
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 4 previous errors; 1 warning emitted

What is the cause of these errors and how can I fix it?

1 Answer 1

3

You need another set of {}s so the macro creates a block containing the statements instead of the individual statements themselves:

#[macro_export]
macro_rules! throw_error {
    () => {
        RaptorexError {
            message: String::new(),
            line: line!(),
            file: file!().to_owned(),
        }
    };

    ($($msg:tt),*) => {
        { // <------------------
            let mut final_msg = String::new();
    
            $(
                final_msg.push_str(&format!("{} ", $msg));
            )*
    
            // remove trailing whitespace
            final_msg.pop();
    
            RaptorexError {
                message: final_msg,
                line: line!(),
                file: file!(),
            }
        } // <-------------------
    }
}

The {} in the (...) => {} is part of the macro syntax and isn't part of the generated code.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, it worked but how do I import the RaptorexError from inside the extra brackets. I'm having trouble with that.
You can use an absolute path (i.e. ::crate_name::some_path::RaptorexError) either directly or with a use declaration within the block.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.