Can declarative rust macros be compiled conditionally?

✍️ Written on 2022-10-09 in 692 words. Part of cs software-development programming-languages rustlang

Motivation

This question arised during implementation of some rust software. Can declarative macros be conditionally compiled?

Declarative macros

Declarative macros give a limited mechanism to extend the syntax of a rust program. Declarative macros allow a programmer to define a set of rules which map some pattern to semantic elements which can be inserted into a block of code. Specifically, we define a meaningless macro for demonstration purposes called date:

macro_rules! date {
    ($year:expr, $month:expr, $day:expr) => {
        format!("{}-{}-{}", $year, $month, $day)
    };
}

The three arguments year, month, and day will be matched as expressions (besides expr, there are other designators).

date!(2022, 12, 23)

Conditional compilation of the macro

Consider the target_os condition. Is it possible to conditionally compile a declarative macro?

#[cfg(target_os = "linux")]
macro_rules! date {
    ($year:expr, $month:expr, $day:expr) => {
        format!("{}-{}-{}", $year, $month, $day)
    };
    ($year:expr, $month:expr) => {
        format!("{}-{}-03", $year, $month)
    };
}

fn main() {
    println!("date: {}", date!(2022, 12, 23));
}

Yes, this compiles.

Conditional compilation of macro rules

Is it possible to conditionally compile only one rule of the declarative macro?

macro_rules! date {
    ($year:expr, $month:expr, $day:expr) => {
        format!("{}-{}-{}", $year, $month, $day)
    };
    #[cfg(target_os = "linux")]
    ($year:expr, $month:expr) => {
        format!("{}-{}-03", $year, $month)
    };
}

fn main() {
    println!("date: {}", date!(2022, 12, 23));
}

No, this does not compile.

Conclusion

So it can be conditionally compiled, but not individual rules of the macros. I expect procedural macros to support this feature, if you need it.