You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
decl_macro expansion in 2018 context cannot refer to external crates at the root #55668
decl_macros that are invoked in a 2018 edition crate can fail depending on how the macro's paths are defined.
Minimized example:
#![feature(decl_macro)]
macro test {
() => {
::std::vec::Vec::new()
}
}
fn main() {
let x: Vec<i32> = test!();
}
In the 2018 edition, this fails to compile:
error[E0433]: failed to resolve. Could not find `std` in `{{root}}`
--> src/main.rs:5:11
|
5 | ::std::vec::Vec::new()
| ^^^ Could not find `std` in `{{root}}`
...
10 | let x: Vec<i32> = test!();
| ------- in this macro invocation
error: aborting due to previous error
The edition at the expansion location is what matters in this case, not the edition in which the macro is defined. Other crates show the same error message, not just std.
The workarounds that I have found so far are to start the path with std (no leading ::), or to add extern crate std; into the macro itself. The former is not a usable option when the decl_macro is generated by a proc_macro, because the crate std could be shadowed by a module named std at the "real" decl_macro definition site.
My bisect of the more complicated example pointed to #54658 -- cc @petrochenkov
I believe this is actually the expected behavior. Since decl_macro's are supposed to be fully hygienic, their expansion should not be able to refer to crates (or any item) that isn't declared in the expansion itself or a parent expansion thereof. That being said, it's long been desired that the prelude be made available to decl_macros which would resolve this case in particular.
The bug, however, is that hygiene seems to depend on the edition. The following, for instance, compiles just fine in the 2015 edition but fails in the 2018 edition:
I believe this is actually the expected behavior. Since decl_macro's are supposed to be fully hygienic, their expansion should not be able to refer to crates (or any item) that isn't declared in the expansion itself or a parent expansion thereof.
The real scheme is a bit more complex, when resolving i-th path segment with i > 0 hygienic context is "adjusted to the module" of the prefix 0 ... i - 1, so things like
#![feature(decl_macro)]structS;mod m {
macro m(){let s = crate::S;// OK}fncheck(){m!();}}fnmain(){}
work despite S in crate::S not having the same context as S in struct S.
So, ::my_crate should indeed work, and #54658 introduced a regression by forgetting to adjust std's context in ::std to the "crate universe module".
That being said, it's long been desired that the prelude be made available to decl_macros
Preludes are already kinda work with decl_macros
#![feature(decl_macro)]macro m(){let v = Vec::<u8>::new();// OK}fnmain(){m!();}
, but how exactly they work with non-built-in names is an open question, and their hygiene is broken in cross-crate scenarios - prelude of the use-site crate is always used.
Activity
SergioBenitez commentedon Nov 4, 2018
I believe this is actually the expected behavior. Since
decl_macro's are supposed to be fully hygienic, their expansion should not be able to refer to crates (or any item) that isn't declared in the expansion itself or a parent expansion thereof. That being said, it's long been desired that the prelude be made available todecl_macros which would resolve this case in particular.The bug, however, is that hygiene seems to depend on the edition. The following, for instance, compiles just fine in the 2015 edition but fails in the 2018 edition:
petrochenkov commentedon Nov 4, 2018
@SergioBenitez
The real scheme is a bit more complex, when resolving
i-th path segment withi > 0hygienic context is "adjusted to the module" of the prefix0 ... i - 1, so things likework despite
Sincrate::Snot having the same context asSinstruct S.So,
::my_crateshould indeed work, and #54658 introduced a regression by forgetting to adjuststd's context in::stdto the "crate universe module".Preludes are already kinda work with decl_macros
, but how exactly they work with non-built-in names is an open question, and their hygiene is broken in cross-crate scenarios - prelude of the use-site crate is always used.
petrochenkov commentedon Nov 18, 2018
Fixed in #55884