Skip to content

Decouple proc_macro from the rest of the compiler.#49219

Merged
bors merged 16 commits intorust-lang:masterfrom
eddyb:proc-macro-decouple
Nov 30, 2018
Merged

Decouple proc_macro from the rest of the compiler.#49219
bors merged 16 commits intorust-lang:masterfrom
eddyb:proc-macro-decouple

Conversation

@eddyb
Copy link
Member

@eddyb eddyb commented Mar 20, 2018

This PR removes all dependencies of proc_macro on compiler crates and allows multiple copies of proc_macro, built even by different compilers (but from the same source), to interoperate.

Practically, it allows:

  • running proc macro tests at stage1 (I moved most from -fulldeps to the regular suites)
  • using proc macros in the compiler itself (may require some rustbuild trickery)

On the server (i.e. compiler front-end) side:

  • server::* traits are implemented to provide the concrete types and methods
    • the concrete types are completely separated from the proc_macro public API
    • the only use of the type implementing Server is to be passed to Client::run

On the client (i.e. proc macro) side (potentially using a different proc_macro instance!):

  • client::Client wraps around client-side (expansion) function pointers
    • it encapsulates the proc_macro instance used by the client
    • its run method can be called by a server, to execute the client-side function
  • proc macro crates get a generated static holding a &[ProcMacro]
    • this describes all derives/attr/bang proc macros, replacing the "registrar" function
    • each variant of ProcMacro contains an appropriately typed Client<fn(...) -> ...>

proc_macro public APIs call into the server via an internal "bridge":

  • only a currently running proc macro Client can interact with those APIs
    • server code might not be able to (if it uses a different proc_macro instance)
      • however, it can always create and run its own Client, but that may be inefficient
  • the bridge uses serialization, C ABI and integer handles to avoid Rust ABI instability
  • each invocation of a proc macro results in disjoint integers in its proc_macro handles
    • this prevents using values of those types across invocations (if they even can be kept)

r? @alexcrichton cc @jseyfried @nikomatsakis @Zoxc @thepowersgang

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Mar 20, 2018
@eddyb
Copy link
Member Author

eddyb commented Mar 20, 2018

@bors try

@bors
Copy link
Collaborator

bors commented Mar 20, 2018

🔒 Merge conflict

@eddyb eddyb force-pushed the proc-macro-decouple branch from 67f317e to 6e63e8d Compare March 20, 2018 21:59
@eddyb
Copy link
Member Author

eddyb commented Mar 20, 2018

@bors try

@bors
Copy link
Collaborator

bors commented Mar 20, 2018

⌛ Trying commit 6e63e8d with merge c4a77e1...

bors added a commit that referenced this pull request Mar 20, 2018
Decouple proc_macro from the rest of the compiler.

This PR removes all dependencies of `proc_macro` on compiler crates and allows multiple copies of `proc_macro`, built even by different compilers (but from the same source), to interoperate.

On the compiler (aka "frontend") side:
* `Registry` is implemented (as until now)
  * instead of function pointers, the `Expand{1,2}` wrapper types are received
* `FrontendInterface` is implemented to provide the concrete type and methods
  * the concrete types are completely separated from the `proc_macro` public API
  * the only use of the implementer is to be passed to `Expand{1,2}::run`

On the proc macro side (potentially using a different `proc_macro` instance):
* `&mut Registry` is passed to the registrar (as until now)
* `Expand{1,2}` wrappers are created to be passed to the `Registry`
  * they encapsulate the `proc_macro` instance used by the macro crate
  * their `run` method will set up the "current frontend" of that instance

`proc_macro` public APIs call into the "current frontend" via the internal `bridge`:
* only a currently running proc macro can interact with those APIs
  * the frontend itself might not be able to (if it uses a different `proc_macro` instance)
* the `bridge` uses C ABI to avoid Rust ABI instability and "generation tagging" for safety
* each invocation of a proc macro results in a different "generation"
  * specifically, opaque `proc_macro` types wrapping concrete frontend types are tagged
  * this prevents using values of those types across invocations (even if they can be kept)
