Repository navigation
Crates can't migrate to 2018 edition when they invoke coupled procedural macros #54647
Description
Activity
- addedWG-epochWorking group: Epoch (2018) managementWorking group: Epoch (2018) managementF-rust_2018_preview`#![feature(rust_2018_preview)]``#![feature(rust_2018_preview)]`
on Sep 28, 2018 This was first reported at dtolnay/syn#507
cc @rust-lang/lang @petrochenkov
Shouldn't such macros use
$self::MyTypeor similar instead? (Does that not work for procedural macros, for some reason?)@joshtriplett the procedural macro and the runtime support live in separate crates, think serde_derive vs serde. You would need some way to specify what crate
$selfwould refer to, because in code generated by serde_derive all the types are defined by serde not serde_derive.Hack: provide a version of macro with an extra argument for internal use and replace
::foowithcrateif it's used.Hack 2:
--extern foo=selfthat addsfoointo extern prelude as an alias tocrate.Or, in general, some way to add a name that's associated with the current crate into extern prelude.
@dtolnay Ah, I misunderstood the phrase "the crate foo to use its own macros internally".
Perhaps even
#![crate_name = "foo"]and--crate-name NAMEcan be re-purposed for that.
In general, if the crate knows its name (which is not always true), we can add that name into extern prelude.EDIT: Nah, perhaps this need is too special,
my_crate_namebeing generally available as an alias tocratein all crates built by Cargo would probably mostly cause confusion.extern crate foo = PATH;😄@petrochenkov wouldn't that create a bit of a "side-effect" in the system?
Or would you be required to place it in the root of another crate?@eddyb
Do you meanextern crate foo?
If by side effect you mean that the extern prelude set becomes dynamic and can change in the process of expansion, then yes.
It's not so bad, it's the same thing as#[macro_use] extern crate ...adding names into the macro prelude, so it's trivially implementable in the existing infrastructure.
It breaks the uniform import path scheme with canaries though, so it's one more reason to move the implementation to the proper search in scope sooner (EDIT: or perhaps not and we'll just need more canaries?).#54658 implements a possible prerequisite (extern crate items adding things into extern prelude).
6 remaining items
@stephaneyfx's solution seems to work nicely, but can be simplified:
let c = if env::var("CARGO_PKG_NAME").unwrap() == "mycrate" { quote!( crate ) } else { quote!( mycrate ) };
Then just use
#cinsidequote!instead of$crate.Edit: I realise this will only work where the crate using the macro is using Edition 2018.
Reacted by Arto BendikenI think I found a problem with this workaround (even using Edition 2018): rustdoc examples. Since the error message is pretty poor I'm not certain, but I think it's using
cratewithin the doc example.Something I noticed in a 2018 edition crate using a 2015 crate/crate-derive pair, is that the trait needs to be
used in the 2018 edition crate, while it wasn't necessary in 2015 code.Something I noticed in a 2018 edition crate using a 2015 crate/crate-derive pair, is that the trait needs to be used in the 2018 edition crate, while it wasn't necessary in 2015 code.
That's expected. Derives were imported with
#[macro_use] extern cratein 2015, whereas in 2018 they are imported the same way as any other name would be.Is this going to be fixed before release or will these kinds of crates be incompatible across editions?
I don't know what the status of this is, but this issue doesn't refer to a crate being "incompatible across editions." That's not possible: there's no way to define a crate so that its "incompatible" with crates using a different edition. Crates using this pattern (which relies on an ambiguity in 2015 edition namespacing) just have to themselves continue to use the 2015 edition or one of the other workarounds discussed in this thread.
- added a commit that references this issue
on Dec 1, 2018 - added a commit that references this issue
on Jul 28, 2024 - added a commit that references this issue
on Aug 19, 2024
Procedural macros are often coupled with "runtime crates" which support the various macros that the procedural macro exports. These runtime crates, however, sometimes also want to invoke the procedural macro itself (think
panic!and libstd, which exports it for users and also defines it itself).Let's say our runtime crate is called
foo. The macro today generally expands to paths that look like::foo::MyType. This doesn't work by default in the cratefooitself, sofootypically includes a module that looks like:And the enables the crate
footo use its own macros internally.In the 2018 edition, however, the
::foo::MyTypepath unconditionally requiresfooto be a crate, which isn't the case when we're compilingfoo! As a result, these sorts of runtime crates don't have a great path forward when migrating to the 2018 edition.