|
1 | 1 | //! Centralized logic for parsing and attributes. |
2 | 2 | //! |
3 | | -//! Part of a series of crates: |
4 | | -//! - rustc_attr_data_structures: contains types that the parsers parse into |
5 | | -//! - rustc_attr_parsing: this crate |
6 | | -//! - (in the future): rustc_attr_validation |
| 3 | +//! ## Architecture |
| 4 | +//! This crate is part of a series of crates that handle attribute processing. |
| 5 | +//! - [rustc_attr_data_structures](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_data_structures/index.html): Defines the data structures that store parsed attributes |
| 6 | +//! - [rustc_attr_parsing](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html): This crate, handles the parsing of attributes |
| 7 | +//! - (planned) rustc_attr_validation: Will handle attribute validation |
7 | 8 | //! |
8 | | -//! History: Check out [#131229](https://github.com/rust-lang/rust/issues/131229). |
9 | | -//! There used to be only one definition of attributes in the compiler: `ast::Attribute`. |
10 | | -//! These were then parsed or validated or both in places distributed all over the compiler. |
11 | | -//! This was a mess... |
| 9 | +//! The separation between data structures and parsing follows the principle of separation of concerns. |
| 10 | +//! Data structures (`rustc_attr_data_structures`) define what attributes look like after parsing. |
| 11 | +//! This crate (`rustc_attr_parsing`) handles how to convert raw tokens into those structures. |
| 12 | +//! This split allows other parts of the compiler to use the data structures without needing |
| 13 | +//! the parsing logic, making the codebase more modular and maintainable. |
12 | 14 | //! |
13 | | -//! Attributes are markers on items. |
14 | | -//! Many of them are actually attribute-like proc-macros, and are expanded to some other rust syntax. |
15 | | -//! This could either be a user provided proc macro, or something compiler provided. |
16 | | -//! `derive` is an example of one that the compiler provides. |
17 | | -//! These are built-in, but they have a valid expansion to Rust tokens and are thus called "active". |
18 | | -//! I personally like calling these *active* compiler-provided attributes, built-in *macros*, |
19 | | -//! because they still expand, and this helps to differentiate them from built-in *attributes*. |
20 | | -//! However, I'll be the first to admit that the naming here can be confusing. |
| 15 | +//! ## Background |
| 16 | +//! Previously, the compiler had a single attribute definition (`ast::Attribute`) with parsing and |
| 17 | +//! validation scattered throughout the codebase. This was reorganized for better maintainability |
| 18 | +//! (see [#131229](https://github.com/rust-lang/rust/issues/131229)). |
21 | 19 | //! |
22 | | -//! The alternative to active attributes, are inert attributes. |
23 | | -//! These can occur in user code (proc-macro helper attributes). |
24 | | -//! But what's important is, many built-in attributes are inert like this. |
25 | | -//! There is nothing they expand to during the macro expansion process, |
26 | | -//! sometimes because they literally cannot expand to something that is valid Rust. |
27 | | -//! They are really just markers to guide the compilation process. |
28 | | -//! An example is `#[inline(...)]` which changes how code for functions is generated. |
| 20 | +//! ## Types of Attributes |
| 21 | +//! In Rust, attributes are markers that can be attached to items. They come in two main categories. |
| 22 | +//! |
| 23 | +//! ### 1. Active Attributes |
| 24 | +//! These are attribute-like proc-macros that expand into other Rust code. |
| 25 | +//! They can be either user-defined or compiler-provided. Examples of compiler-provided active attributes: |
| 26 | +//! - `#[derive(...)]`: Expands into trait implementations |
| 27 | +//! - `#[cfg()]`: Expands based on configuration |
| 28 | +//! - `#[cfg_attr()]`: Conditional attribute application |
| 29 | +//! |
| 30 | +//! ### 2. Inert Attributes |
| 31 | +//! These are pure markers that don't expand into other code. They guide the compilation process. |
| 32 | +//! They can be user-defined (in proc-macro helpers) or built-in. Examples of built-in inert attributes: |
| 33 | +//! - `#[stable()]`: Marks stable API items |
| 34 | +//! - `#[inline()]`: Suggests function inlining |
| 35 | +//! - `#[repr()]`: Controls type representation |
29 | 36 | //! |
30 | 37 | //! ```text |
31 | 38 | //! Active Inert |
32 | 39 | //! ┌──────────────────────┬──────────────────────┐ |
33 | 40 | //! │ (mostly in) │ these are parsed │ |
34 | 41 | //! │ rustc_builtin_macros │ here! │ |
35 | 42 | //! │ │ │ |
36 | | -//! │ │ │ |
37 | 43 | //! │ #[derive(...)] │ #[stable()] │ |
38 | 44 | //! Built-in │ #[cfg()] │ #[inline()] │ |
39 | 45 | //! │ #[cfg_attr()] │ #[repr()] │ |
40 | 46 | //! │ │ │ |
41 | | -//! │ │ │ |
42 | | -//! │ │ │ |
43 | 47 | //! ├──────────────────────┼──────────────────────┤ |
44 | 48 | //! │ │ │ |
45 | | -//! │ │ │ |
46 | 49 | //! │ │ `b` in │ |
47 | 50 | //! │ │ #[proc_macro_derive( │ |
48 | 51 | //! User created │ #[proc_macro_attr()] │ a, │ |
49 | 52 | //! │ │ attributes(b) │ |
50 | 53 | //! │ │ ] │ |
51 | | -//! │ │ │ |
52 | | -//! │ │ │ |
53 | | -//! │ │ │ |
54 | 54 | //! └──────────────────────┴──────────────────────┘ |
55 | 55 | //! ``` |
56 | 56 | //! |
| 57 | +//! ## How This Crate Works |
57 | 58 | //! In this crate, syntactical attributes (sequences of tokens that look like |
58 | 59 | //! `#[something(something else)]`) are parsed into more semantic attributes, markers on items. |
59 | 60 | //! Multiple syntactic attributes might influence a single semantic attribute. For example, |
|
63 | 64 | //! and `#[unstable()]` syntactic attributes, and at the end produce a single |
64 | 65 | //! [`AttributeKind::Stability`](rustc_attr_data_structures::AttributeKind::Stability). |
65 | 66 | //! |
66 | | -//! As a rule of thumb, when a syntactical attribute can be applied more than once, they should be |
67 | | -//! combined into a single semantic attribute. For example: |
| 67 | +//! When multiple instances of the same attribute are allowed, they're combined into a single |
| 68 | +//! semantic attribute. For example: |
68 | 69 | //! |
69 | | -//! ``` |
| 70 | +//! ```rust |
70 | 71 | //! #[repr(C)] |
71 | 72 | //! #[repr(packed)] |
72 | 73 | //! struct Meow {} |
73 | 74 | //! ``` |
74 | 75 | //! |
75 | | -//! should result in a single `AttributeKind::Repr` containing a list of repr annotations, in this |
76 | | -//! case `C` and `packed`. This is equivalent to writing `#[repr(C, packed)]` in a single |
77 | | -//! syntactical annotation. |
| 76 | +//! This is equivalent to `#[repr(C, packed)]` and results in a single `AttributeKind::Repr` |
| 77 | +//! containing both `C` and `packed` annotations. |
78 | 78 |
|
79 | 79 | // tidy-alphabetical-start |
80 | 80 | #![allow(internal_features)] |
|
0 commit comments