Rust macro with #[no_mangle] function triggers 'unsafe attribute' error when applied to a struct
03:59 30 Sep 2025

I'm trying to implement a Rust procedural macro that exports a C-compatible function for a driver I'm writing. Here's my macro:

extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{ItemStruct, parse_macro_input};

#[proc_macro_attribute]
pub fn export_driver(_attr: TokenStream, item: TokenStream) -> TokenStream {
    let input = parse_macro_input!(item as ItemStruct);
    let name = &input.ident;
    
    let expanded = quote! {
        #input        
        
        #[no_mangle]
        pub unsafe extern "C" fn init() -> i32 {
            #name::init()                
        }        
    };

    TokenStream::from(expanded)
}

I try to use the macro like this:

#[export_driver] 
struct MyDriver;

But I get the error:

[export_driver]
  | ^^^^^^^^^^^^^^^^ usage of unsafe attribute
  |
  = note: this error originates in the attribute macro `export_driver` (in Nightly builds, run with -Z macro-backtrace for more info)
help: wrap the attribute in `unsafe(...)`
  |
4 | unsafe(#[export_driver])
  | +++++++  

If I try what the compiler suggests, I get another error:

error: expected item, found keyword `unsafe`
 --> my-driver\src\main.rs:4:1
  |
4 | unsafe(#[export_driver])
  | ^^^^^^ expected item

Removing #[no_mangle] suppresses the first error in the original code, but I need to keep the exported function name.

Question: How can I keep #[no_mangle] in the generated function while still applying my macro to a struct?

rust macros