This is actually almost possible today! There's an open issue about this in the rust repository: https://github.com/rust-lang/rust/issues/52607
It turns out that the way rust expands macros, if concat!()
is used as an argument to another proc-macro, it will be passed successfully into #[doc = ...]
, whereas using it directly will trigger the error.
I've worked around this in my projects with the following macro:
/// Declares an item with a doc attribute computed by some macro expression.
/// This allows documentation to be dynamically generated based on input.
/// Necessary to work around https://github.com/rust-lang/rust/issues/52607.
macro_rules! calculated_doc {
(
$(
#[doc = $doc:expr]
$thing:item
)*
) => (
$(
#[doc = $doc]
$thing
)*
);
}
This can be expanded/modified to support arbitrary other doc comments! One way would be to mark the specific one to expand using a special symbol, such as @
, and to rely on the fact that item
includes arbitrary meta attributes as well, like so:
/// Declares an item with a doc attribute computed by some macro expression.
/// This allows documentation to be dynamically generated based on input.
/// Necessary to work around https://github.com/rust-lang/rust/issues/52607.
macro_rules! calculated_doc {
(
$(
$(#[$m:meta])*
@#[doc = $doc:expr]
$thing:item
)*
) => (
$(
$(#[$m])*
#[doc = $doc]
$thing
)*
);
}
This could then be used like this:
macro_rules! impl_function {
($name:ident) => {
calculated_doc! {
/// # Usage:
///
/// ```
@#[doc = concat!(" let _ = ", stringify!($name), "();")]
/// ```
pub fn $name() {}
}
};
}
Hopefully that helps - depending on what you're doing, it might make sense to just use an inner macro particular to your macro - something like this:
macro_rules! impl_function {
($name:ident) => {
impl_function!($name, concat!(" let _ = ", stringify!($name), "();"));
};
($name:ident, $usage:expr) => {
/// # Usage:
///
/// ```
#[doc = $usage]
/// ```
pub fn $name() {}
};
}
impl_function!(hi);
This whole thing is definitely a bit hacky, but as there are published crates which inadvertently use this (or purposefully use this), I don't think it'll be removed anytime soon.