Moving procedural macros & lints out of the compiler


#1

I’ve seen this loosely tossed around but I haven’t seen any concrete discussion (maybe I missed it). We can now load macros and lints from external crates, so we can theoretically have none of these hardcoded into the compiler.

Concrete proposal:

  • move syntax::ext::* (except base, build and expand) to librustc_macros
  • move rustc::lint::builtin to librustc_lints
  • have the compiler insert #[phase(plugin)] extern crate librustc_lints; #[phase(plugin)] extern crate librustc_macros; at the same time as it inserts extern crate std
  • possibly provide a way to opt-out, although there is currently no way to opt-out, and this change would not impose any additional runtime dependencies on the generated executables. In any case, it’s very desirable to have lints in #[no_std] code so if an opt-out is provided, it should not be reusing the #[no_std] attribute.

This should just be an internal change which is not meaningfully user-visible. The benefits include faster iteration times, since these crates depend on libsyntax/librustc (resp.) but not vice versa, so changes to macros and lints do not need to spend time doing the slowest part of the bootstrap (that is, make after a change to a lint will just need to build stage0 rustc_lints and then immediately start on the stage1 libraries).

Unfortunately, this may have staging issues, and possibly even problems with (soon to be removed) rpaths, due to the dynamically loading.


#2

I’m pretty sure there will be staging issues, but they’re issues we really should be solving (assuming they’re actually solvable). It feels kind of dirty to have to disable all procedural macro tests at stage1.


#3

We should do the same with the deriving macros. In order to do that though it would be ideal if a 3rd party could register a new deriving extension. That would mean this libderiving would then have to have some context that’s threaded through all the calls to #[deriving(Foo,Bar)].

Anyone know of a good way to do that without just throwing it into libsyntax’s ExtContext? Maybe putting in TLS would work, or possibly we could borrow iron’s middleware design to store that context data.


#5

Niko had a suggestion that #[deriving(Foo)] could just expand to a #[deriving_Foo] attribute.


#6

What if it actually expanded to an attribute with an identifier of "deriving(Foo)"? This way you can register your syntax extension with that name and it would work. Then when printing attributes, all attributes of that form with the same “base” name (e.g. deriving) would be combined into a single displayed attribute, to match how it’s expressed in code.

Or instead of actually literally transforming attributes like that, the item decorator/modifier machinery could instead just learn to treat things like deriving(Foo, Bar) as a sequence of fake attributes deriving(Foo), deriving(Bar) and invoke the syntax extensions that registered those names.