Skip to content

Crates can't migrate to 2018 edition when they invoke coupled procedural macros #54647

Description

@alexcrichton

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 crate foo itself, so foo typically includes a module that looks like:

mod foo { pub use super::*; }

And the enables the crate foo to use its own macros internally.

In the 2018 edition, however, the ::foo::MyType path unconditionally requires foo to be a crate, which isn't the case when we're compiling foo! As a result, these sorts of runtime crates don't have a great path forward when migrating to the 2018 edition.

Activity

  1. alexcrichton commented on Sep 28, 2018

    @alexcrichton
    MemberAuthor

    This was first reported at dtolnay/syn#507

  2. eddyb commented on Sep 28, 2018

    @eddyb
    Contributor

    cc @rust-lang/lang @petrochenkov

  3. joshtriplett commented on Sep 28, 2018

    @joshtriplett
    Member

    Shouldn't such macros use $self::MyType or similar instead? (Does that not work for procedural macros, for some reason?)

  4. dtolnay commented on Sep 28, 2018

    @dtolnay
    Member

    @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 $self would refer to, because in code generated by serde_derive all the types are defined by serde not serde_derive.

  5. petrochenkov commented on Sep 28, 2018

    @petrochenkov
    Contributor

    Hack: provide a version of macro with an extra argument for internal use and replace ::foo with crate if it's used.

  6. petrochenkov commented on Sep 28, 2018

    @petrochenkov
    Contributor

    Hack 2: --extern foo=self that adds foo into extern prelude as an alias to crate.

  7. petrochenkov commented on Sep 28, 2018

    @petrochenkov
    Contributor

    Or, in general, some way to add a name that's associated with the current crate into extern prelude.

  8. joshtriplett commented on Sep 28, 2018

    @joshtriplett
    Member

    @dtolnay Ah, I misunderstood the phrase "the crate foo to use its own macros internally".

  9. petrochenkov commented on Sep 28, 2018

    @petrochenkov
    Contributor

    Perhaps even #![crate_name = "foo"] and --crate-name NAME can 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_name being generally available as an alias to crate in all crates built by Cargo would probably mostly cause confusion.

  10. petrochenkov commented on Sep 28, 2018

    @petrochenkov
    Contributor

    extern crate foo = PATH; 😄

  11. eddyb commented on Sep 28, 2018

    @eddyb
    Contributor

    @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?

  12. petrochenkov commented on Sep 28, 2018

    @petrochenkov
    Contributor

    @eddyb
    Do you mean extern 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?).

  13. petrochenkov commented on Sep 29, 2018

    @petrochenkov
    Contributor

    #54658 implements a possible prerequisite (extern crate items adding things into extern prelude).

  14. 6 remaining items

  15. dhardy commented on Oct 28, 2018

    @dhardy
    Contributor

    @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 #c inside quote! instead of $crate.

    Edit: I realise this will only work where the crate using the macro is using Edition 2018.

  16. petrochenkov commented on Oct 28, 2018

    @petrochenkov
    Contributor

    @dhardy
    ::crate::foo with leading :: doesn't currently work (#53347), so there may be issues with disambiguated paths?

  17. dhardy commented on Oct 30, 2018

    @dhardy
    Contributor

    I 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 crate within the doc example.

  18. glandium commented on Nov 23, 2018

    @glandium
    Contributor

    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.

  19. withoutboats commented on Nov 27, 2018

    @withoutboats
    Contributor

    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.

  20. added a commit that references this issue on Dec 1, 2018
  21. added a commit that references this issue on Mar 2, 2019
  22. added a commit that references this issue on Jul 28, 2024
  23. added a commit that references this issue on Aug 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

A-edition-2018Area: The 2018 editionF-rust_2018_preview`#![feature(rust_2018_preview)]`WG-epochWorking group: Epoch (2018) management

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions