-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
rustc_macros
: Make it possible to derive both Diagnostic
and LintDiagnostic
on the same type
#125169
Comments
I'll probably investigate getting rid of cc @nnethercote |
Yep, I think that |
Ah, that's annoying. We can't simply leverage rust/compiler/rustc_middle/src/lint.rs Lines 333 to 351 in 4eedf73
By the way, I've already migrated all lint diagnostic structs to the new system. The only solution I see is adding a |
Right now, my patched rustc fails to build std because of that >.< |
…r=<try> Make lint diagnostics responsible for providing their primary span ### Summary and Rustc-Dev-Facing Changes Instead of passing the primary span of lint diagnostics separately — namely to the functions `tcx.emit_span_lint` and `tcx.emit_node_span_lint` —, make lint diagnostics responsible for “storing” (providing) their span. I've removed the two aforementioned methods. You are now expected to use `tcx.emit_lint` and `tcx.emit_node_lint` respectively and to provide the primary span when deriving `LintDiagnostic` (via `#[primary_span]`) / implementing `LintDiagnostic` manually (via `LintDiagnostic::span`). ### Motivation Making the general format of `#[derive(LintDiagnostic)]` identical to `#[derive(Diagnostic)]`. I bet this has lead to slight confusion or annoyances before. Moreover, it enables deriving both traits at once (see rust-lang#125169 for the motivation). ### Approach As outlined in rust-lang#125169 (comment), the naïve approach of doing the same as `Diagnostic` doesn't work for `LintDiagnostic`, i.e., setting the primary span with `Diag::span` inside `decorate_lint` (that's `into_diag` for `Diagnostic`) because `lint_level` (`lint_level_impl`) needs access to the primary spans before decorating the `Diag` to be able to filter out some lints (namely if they come from an external macro) etc. Therefore, I had to introduce a new method to `LintDiagnostic`: `fn span(&self) -> Option<MultiSpan>` (similar to the existing method `LintDiagnostic::msg`). ### Commits 1. The 1st commit addresses [rust-lang#125169 (comment)](rust-lang#125169 (comment)). It contains the necessary changes to the linting APIs. It doesn't build on its own due to the removed APIs. Split out for easier reviewing. 2. The 2nd commit updates all existing lint diagnostics to use the new APIs. Most of them are mindless, monotonous, obvious changes. Some changes are *slightly* more involved out of necessity. I've verified (partly programmatically, partly manually) that all lint diags that used to have a primary span still have a primary span. 3. The 3rd commit updates the fulldeps UI tests that exercise the (lint) diagnostic API 4. The 4th commit fixes [rust-lang#125169](rust-lang#125169). I've only deduplicated the lint diagnostic structs mentioned in the issue and haven't gone looking for other structs that may benefit from deriving both `Diagnostic` and `LintDiagnostic` because I didn't have the time to do so yet. ### Meta Fixes rust-lang#125169. I'll submit a rustc-dev-guide PR later. I hope this doesn't need an MCP, it's pretty straight forward. cc `@davidtwco` r? `@nnethercote` or anyone on compiler who has the energy to review 82 files
…r=<try> Make lint diagnostics responsible for providing their primary span ### Summary and Rustc-Dev-Facing Changes Instead of passing the primary span of lint diagnostics separately — namely to the functions `tcx.emit_span_lint` and `tcx.emit_node_span_lint` —, make lint diagnostics responsible for “storing” (providing) their span. I've removed the two aforementioned methods. You are now expected to use `tcx.emit_lint` and `tcx.emit_node_lint` respectively and to provide the primary span when deriving `LintDiagnostic` (via `#[primary_span]`) / implementing `LintDiagnostic` manually (via `LintDiagnostic::span`). > [!NOTE] > FIXME(fmease): Mention how early lints are handled. ### Motivation Making the general format of `#[derive(LintDiagnostic)]` identical to `#[derive(Diagnostic)]`. I bet this has lead to slight confusion or annoyances before. Moreover, it enables deriving both traits at once (see rust-lang#125169 for the motivation). ### Approach As outlined in rust-lang#125169 (comment), the naïve approach of doing the same as `Diagnostic` doesn't work for `LintDiagnostic`, i.e., setting the primary span with `Diag::span` inside `decorate_lint` (that's `into_diag` for `Diagnostic`) because `lint_level` (`lint_level_impl`) needs access to the primary spans before decorating the `Diag` to be able to filter out some lints (namely if they come from an external macro) etc. Therefore, I had to introduce a new method to `LintDiagnostic`: `fn span(&self) -> Option<MultiSpan>` (similar to the existing method `LintDiagnostic::msg`). ### Commits 1. The 1st commit addresses [rust-lang#125169 (comment)](rust-lang#125169 (comment)). It contains the necessary changes to the linting APIs. It doesn't build on its own due to the removed APIs. Split out for easier reviewing. 2. The 2nd commit updates all existing lint diagnostics to use the new APIs. Most of them are mindless, monotonous, obvious changes. Some changes are *slightly* more involved out of necessity. I've verified (partly programmatically, partly manually) that all lint diags that used to have a primary span still have a primary span. 3. The 3rd commit updates the fulldeps UI tests that exercise the (lint) diagnostic API 4. The 4th commit fixes [rust-lang#125169](rust-lang#125169). I've only deduplicated the lint diagnostic structs mentioned in the issue and haven't gone looking for other structs that may benefit from deriving both `Diagnostic` and `LintDiagnostic` because I didn't have the time to do so yet. ### Meta Fixes rust-lang#125169. I'll submit a rustc-dev-guide PR later. I hope this doesn't need an MCP, it's pretty straight forward. cc `@davidtwco` r? `@nnethercote` or anyone on compiler who has the energy to review 82 files
fmease commented in #125208 (comment):
|
In #117164 I had to copy the diagnostic structs
TyParamFirstLocal
andTyParamSome
and define the separate structsTyParamFirstLocalLint
andTyParamSomeLint
to be able to use the translatable diagnosticshir_analysis_ty_param_first_local
andhir_analysis_ty_param_some
as both aDiagnostic
and aLintDiagnostic
:rust/compiler/rustc_hir_analysis/src/errors.rs
Lines 1360 to 1406 in b21b74b
In #116829, had to duplicate the lint diagnostic struct
ReprConflicting
and split it into the separate structsReprConflicting
andReprConflictingLint
to be able to use the translatable diagnosticpasses_repr_conflicting
as both aDiagnostic
and aLintDiagnostic
:rust/compiler/rustc_passes/src/errors.rs
Lines 554 to 563 in b21b74b
In all three cases, I could've probably turned the derivation of
LintDiagnostic
into a manual impl but that doesn't seem very enticing either for various reasons.For context, this situation arises whenever we want to emit a diagnostic for something but can't report a hard error unconditionally in all cases for backward compatibility and therefore have to emit the very same diagnostic at different “levels of severity” depending on a set of conditions. With level of severity I'm specifically referring to the set {hard error, lint} here (where lint has its own level of course).
More concretely, the reason why you can't just
#[derive(Diagnostic, LintDiagnostic)] struct Ty/*...*/
is because of#[primary_span]
: If the diagnostic struct contains a#[primary_span]
(which it does most of the time) for the derive macroDiagnostic
, then the derive macroLintDiagnostic
will reject#[primary_span]
rendering the two derives incompatible with one another.Individually,
LintDiagnostic
rejecting#[primary_span]
makes sense because the span(s) for a lint are to be provided to the function that emits the lint likeemit_span_lint
,emit_node_span_lint
.There are probably multiple ways to approach this but I'm not super familiar with internals of rustc's linting API. Anyways, I'd like to see this “just work” because it won't be the last time this case will occur.
The text was updated successfully, but these errors were encountered: