Macros 1.2: Stabilization Status Update


#1

Hey all! It’s been some time now since Help stabilize a subset of Macros 2.0!, and a lot has happened in the meantime. I’d like to both try to collect my own thoughts about this here as well as try to post a general status update on the stabilization of a “macros 1.2” and the current open questions.

FCP for stable

Two primary features have gone through FCP for stability:

At the time of FCP proposal I wrote a detailed design of what’s to become stable and here’s a gist if you don’t want to load the whole comment thread. As of this writing the proposed design here has not changed. Some snags, however, have been hit along the way which have held up stabilization.

Internal helpers for macro_rules!

This is an issue that we discovered as a sort of late-breaking bug. Immactulately articulated by @dtolnay the bug here is with crates that have internal helpers for exported macro_rules! macros. I won’t go too much into the details of the bug here (@dtolnay did a great job in his writeup), so it’s sufficient to say that two bugs were discovered here:

  • First, existing macros aren’t compatible with use. This has now been solved with a new #[macro_export(local_inner_macros)] attribute. This is planned to become stable in the 1.30.0 release (today’s nightly is 1.29.0) pending any major bugs coming up.
  • Second, the recommended fix on the 2018 edition is to use $crate::__foo_internal!(). This however does not work for the defining crate, it only works across crates. At this point it looks like we’re going to stabilize this behavior and consider this a bugfix to fix in a future release.

As a result, internal helpers in macro_rules! are resolved and fixes are in nightly, we’re just waiting another cycle before stabilization to ensure that the new local_inner_macros attribute has time to stabilize.

Bugs in procedural macros

Procedural macros have been in the compiler for quite some time now, and throughout this time they’ve acrrued quite the number of interesting corner cases and such. There’s a category for these bugs on our issue tracker and some are tagged as A-macros-1.2 to block 1.2 as well, but otherwise many of these are existing bugs in custom derive or don’t affect behavior that’s stabilizing.

Some of the more notorious bugs are:

  • #50504 - proc_macro! expansion can refer to items defined in the root w/o importing them (fixed in #51952)
  • #52219 - #![feature(proc_macro)] breaks some custom derive attributes (fixed in #52230)
  • #52225 - Procedural macro crates should require at most one definition per macro name (fixed in #52383)
  • #52226 - Ambiguity between custom derive attributes and proc macro attributes
    • More discussion on the issue, this is very new and not fully understood to me yet what fix is in scope.
  • #52269 - interaction between built-in and custom derives via shadowing is unclear

Stabilization

There’s two aspects that need to be stabilized here. The first is the new proc_macro crate APIs as well as the new attributes that can be defined in #![crate_type = "proc-macro"] crates. This is being done in #52081.

The second is use_extern_macros, the ability to use macros with the module system. This is being done in #50911. This itself can be theoretically split into two pieces as well, one where macro_rules! is integrated with the module system and one where custom attributes/procedural macros are integrated. The former (macro_rules!) is blocked on giving local_inner_macros another cycle to bake. The latter (procedural macros) should be stabilizable once some of the above bugs have been sorted out.


My goal is that we’re still on track for the 2018 edition for sure with both procedural macros and macro_rules!-via-the-module-system. My hope is to land procedural macros in the 1.29 release (current nightly) and the remaining macro_rules! pieces during the 1.30 release. This depends on issues that arise, however!

In any case if I’m missing something here please let me know! I’ll try to keep this updated as we approach the 1.29 release and 1.30.


#2

cc @dtolnay @petrochenkov @nrc @jseyfried


#3

Introduction of a new namespace (macro namespace in this case) is a single indivisible event.
We can’t tweak contents of namespaces without introducing breaking changes (i.e. creating name conflicts, or indeterminacy in case of adding new names).
Namespaces were slightly tweaked in the past (e.g. https://github.com/rust-lang/rust/pull/30882), but such tweaks were always accompanied by breaking changes.

In this sense I’d prefer not to rush for stabilizing macro namespace (aka feature(use_extern_macros), which is a bit a misnomer) into a specific release if it would require such a split.
(I pushed for landing https://github.com/rust-lang/rust/pull/50911 sooner myself, but that was because I thought everything is fixed and didn’t realize that single-segment attributes need more future-proofing).
Right now work is happening steadily, PRs are landed, bugs are being fixed. I just want to do everything carefully and once it’s ready, it’s ready. For 1.30 for sure, for 1.29 - 50/50. “Saved a minute, lost a life” like they write on train stations :slight_smile:


#4

Things that needs to be done for “closing” the macro namespace:

  • https://github.com/rust-lang/rust/issues/52225 (very minor issue, EDIT: fixed in https://github.com/rust-lang/rust/pull/52383).
  • Modularization of crate-local #[macro_export] macro_rules (https://github.com/rust-lang/rust/pull/50911#issuecomment-401151270).
    I almost have this ready for crater run and wanted to submit a PR today, but was distracted by reading all the posts that @alexcrichton and @alercah wrote today. EDIT: https://github.com/rust-lang/rust/pull/52234
  • Always resolving #[my_attr] as a proc macro first and then falling back to built-in attributes and perhaps inert derive attributes (i.e. treat them as a prelude). This is the required “future proofing”, but also the desired end goal (that’s how the rest of name resolution works). (Multi-segment attributes including tool attributes still can be stabilized separately later).
  • Figure out how exactly derive attributes fit into attribute resolution. They still need to use one of mechanisms standard to all name resolution - name in module, name in scope, prelude. I think, In this case future-proofing and the desired end goal will also coincide.

#5

Ok that makes sense to me, thanks for expanding!


#6

Another update! (OP updated slightly as well)

Current work:

  • PR #52081 - will stabilize library APIs in proc_macro, but procedural macros are still not stable until use_extern_macros is stabilized. This is approved and should land soon.
  • PR #52234 - enables $crate::foo!() within the crate that defines foo!. Blocked on an FCP proposal
  • Issue #52226 - ambiguity between procedural macro attributes and custom derive custom attributes
  • Issue #52269 - unclear interaction between built-in derive modes and shadowing with custom derive
  • PR #50911 - will stabilize use_extern_macros, but is blocked on all above issues/PRs