|
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