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

Different behavior for macro by example and procedural macro #125238

Closed
thomasyonug opened this issue May 18, 2024 · 1 comment
Closed

Different behavior for macro by example and procedural macro #125238

thomasyonug opened this issue May 18, 2024 · 1 comment
Labels
A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) C-discussion Category: Discussion or questions that doesn't represent real issues.

Comments

@thomasyonug
Copy link

I tried this code:

// procedural macro definition
extern crate proc_macro;

use proc_macro::TokenStream;
use quote::quote;
use syn;

#[proc_macro]
pub fn mdriver(input: TokenStream) -> TokenStream {
    let ast = syn::parse(input).unwrap();
    impl_mdriver(&ast)
}

fn impl_mdriver(ast: &syn::Expr) -> TokenStream {
    let generated = quote! {
        pub fn main() {
            let (tx, rx) = #ast::<usize>();
            let x: Box<isize> = Box::new(1);
            let x_in_parent = &(*x) as *const isize as usize;
            let t = std::thread::spawn(move || {
                let x_in_child = &(*x) as *const isize as usize;
                tx.send(x_in_child).unwrap();
            });
            let x_in_child = rx.recv().unwrap();
            assert_eq!(x_in_parent, x_in_child);
            t.join().unwrap();
        }
    };

    generated.into()
}

// procedural call
mdriver!(std::sync::mpsc::channel);


// macro by example definition

#[macro_export]
macro_rules! mdriver {
    ($channel:expr) => {
        pub fn main() {
            let (tx, rx) = $channel::<usize>();
            let x: Box<isize> = Box::new(1);
            let x_in_parent = &(*x) as *const isize as usize;
            let t = std::thread::spawn(move || {
                let x_in_child = &(*x) as *const isize as usize;
                tx.send(x_in_child).unwrap();
            });
            let x_in_child = rx.recv().unwrap();
            assert_eq!(x_in_parent, x_in_child);
            t.join().unwrap();
        }
    };
}

// macro by example call

mdriver!(std::sync::mpsc::channel);

I expected to see this happen:

// expanded code as follows
#[prelude_import]
use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
extern crate pcd_16652092204041976610;
use pcd_16652092204041976610::mdriver;

fn main() {
        let (tx, rx) = std::sync::mpsc::channel::<usize>();
        let x: Box<isize> = Box::new(1);
        let x_in_parent = &*x as *const isize as usize;
        let t =
            std::thread::spawn(move ||
                    {
                            let x_in_child = &*x as *const isize as usize;
                            tx.send(x_in_child).unwrap();
                        });
        let x_in_child = rx.recv().unwrap();
        match (&x_in_parent, &x_in_child) {
                (left_val, right_val) => {
                    if !(*left_val == *right_val)
                            {
                                    let kind = ::core::panicking::AssertKind::Eq;
                                    ::core::panicking::assert_failed(kind, &*left_val,
                                        &*right_val, ::core::option::Option::None);
                                }
                        } };
                t.join().unwrap();
            }

Instead, this happened:

// but for macro by example, I get an error
// error: expected one of `.`, `;`, `?`, `else`, or an operator, found `::`
fn main() { (/*ERROR*/) }

Meta

rustc --version --verbose:

rustc 1.80.0-nightly (ef0027897 2024-05-12)
binary: rustc
commit-hash: ef0027897d2e9014766fb47dce9ddbb925d2f540
commit-date: 2024-05-12
host: x86_64-unknown-linux-gnu
release: 1.80.0-nightly
LLVM version: 18.1.4
Backtrace

<backtrace>

@thomasyonug thomasyonug added the C-bug Category: This is a bug. label May 18, 2024
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label May 18, 2024
@bjorn3
Copy link
Member

bjorn3 commented May 18, 2024

$channel::<usize>() is not a valid expression as $channel is parsed as expression due to the $channel:expr match. Try matching it using $($channel:tt)* and then use $($channel)*::<usize>().

This doesn't happen with proc macros as the syn::Expr gets turned back into a bunch of token trees rather than being captured as an expression like happens in the decl macro (macro by example) case.

@bjorn3 bjorn3 added A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) C-discussion Category: Discussion or questions that doesn't represent real issues. and removed C-bug Category: This is a bug. labels May 18, 2024
@fmease fmease removed the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label May 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) C-discussion Category: Discussion or questions that doesn't represent real issues.
Projects
None yet
Development

No branches or pull requests

4 participants