-
-
Notifications
You must be signed in to change notification settings - Fork 15.3k
Introduce string_enum!; migrate lint Level and other CLI flag enums #158123
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
Open
palozano
wants to merge
9
commits into
rust-lang:main
Choose a base branch
from
palozano:feat/lint-level-string-enum
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
6d81ea7
refactor(session): add `string_enum!` macro for CLI flag enums
palozano 85d6812
refactor(session): use `string_enum!` for `-C`/`-Z` value enums, stru…
palozano 18da8e7
refactor(session): extend `string_enum!` for aliases, migrate `DebugI…
palozano 9f71dd8
refactor(session): migrate `CFProtection` with bool+none parse helper
palozano 0febf23
refactor(session): migrate `Polonius`, `InstrumentCoverage`, `LtoCli`
palozano 2ca741a
refactor(session): support discriminants in `string_enum!`, migrate `…
palozano ec4b36f
refactor(data_structures): extend `string_enum!` with `@no_from_str`
palozano c6adebd
refactor(lint_defs): migrate `Level` to `string_enum!`
palozano 5f28a62
refactor(data_structures): generate `FROM_STR_VARIANTS` in `string_en…
palozano File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,145 @@ | ||
| /// Like an enum, but the variants are tied to a string representation. | ||
| /// | ||
| /// Each variant is declared in one of three forms: | ||
| /// * `Variant => "primary"` — single canonical CLI string. | ||
| /// * `Variant => "primary" | "alias1" | "alias2"` — canonical string plus | ||
| /// one or more aliases that also parse to this variant. `to_str` and | ||
| /// `Display` return the canonical form. | ||
| /// * `Variant` (no `=>`) — the variant exists in the enum but has no CLI | ||
| /// string representation. Reachable only by code that produces the value | ||
| /// directly (e.g. a parser handling no-value or boolean fallthrough). | ||
| /// Calling `to_str` or `Display` on such a variant panics, and `FromStr` | ||
| /// will not produce it. | ||
| /// | ||
| /// Any variant may also carry an explicit discriminant | ||
| /// (`Variant = N` or `Variant = N => "primary"`), forwarded verbatim to | ||
| /// the generated enum. Use this when the discriminant values are | ||
| /// load-bearing (e.g. encoded on the wire or stable-hashed). | ||
| /// | ||
| /// Variants with a CLI string may also be marked `@no_from_str` | ||
| /// (`Variant => "primary" @no_from_str`), which makes the string | ||
| /// available to `to_str`/`Display` but excludes it from `FromStr`. | ||
| /// Use this for variants that have a textual identity for display | ||
| /// purposes but should not be constructible from untrusted user input | ||
| /// (e.g. variants that require out-of-band context to build correctly). | ||
| /// Such variants still appear in `STR_VARIANTS`/`ALL_STR_VARIANTS`; | ||
| /// callers that want only the strings the user is allowed to supply | ||
| /// should use `FROM_STR_VARIANTS` instead. | ||
| /// | ||
| /// Generates: | ||
| /// * `VARIANTS` — every variant, in declaration order. | ||
| /// * `STR_VARIANTS` — canonical string of each variant that has one, in | ||
| /// declaration order. | ||
| /// * `ALL_STR_VARIANTS` — every accepted string (canonical + aliases) in | ||
| /// declaration order. Use this when help text should list all accepted | ||
| /// forms. | ||
| /// * `FROM_STR_VARIANTS` — canonical string of each variant whose canonical | ||
| /// string is accepted by `FromStr` (i.e. `STR_VARIANTS` minus any variant | ||
| /// marked `@no_from_str`). Use this in diagnostics that list the inputs | ||
| /// the user is actually allowed to supply. | ||
| /// * `to_str()`, `Display`, `FromStr`. `FromStr::Err` is `()` because | ||
| /// diagnostic emission is handled by the caller. | ||
| #[macro_export] | ||
| macro_rules! string_enum { | ||
| ( | ||
| $(#[$meta:meta])* | ||
| $vis:vis enum $name:ident { | ||
| $( | ||
| $(#[$variant_meta:meta])* | ||
| $variant:ident $( = $disc:expr )? | ||
| $( => $repr:literal $( | $alias:literal )* | ||
| $( @ $no_from_str:ident )? )? , | ||
| )* | ||
| } | ||
| ) => { | ||
| $(#[$meta])* | ||
| $vis enum $name { | ||
| $( | ||
| $(#[$variant_meta])* | ||
| $variant $( = $disc )?, | ||
| )* | ||
| } | ||
|
|
||
| impl $name { | ||
| #[allow(dead_code)] | ||
| $vis const VARIANTS: &'static [Self] = &[ | ||
| $( Self::$variant, )* | ||
| ]; | ||
| #[allow(dead_code)] | ||
| $vis const STR_VARIANTS: &'static [&'static str] = &[ | ||
| $( $( $repr, )? )* | ||
| ]; | ||
| #[allow(dead_code)] | ||
| $vis const ALL_STR_VARIANTS: &'static [&'static str] = &[ | ||
| $( $( $repr, $( $alias, )* )? )* | ||
| ]; | ||
| #[allow(dead_code)] | ||
| $vis const FROM_STR_VARIANTS: &'static [&'static str] = | ||
| $crate::__string_enum_from_str_arr!( | ||
| @collect [] | ||
| $( $( $repr $( @ $no_from_str )? , )? )* | ||
| ); | ||
|
|
||
| #[allow(unreachable_patterns)] | ||
| $vis const fn to_str(&self) -> &'static str { | ||
| match self { | ||
| $( $( Self::$variant => $repr, )? )* | ||
| _ => panic!("variant has no CLI string representation"), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl ::std::fmt::Display for $name { | ||
| fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { | ||
| ::std::fmt::Display::fmt(self.to_str(), f) | ||
| } | ||
| } | ||
|
|
||
| impl ::std::str::FromStr for $name { | ||
| type Err = (); | ||
|
|
||
| #[allow(unreachable_code)] | ||
| fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
| match s { | ||
| $( $( $repr $( | $alias )* => { | ||
| $( | ||
| $crate::__string_enum_check_no_from_str!($no_from_str); | ||
| return Err(()); | ||
| )? | ||
| Ok(Self::$variant) | ||
| }, )? )* | ||
| _ => Err(()), | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// Validates that a `string_enum!` variant's `@`-marker is spelled exactly | ||
| /// `no_from_str`. Used internally by [`string_enum!`]; not part of the public | ||
| /// surface. | ||
| #[doc(hidden)] | ||
| #[macro_export] | ||
| macro_rules! __string_enum_check_no_from_str { | ||
| (no_from_str) => {}; | ||
| } | ||
|
|
||
| /// Builds a `&[&str]` literal containing only the canonical strings of | ||
| /// variants accepted by `FromStr`. Token-tree munches a comma-terminated | ||
| /// stream of `$repr` (or `$repr @ no_from_str`) entries into an accumulator, | ||
| /// then emits the full slice literal in one go — needed because in | ||
| /// expression position a macro must expand to a single expression. Used | ||
| /// internally by [`string_enum!`]; not part of the public surface. | ||
| #[doc(hidden)] | ||
| #[macro_export] | ||
| macro_rules! __string_enum_from_str_arr { | ||
| (@collect [$($acc:literal,)*]) => { | ||
| &[ $($acc,)* ] | ||
| }; | ||
| (@collect [$($acc:literal,)*] $repr:literal @ no_from_str , $($rest:tt)*) => { | ||
| $crate::__string_enum_from_str_arr!(@collect [$($acc,)*] $($rest)*) | ||
| }; | ||
| (@collect [$($acc:literal,)*] $repr:literal , $($rest:tt)*) => { | ||
| $crate::__string_enum_from_str_arr!(@collect [$($acc,)* $repr,] $($rest)*) | ||
| }; | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if this assoc const pulls its weight. After all, this information can be obtained via
Self::VARIANTS.iter().map(Self::to_str).collect::<Vec<_>>()which isn't that expensive.I'd say the fewer things we macro-generate the better to avoid negatively impacting compile times of rustc itself.
View changes since the review
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point.
STR_VARIANTS's only use here was thatprint_requestline (now inlined).ALL_STR_VARIANTS/FROM_STR_VARIANTSaren't used in this PR at all — only by later PRs in the stack. I'll move their generation (plus@no_from_strand theFROM_STR_VARIANTScommit) down to the PR that first needs them, leaving #158123 as just the macro core + migrations. Sound good?