Skip to content
New issue

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

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

Already on GitHub? # 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
# for free to join this conversation on GitHub. Already have an account? # 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