gccrs
gccrs copied to clipboard
Handle `$crate` properly in macros
A special "metavar" exists in macro invocations, which helps reference items from the module in macro invocations. We must implement its handling properly for the Imports and Visibility milestone as it is a core part of exporting macros to the rest of a crate
By default, all identifiers referred to in a macro are expanded as-is, and are looked up at the macro's invocation site. This can lead to issues if a macro refers to an item or macro which isn't in scope at the invocation site. To alleviate this, the $crate metavariable can be used at the start of a path to force lookup to occur inside the crate defining the macro.
//// Definitions in the `helper_macro` crate.
#[macro_export]
macro_rules! helped {
// () => { helper!() } // This might lead to an error due to 'helper' not being in scope.
() => { $crate::helper!() }
}
#[macro_export]
macro_rules! helper {
() => { () }
}
//// Usage in another crate.
// Note that `helper_macro::helper` is not imported!
use helper_macro::helped;
fn unit() {
helped!();
}
Note that, because $crate refers to the current crate, it must be used with a fully qualified module path when referring to non-macro items:
pub mod inner {
#[macro_export]
macro_rules! call_foo {
() => { $crate::inner::foo() };
}
pub fn foo() {}
}
Additionally, even though $crate allows a macro to refer to items within its own crate when expanding, its use has no effect on visibility. An item or macro referred to must still be visible from the invocation site. In the following example, any attempt to invoke call_foo!() from outside its crate will fail because foo() is not public.
#[macro_export]
macro_rules! call_foo {
() => { $crate::foo() };
}
fn foo() {}