Introduce string_enum!; migrate lint Level and other CLI flag enums#158123
Introduce string_enum!; migrate lint Level and other CLI flag enums#158123palozano wants to merge 9 commits into
Conversation
|
Some changes occurred in compiler/rustc_hir/src/attrs cc @jdonszelmann, @JonathanBrouwer Some changes occurred in exhaustiveness checking cc @Nadrieril
cc @rust-lang/clippy |
|
Thanks for the pull request, and welcome! The Rust Project is excited to review your changes, and you should hear from @mejrs (or someone else) some time within the next two weeks. Please see the contribution instructions for more information. Namely, in order to ensure the minimum review times lag, PR authors and assigned reviewers should ensure that the review label (
Why was this reviewer chosen?The reviewer was selected based on:
|
|
This comment has been minimized.
This comment has been minimized.
This commit adds the infrastructure to unify them and migrates `PrintKind` as the first user: * `rustc_data_structures::string_enum!` -- a macro adapted from compiletest. Co-locates each variant with its CLI string and generates `VARIANTS`, `STR_VARIANTS`, `to_str()`, `Display`, and `FromStr`. Single source of truth per CLI enum. * `rustc_session::config::build_unknown_arg_value_diag` -- helper taking the flag label, the bad value, and the valid-values slice; returns an un-emitted `Diag<'_, FatalAbort>` with the shape ``"unknown <label>: `x`"`` + `"valid <label>s are: ..."` so callers can attach extra help notes before emit. * `PrintKind` migrated to `string_enum!`. Its inherent `name()`, custom `Display`, and `from_str()` are replaced by the macro's output; `emit_unknown_print_request_help` becomes a thin call to the shared helper plus PrintKind's `lints` hint and rustc-book link. The `--print` diagnostic is byte-identical to before, so existing UI and run-make fixtures (`tests/ui/compile-flags/invalid/print.stderr`, `tests/ui/print-request/print-lints-help.stderr`, `tests/run-make/print-request-help-stable-unstable/*.err`) need no re-blessing. Follow-up MRs will migrate more CLI enums (`lint::Level`, `CrateType`, `OutputType`) and reshape the -C/-Z option dispatcher to use the same helper.
…cture diagnostic
Builds on the `string_enum!` infrastructure to wire valid-values into the
`-C`/`-Z` option dispatcher and migrate the first batch of clean-fit value
enums.
The dispatcher in `options.rs` previously emitted a single-line error on
bad input ("incorrect value `x` for codegen option `y` - <type_desc> was
expected") with no structured help. This commit adds an opt-in path that
splits the diagnostic into a title plus a `help:` line listing the valid
values, matching the structured shape used by `--print` (and now
`build_unknown_arg_value_diag`):
* `OptionDesc` gains a `valid_values: Option<&'static [&'static str]>`
field. The `options!` macro accepts an optional `[VALUES: <expr>]`
marker after `[TRACKED]`/`[UNTRACKED]`, populated from the enum's
`STR_VARIANTS`. Non-migrated options keep the old single-line wording
unchanged.
* New `build_unknown_option_value_diag` helper in `rustc_session::config`
produces the dispatcher's structured diagnostic. Preserves the
existing title ("incorrect value `x` for codegen option `y`") and moves
the per-parser vocabulary into a `valid values are: ...` help line.
* New generic `parse::parse_string_enum<T: FromStr<Err = ()>>` helper.
Each migrated parser collapses from a hand-written `match v` body to a
single delegating call.
Five enums are migrated to `string_enum!` form and gain `[VALUES: ...]`
in their option declarations: `Strip` (`-C strip`), `FmtDebug`
(`-Z fmt-debug`), `DebugInfoCompression` (`-Z debuginfo-compression`),
`MirStripDebugInfo` (`-Z mir-strip-debuginfo`), `FunctionReturn`
(`-Z function-return`). Their per-variant CLI strings now live in a
single source of truth.
Only one UI fixture is affected (`tests/ui/fmt/fmt_debug/invalid.stderr`);
re-blessed to match the new structured shape. The other ~21 "incorrect
value" fixtures across the suite are untouched because their parsers
don't opt into `[VALUES: ...]`.
Follow-ups: enums with bool fallthrough (`InstrumentCoverage`, `LtoCli`,
`CollapseMacroDebuginfo`), variants with multiple accepted strings
(`DebugInfo`, `CFGuard`, `CFProtection`), and `Polonius` (where the
no-value case maps to a non-default variant) need an extension to
`string_enum!` for aliases/bool handling before they can migrate.
…nfo` Extends the `string_enum!` macro so a variant can declare multiple accepted CLI strings, and migrates `DebugInfo` (`-C debuginfo`) which takes numeric and named forms of the same value (`0`/`none`, `1`/`limited`, `2`/`full`). * `string_enum!` accepts `Variant => "primary" | "alias1" | "alias2"`. The first string is the canonical form returned by `to_str` and `Display`; all forms parse via `FromStr`. The `$repr` fragment moves from `:expr` to `:literal` so the `|`-separated alias list parses in the macro definition. * New generated const `ALL_STR_VARIANTS` exposes every accepted string (canonical + aliases) in declaration order. `STR_VARIANTS` keeps its existing meaning (one canonical per variant). Option declarations that want the full vocabulary in the "valid values are: ..." help line opt into `ALL_STR_VARIANTS`; others stay on `STR_VARIANTS`. * `DebugInfo` migrated to `string_enum!` form with five variants and four aliases. `parse_debuginfo` collapses to a single `parse_string_enum` call. The option declaration opts into `[VALUES: DebugInfo::ALL_STR_VARIANTS]`, preserving the `0`/`1`/`2` numeric forms in the error diagnostic. Drive-by: removes `compiler/rustc_session/src/macros.rs` (and its `mod` declaration plus the `macro_derive` feature gate), which were orphaned when the previous commit migrated `PrintKind` away from the `AllVariants` derive. No UI fixtures need re-blessing — there are no existing tests for bad `-Cdebuginfo` values.
Adds a small generic helper for the "bool fallthrough + no-value mapping + string match" parser shape shared by several `-C`/`-Z` enums, and migrates `CFProtection` as the first user. * `parse::parse_string_enum_with_bool<T: FromStr<Err = ()>>` — accepts `Option<T>` mappings for the no-value, bool-true, and bool-false cases; falls back to `T::from_str` for explicit string values. Each mapping can be `None` to reject that input shape. * `CFProtection` migrated to `string_enum!` form (all four variants have canonical strings). `parse_cfprotection` collapses from a hand-written `match v` body to a single helper call. The option declaration is not opted into `[VALUES: ...]` — the existing `parse_cfprotection` `type_desc` lists the bool aliases (`yes`/`y`/`no`/`n`) that `STR_VARIANTS` doesn't include, so the old single-line diagnostic preserves more information than the structured one would.
Continues the `string_enum!`/`parse_string_enum_with_bool` rollout, applying the now-complete helper set to the remaining clean-fit `-C`/`-Z` enums in `rustc_session`. * `Polonius` — `Off` is bare (only the default when the flag is not passed); `Legacy`/`Next` keep canonical strings. `parse_polonius` passes `None` for both bool slots — the helper still attempts bool parsing, but unmapped successes fall through to `FromStr`, which rejects `yes`/`no`/etc. Behavior preserved. * `InstrumentCoverage` — both variants are reachable via bool fallthrough; the historical aliases `"0"` and `"all"` become the canonical strings for `No` and `Yes`. The comment about these being "currently just aliases for boolean values" is dropped — the enum declaration now carries that information directly. * `LtoCli` — `No`/`Yes`/`NoParam`/`Unspecified` are bare; `Thin`/`Fat` keep canonical strings. None of the three opts into `[VALUES: ...]` — the legacy `type_desc` strings on these options carry boolean-alias and no-value hints that `STR_VARIANTS` doesn't. The one existing UI fixture (`tests/ui/instrument-coverage/bad-value.*.stderr`) stays on the legacy diagnostic shape and needs no re-blessing.
…CollapseMacroDebuginfo` Closes out the deferred-followups list from the `string_enum!` rollout: extends the macro to accept explicit variant discriminants and migrates the last remaining enum — `CollapseMacroDebuginfo`, which lives in `rustc_hir` and whose discriminant values are load-bearing for the wire encoding. * `string_enum!` accepts an optional `= $disc:expr` between the variant ident and the optional `=> "primary"`. The discriminant is forwarded verbatim to the generated enum body; all other emitted code (`VARIANTS`, `STR_VARIANTS`, `ALL_STR_VARIANTS`, `to_str`, `FromStr`) is unchanged. * `CollapseMacroDebuginfo` migrated. Discriminants (`= 0`, `= 1`, `= 2`, `= 3`) preserved exactly — they're encoded by `Encodable`/`Decodable` and hashed by `StableHash`/`PrintAttribute`, so any drift would be a breaking change to on-disk artifacts. `External` keeps its `"external"` CLI string; `No`, `Unspecified`, and `Yes` are bare (reachable only via boolean fallthrough or as the default sentinel). `parse_collapse_macro_debuginfo` collapses to a single `parse_string_enum_with_bool` call. The option is not opted into `[VALUES: ...]` — same reasoning as the other bool-fallthrough migrations: `STR_VARIANTS` would only list `"external"`, dropping the boolean aliases that `type_desc` currently mentions. No UI fixtures need re-blessing. With this, every `-C`/`-Z` enum named in the original `string_enum!`-rollout follow-ups list has been migrated.
Adds a per-variant marker that decouples a variant's display string from its parseability. Motivated by enums where some variants carry a textual identity used for display and diagnostic output, but must not round-trip through `FromStr` because constructing them correctly requires out-of-band context the parser doesn't have (e.g. an expectation id, or "this can only come from the CLI, not an attribute"). Previously such enums couldn't adopt `string_enum!` without regressing the `from_str` guard; they had to keep a hand-written impl. * New syntax: a variant with a CLI string may be suffixed with `@no_from_str` after the `"primary"` (and any `| "alias"`) strings, e.g. `Variant => "primary" @no_from_str`. The marker is optional and per-variant. * Generated code: `@no_from_str` variants are emitted into `to_str`/`Display`/`STR_VARIANTS`/`ALL_STR_VARIANTS` exactly as before — their string is still the canonical display form. Their arm in the generated `FromStr` matches the string but returns `Err(())` instead of `Ok(Self::Variant)`, so user input naming the variant is rejected rather than silently parsed. * Spelling check: the marker keyword is validated through a hidden `__string_enum_check_no_from_str!` helper that only accepts the literal token `no_from_str`. A typo (`@no_from_st`, `@noFromStr`, …) is a compile error at the macro call site rather than a silently-ignored token. * Doc comment on `string_enum!` updated to describe the new marker, including the caveat that `STR_VARIANTS` still lists these variants — callers needing a parseable-only view must filter through `FromStr` themselves.
Removes the hand-written `as_str`/`from_str` pair on
`rustc_lint_defs::Level` in favour of the impls generated by
`string_enum!`. Uses the `@no_from_str` marker introduced in the
previous commit to preserve the existing parse-time guard: `Expect`
and `ForceWarn` remain emittable by `to_str`/`Display` but are
rejected by `FromStr`, because constructing them requires context
the string itself can't supply (a `LintExpectationId` for `Expect`,
and "this came from the CLI, not an attribute" for `ForceWarn`).
* `Level` migrated. Variant order, derives, and per-variant
doc comments preserved verbatim. `"allow"`/`"warn"`/`"deny"`/
`"forbid"` round-trip through both `to_str` and `FromStr`;
`"expect"` and `"force-warn"` go out via `to_str` only.
* `from_symbol` and `from_opt_symbol` are kept as-is. They predate
this macro, match on variants directly rather than via strings,
and are not part of the `string_enum!` surface — no behavioural
change.
* Call sites updated mechanically:
- `Level::as_str()` → `Level::to_str()` in `rustc_driver_impl`
(`--print=lints` + `describe_lints`), `rustc_errors::json`
(unused-extern emission), `rustc_lint::levels` (overruled-
attribute diagnostics, ignored-unless-crate-specified),
`rustc_middle::lint` (default-source and implied-by notes),
and `rustc_pattern_analysis::lints`
(non-exhaustive-omitted-patterns).
- `Level::from_str(&cap)` in `rustc_session::config::get_cmd_lint_options`
becomes `cap.parse::<Level>()`, picking up the `FromStr` impl
generated by the macro. Error type changes from `Option<Level>`
to `Result<Level, ()>`; the surrounding `unwrap_or_else` is
updated to take `|()|`.
No behavioural change: the set of accepted/rejected `--cap-lints`
values is identical, and every diagnostic that embeds a level
string emits the same text as before.
…um!` Adds a third generated constant alongside `STR_VARIANTS`/`ALL_STR_VARIANTS`: the canonical strings of variants accepted by `FromStr` (i.e. `STR_VARIANTS` minus any variant marked `@no_from_str`). Use it in "valid values are: …" diagnostics so the list cannot drift from the parser. Implemented with a TT-munching accumulator since a macro in expression position must expand to a single expression.
848ddb1 to
7a3a58b
Compare
|
The job Click to see the possible cause of the failure (guessed by this bot) |
Description
string_enum!macro inrustc_data_structuresand extends it with aliases,@no_from_str, explicit discriminants, andFROM_STR_VARIANTS.PrintKind,Level,DebugInfo,Polonius,InstrumentCoverage,LtoCli,CFProtection,CollapseMacroDebuginfo,Strip,CFGuard, …) and removes theAllVariantsderive.AllVariants& generated assoc constALL_VARIANTSfor CLI error+help messages #155677.Part of #155677. It's a collection of stacked PRs described in the issue.
Commit history
string_enum!macro for CLI flag enumsstring_enum!for-C/-Zvalue enums, structure diagnosticstring_enum!for aliases, migrateDebugInfoCFProtectionwith bool+none parse helperPolonius,InstrumentCoverage,LtoClistring_enum!, migrateCollapseMacroDebuginfostring_enum!with@no_from_strLeveltostring_enum!FROM_STR_VARIANTSinstring_enum!