Skip to content

Commit d3c9908

Browse files
authored
Rollup merge of #145747 - joshtriplett:builtin-diag-dyn, r=jdonszelmann
Refactor lint buffering to avoid requiring a giant enum Lint buffering currently relies on a giant enum `BuiltinLintDiag` containing all the lints that might potentially get buffered. In addition to being an unwieldy enum in a central crate, this also makes `rustc_lint_defs` a build bottleneck: it depends on various types from various crates (with a steady pressure to add more), and many crates depend on it. Having all of these variants in a separate crate also prevents detecting when a variant becomes unused, which we can do with a dedicated type defined and used in the same crate. Refactor this to use a dyn trait, to allow using `LintDiagnostic` types directly. Because the existing `BuiltinLintDiag` requires some additional types in order to decorate some variants, which are only available later in `rustc_lint`, use an enum `DecorateDiagCompat` to handle both the `dyn LintDiagnostic` case and the `BuiltinLintDiag` case. --- With the infrastructure in place, use it to migrate three of the enum variants to use `LintDiagnostic` directly, as a proof of concept and to demonstrate that the net result is a reduction in code size and a removal of a boilerplate-heavy layer of indirection. Also remove an unused `BuiltinLintDiag` variant.
2 parents 561656d + 52fadd8 commit d3c9908

File tree

29 files changed

+265
-277
lines changed

29 files changed

+265
-277
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3797,6 +3797,7 @@ dependencies = [
37973797
"annotate-snippets 0.11.5",
37983798
"derive_setters",
37993799
"rustc_abi",
3800+
"rustc_ast",
38003801
"rustc_data_structures",
38013802
"rustc_error_codes",
38023803
"rustc_error_messages",
@@ -4134,7 +4135,6 @@ dependencies = [
41344135
name = "rustc_lint_defs"
41354136
version = "0.0.0"
41364137
dependencies = [
4137-
"rustc_abi",
41384138
"rustc_ast",
41394139
"rustc_data_structures",
41404140
"rustc_error_messages",

compiler/rustc_ast_passes/messages.ftl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ ast_passes_extern_without_abi = `extern` declarations without an explicit ABI ar
113113
.suggestion = specify an ABI
114114
.help = prior to Rust 2024, a default ABI was inferred
115115
116+
ast_passes_extern_without_abi_sugg = `extern` declarations without an explicit ABI are deprecated
117+
.label = ABI should be specified here
118+
.suggestion = explicitly specify the {$default_abi} ABI
119+
116120
ast_passes_feature_on_non_nightly = `#![feature]` may not be used on the {$channel} release channel
117121
.suggestion = remove the attribute
118122
.stable_since = the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ use rustc_ast::*;
2727
use rustc_ast_pretty::pprust::{self, State};
2828
use rustc_attr_parsing::validate_attr;
2929
use rustc_data_structures::fx::FxIndexMap;
30-
use rustc_errors::DiagCtxtHandle;
30+
use rustc_errors::{DiagCtxtHandle, LintBuffer};
3131
use rustc_feature::Features;
3232
use rustc_session::Session;
33+
use rustc_session::lint::BuiltinLintDiag;
3334
use rustc_session::lint::builtin::{
3435
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN,
3536
PATTERNS_IN_FNS_WITHOUT_BODY,
3637
};
37-
use rustc_session::lint::{BuiltinLintDiag, LintBuffer};
3838
use rustc_span::{Ident, Span, kw, sym};
3939
use rustc_target::spec::{AbiMap, AbiMapping};
4040
use thin_vec::thin_vec;
@@ -876,7 +876,7 @@ impl<'a> AstValidator<'a> {
876876
MISSING_ABI,
877877
id,
878878
span,
879-
BuiltinLintDiag::MissingAbi(span, ExternAbi::FALLBACK),
879+
errors::MissingAbiSugg { span, default_abi: ExternAbi::FALLBACK },
880880
)
881881
}
882882
}

compiler/rustc_ast_passes/src/errors.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc_abi::ExternAbi;
44
use rustc_ast::ParamKindOrd;
55
use rustc_errors::codes::*;
66
use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic};
7-
use rustc_macros::{Diagnostic, Subdiagnostic};
7+
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
88
use rustc_span::{Ident, Span, Symbol};
99

1010
use crate::fluent_generated as fluent;
@@ -815,6 +815,14 @@ pub(crate) struct MissingAbi {
815815
pub span: Span,
816816
}
817817

818+
#[derive(LintDiagnostic)]
819+
#[diag(ast_passes_extern_without_abi_sugg)]
820+
pub(crate) struct MissingAbiSugg {
821+
#[suggestion(code = "extern {default_abi}", applicability = "machine-applicable")]
822+
pub span: Span,
823+
pub default_abi: ExternAbi,
824+
}
825+
818826
#[derive(Diagnostic)]
819827
#[diag(ast_passes_abi_custom_safe_foreign_function)]
820828
pub(crate) struct AbiCustomSafeForeignFunction {

compiler/rustc_builtin_macros/src/format.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ use rustc_ast::{
1010
};
1111
use rustc_data_structures::fx::FxHashSet;
1212
use rustc_errors::{
13-
Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans, listify, pluralize,
13+
Applicability, BufferedEarlyLint, Diag, MultiSpan, PResult, SingleLabelManySpans, listify,
14+
pluralize,
1415
};
1516
use rustc_expand::base::*;
1617
use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
17-
use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, LintId};
18+
use rustc_lint_defs::{BuiltinLintDiag, LintId};
1819
use rustc_parse::exp;
1920
use rustc_parse_format as parse;
2021
use rustc_span::{BytePos, ErrorGuaranteed, Ident, InnerSpan, Span, Symbol};
@@ -595,7 +596,8 @@ fn make_format_args(
595596
named_arg_sp: arg_name.span,
596597
named_arg_name: arg_name.name.to_string(),
597598
is_formatting_arg: matches!(used_as, Width | Precision),
598-
},
599+
}
600+
.into(),
599601
});
600602
}
601603
}

compiler/rustc_errors/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ edition = "2024"
88
annotate-snippets = "0.11"
99
derive_setters = "0.1.6"
1010
rustc_abi = { path = "../rustc_abi" }
11+
rustc_ast = { path = "../rustc_ast" }
1112
rustc_data_structures = { path = "../rustc_data_structures" }
1213
rustc_error_codes = { path = "../rustc_error_codes" }
1314
rustc_error_messages = { path = "../rustc_error_messages" }
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/// This module provides types and traits for buffering lints until later in compilation.
2+
use rustc_ast::node_id::NodeId;
3+
use rustc_data_structures::fx::FxIndexMap;
4+
use rustc_error_messages::MultiSpan;
5+
use rustc_lint_defs::{BuiltinLintDiag, Lint, LintId};
6+
7+
use crate::{DynSend, LintDiagnostic, LintDiagnosticBox};
8+
9+
/// We can't implement `LintDiagnostic` for `BuiltinLintDiag`, because decorating some of its
10+
/// variants requires types we don't have yet. So, handle that case separately.
11+
pub enum DecorateDiagCompat {
12+
Dynamic(Box<dyn for<'a> LintDiagnosticBox<'a, ()> + DynSend + 'static>),
13+
Builtin(BuiltinLintDiag),
14+
}
15+
16+
impl std::fmt::Debug for DecorateDiagCompat {
17+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18+
f.debug_struct("DecorateDiagCompat").finish()
19+
}
20+
}
21+
22+
impl !LintDiagnostic<'_, ()> for BuiltinLintDiag {}
23+
24+
impl<D: for<'a> LintDiagnostic<'a, ()> + DynSend + 'static> From<D> for DecorateDiagCompat {
25+
#[inline]
26+
fn from(d: D) -> Self {
27+
Self::Dynamic(Box::new(d))
28+
}
29+
}
30+
31+
impl From<BuiltinLintDiag> for DecorateDiagCompat {
32+
#[inline]
33+
fn from(b: BuiltinLintDiag) -> Self {
34+
Self::Builtin(b)
35+
}
36+
}
37+
38+
/// Lints that are buffered up early on in the `Session` before the
39+
/// `LintLevels` is calculated.
40+
#[derive(Debug)]
41+
pub struct BufferedEarlyLint {
42+
/// The span of code that we are linting on.
43+
pub span: Option<MultiSpan>,
44+
45+
/// The `NodeId` of the AST node that generated the lint.
46+
pub node_id: NodeId,
47+
48+
/// A lint Id that can be passed to
49+
/// `rustc_lint::early::EarlyContextAndPass::check_id`.
50+
pub lint_id: LintId,
51+
52+
/// Customization of the `Diag<'_>` for the lint.
53+
pub diagnostic: DecorateDiagCompat,
54+
}
55+
56+
#[derive(Default, Debug)]
57+
pub struct LintBuffer {
58+
pub map: FxIndexMap<NodeId, Vec<BufferedEarlyLint>>,
59+
}
60+
61+
impl LintBuffer {
62+
pub fn add_early_lint(&mut self, early_lint: BufferedEarlyLint) {
63+
self.map.entry(early_lint.node_id).or_default().push(early_lint);
64+
}
65+
66+
pub fn take(&mut self, id: NodeId) -> Vec<BufferedEarlyLint> {
67+
// FIXME(#120456) - is `swap_remove` correct?
68+
self.map.swap_remove(&id).unwrap_or_default()
69+
}
70+
71+
pub fn buffer_lint(
72+
&mut self,
73+
lint: &'static Lint,
74+
node_id: NodeId,
75+
span: impl Into<MultiSpan>,
76+
decorate: impl Into<DecorateDiagCompat>,
77+
) {
78+
self.add_early_lint(BufferedEarlyLint {
79+
lint_id: LintId::of(lint),
80+
node_id,
81+
span: Some(span.into()),
82+
diagnostic: decorate.into(),
83+
});
84+
}
85+
}

compiler/rustc_errors/src/diagnostic.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,10 +138,20 @@ where
138138
/// `#[derive(LintDiagnostic)]` -- see [rustc_macros::LintDiagnostic].
139139
#[rustc_diagnostic_item = "LintDiagnostic"]
140140
pub trait LintDiagnostic<'a, G: EmissionGuarantee> {
141-
/// Decorate and emit a lint.
141+
/// Decorate a lint with the information from this type.
142142
fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>);
143143
}
144144

145+
pub trait LintDiagnosticBox<'a, G: EmissionGuarantee> {
146+
fn decorate_lint_box<'b>(self: Box<Self>, diag: &'b mut Diag<'a, G>);
147+
}
148+
149+
impl<'a, G: EmissionGuarantee, D: LintDiagnostic<'a, G>> LintDiagnosticBox<'a, G> for D {
150+
fn decorate_lint_box<'b>(self: Box<Self>, diag: &'b mut Diag<'a, G>) {
151+
self.decorate_lint(diag);
152+
}
153+
}
154+
145155
#[derive(Clone, Debug, Encodable, Decodable)]
146156
pub(crate) struct DiagLocation {
147157
file: Cow<'static, str>,

compiler/rustc_errors/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,10 @@ use std::{fmt, panic};
4040

4141
use Level::*;
4242
pub use codes::*;
43+
pub use decorate_diag::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer};
4344
pub use diagnostic::{
4445
BugAbort, Diag, DiagArgMap, DiagInner, DiagStyledString, Diagnostic, EmissionGuarantee,
45-
FatalAbort, LintDiagnostic, StringPart, Subdiag, Subdiagnostic,
46+
FatalAbort, LintDiagnostic, LintDiagnosticBox, StringPart, Subdiag, Subdiagnostic,
4647
};
4748
pub use diagnostic_impls::{
4849
DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,
@@ -80,6 +81,7 @@ use crate::timings::TimingRecord;
8081

8182
pub mod annotate_snippet_emitter_writer;
8283
pub mod codes;
84+
mod decorate_diag;
8385
mod diagnostic;
8486
mod diagnostic_impls;
8587
pub mod emitter;

compiler/rustc_expand/src/base.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ use rustc_ast::visit::{AssocCtxt, Visitor};
1313
use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind};
1414
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
1515
use rustc_data_structures::sync;
16-
use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult};
16+
use rustc_errors::{BufferedEarlyLint, DiagCtxtHandle, ErrorGuaranteed, PResult};
1717
use rustc_feature::Features;
1818
use rustc_hir as hir;
1919
use rustc_hir::attrs::{AttributeKind, CfgEntry, Deprecation};
2020
use rustc_hir::def::MacroKinds;
2121
use rustc_hir::{Stability, find_attr};
22-
use rustc_lint_defs::{BufferedEarlyLint, RegisteredTools};
22+
use rustc_lint_defs::RegisteredTools;
2323
use rustc_parse::MACRO_ARGUMENTS;
2424
use rustc_parse::parser::{ForceCollect, Parser};
2525
use rustc_session::config::CollapseMacroDebuginfo;

0 commit comments

Comments
 (0)