* an ABI mismatch between two versions of `proc_macro` is only possible during stage1
  * specifically, rustc compiled by stage0 but proc macros compiled by stage1
  * can only affect running tests at stage1 or the compiler using proc macros
  * defficiencies in the `bridge` can be addressed without waiting for a release cycle

r? @alexcrichton cc @jseyfried @nikomatsakis @Zoxc @thepowersgang
@eddyb eddyb added the S-waiting-on-crater Status: Waiting on a crater run to be completed. label Mar 20, 2018
@eddyb
Copy link
Member Author

eddyb commented Mar 20, 2018

cc @rust-lang/infra We shouldn't merge this without a crater run, although you might want to wait on a review as well (then again, the results could inform the review, so whichever comes first).

@bors
Copy link
Collaborator

bors commented Mar 21, 2018

☀️ Test successful - status-travis
State: approved= try=True


#[unstable(feature = "proc_macro_internals", issue = "27812")]
#[doc(hidden)]
pub contents: Term,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to commit to using interning for literals? I'm not sure interning it terrible useful for that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, I can make these fields private again. Definitely not considering stabilizing any of this.

term = { path = "../libterm" }

# not actually used but needed to always have proc_macro in the sysroot
proc_macro = { path = "../libproc_macro" }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be a rustbuild change.

@bjorn3
Copy link
Member

bjorn3 commented Mar 21, 2018

Could you use something like bincode for data bridging, instead of 800 lines of own code?

@eddyb
Copy link
Member Author

eddyb commented Mar 22, 2018

@bjorn3 I'm not serializing the data (but rather using handles), and bincode (like any other serialization) is annoying to use without derived impls (which you can't have because this is proc_macro itself - or at least I don't want to try to make that work, for now).

I am going to look into simplifying the bridge code, removing most unsafe, and making it more amenable to message-passing, however.

@bjorn3
Copy link
Member

bjorn3 commented Mar 22, 2018

I get it.

@alexcrichton

This comment has been minimized.

@eddyb eddyb changed the title Decouple proc_macro from the rest of the compiler. [WIP] Decouple proc_macro from the rest of the compiler. Mar 22, 2018
@eddyb eddyb force-pushed the proc-macro-decouple branch from 6e63e8d to cd9ac21 Compare March 22, 2018 20:07
@eddyb

This comment has been minimized.

@Mark-Simulacrum
Copy link
Member

@eddyb
Copy link
Member Author

eddyb commented Mar 23, 2018

@Mark-Simulacrum It doesn't look bad, that's for sure, thanks! If we switch to spawning a thread (or even a process) per invocation it'd warrant another perf run.

@eddyb eddyb force-pushed the proc-macro-decouple branch from cd9ac21 to 76590d8 Compare March 23, 2018 19:13
Phlosioneer added a commit to Phlosioneer/rust that referenced this pull request Mar 25, 2018
A few tests related to proc-macros fail when performing stage-1
testing. This PR adds // ignore-stage1 to them, along with a FIXME.

Original issue: rust-lang#49352

This should (hopefully) be fixed when rust-lang#49219 is merged.
@aidanhs
Copy link
Contributor

aidanhs commented Mar 26, 2018

Crater run started

@shepmaster shepmaster removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Mar 30, 2018
@aidanhs
Copy link
Contributor

aidanhs commented Mar 31, 2018

Hi @eddyb (crater requester), @Zoxc (PR reviewer)! Crater results are at: http://cargobomb-reports.s3.amazonaws.com/pr-49219/index.html. 'Blacklisted' crates (spurious failures etc) can be found here. If you see any spurious failures not on the list, please make a PR against that file.

(interested observers: Crater is a tool for testing the impact of changes on the crates.io ecosystem. You can find out more at the repo if you're curious)

@petrochenkov
Copy link
Contributor

I can't believe you've done this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.

Projects

None yet

Development

Successfully merging this pull request may close these issues.