Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tracking issue for macro attributes in #[derive] output #81119

Closed
petrochenkov opened this issue Jan 17, 2021 · 0 comments · Fixed by #87220
Closed

Tracking issue for macro attributes in #[derive] output #81119

petrochenkov opened this issue Jan 17, 2021 · 0 comments · Fixed by #87220
Assignees
Labels
A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC

Comments

@petrochenkov
Copy link
Contributor

petrochenkov commented Jan 17, 2021

This is a tracking issue for macro attributes that can observe output of the #[derive] attribute.
This includes macro attributes on the same item as #[derive] but below it, and macro attributes on nested nodes of the item with #[derive].

#[derive] fully configures its input, eagerly evaluating cfgs everywhere in its target, for example on fields.
Attributes expanded after the #[derive] will see the item in this fully configured form, but we don't want expose it to them on stable channel for now.

Example:

#[derive(Trait)]
#[my_attr] // Gated
struct S1 {
    field: [u8; 10],
}

#[derive(Trait)]
struct S2 {
    field: [u8; #[my_attr] 10], // Gated
}

The feature name is macro_attributes_in_derive_output.
The feature gate was introduced in #79078.

@camelid camelid added A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC labels Jan 18, 2021
bors added a commit to rust-lang-ci/rust that referenced this issue Feb 7, 2021
expand/resolve: Turn `#[derive]` into a regular macro attribute

This PR turns `#[derive]` into a regular attribute macro declared in libcore and defined in `rustc_builtin_macros`, like it was previously done with other "active" attributes in rust-lang#62086, rust-lang#62735 and other PRs.
This PR is also a continuation of rust-lang#65252, rust-lang#69870 and other PRs linked from them, which layed the ground for converting `#[derive]` specifically.

`#[derive]` still asks `rustc_resolve` to resolve paths inside `derive(...)`, and `rustc_expand` gets those resolution results through some backdoor (which I'll try to address later), but otherwise `#[derive]` is treated as any other macro attributes, which simplifies the resolution-expansion infra pretty significantly.

The change has several observable effects on language and library.
Some of the language changes are **feature-gated** by [`feature(macro_attributes_in_derive_output)`](rust-lang#81119).

#### Library

- `derive` is now available through standard library as `{core,std}::prelude::v1::derive`.

#### Language

- `derive` now goes through name resolution, so it can now be renamed - `use derive as my_derive; #[my_derive(Debug)] struct S;`.
- `derive` now goes through name resolution, so this resolution can fail in corner cases. Crater found one such regression, where import `use foo as derive` goes into a cycle with `#[derive(Something)]`.
- **[feature-gated]** `#[derive]` is now expanded as any other attributes in left-to-right order. This allows to remove the restriction on other macro attributes following `#[derive]` (rust-lang/reference#566). The following macro attributes become a part of the derive's input (this is not a change, non-macro attributes following `#[derive]` were treated in the same way previously).
- `#[derive]` is now expanded as any other attributes in left-to-right order. This means two derive attributes `#[derive(Foo)] #[derive(Bar)]` are now expanded separately rather than together. It doesn't generally make difference, except for esoteric cases. For example `#[derive(Foo)]` can now produce an import bringing `Bar` into scope, but previously both `Foo` and `Bar` were required to be resolved before expanding any of them.
- **[feature-gated]** `#[derive()]` (with empty list in parentheses) actually becomes useful. For historical reasons `#[derive]` *fully configures* its input, eagerly evaluating `cfg` everywhere in its target, for example on fields.
Expansion infra doesn't do that for other attributes, but now when macro attributes attributes are allowed to be written after `#[derive]`, it means that derive can *fully configure* items for them.
    ```rust
	#[derive()]
	#[my_attr]
	struct S {
		#[cfg(FALSE)] // this field in removed by `#[derive()]` and not observed by `#[my_attr]`
		field: u8
	}
    ```
- `#[derive]` on some non-item targets is now prohibited. This was accidentally allowed as noop in the past, but was warned about since early 2018 (rust-lang#50092), despite that crater found a few such cases in unmaintained crates.
- Derive helper attributes used before their introduction are now reported with a deprecation lint. This change is long overdue (since macro modularization, rust-lang#52226 (comment)), but it was hard to do without fixing expansion order for derives. The deprecation is tracked by rust-lang#79202.
```rust
    #[trait_helper] // warning: derive helper attribute is used before it is introduced
    #[derive(Trait)]
    struct S {}
```

Crater analysis: rust-lang#79078 (comment)
@petrochenkov petrochenkov self-assigned this Mar 1, 2021
@bors bors closed this as completed in 60fe8b3 Sep 25, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC
Projects
None yet
2 participants