Skip to content

Commit c9e832c

Browse files
committed
dont delay bugs on lint attrs during pre-ast-expansion lint checking
1 parent 115e4b0 commit c9e832c

2 files changed

Lines changed: 105 additions & 51 deletions

File tree

compiler/rustc_attr_parsing/src/attributes/lint.rs

Lines changed: 84 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_session::lint::builtin::{RENAMED_AND_REMOVED_LINTS, UNKNOWN_LINTS, UNU
88
use rustc_session::lint::{CheckLintNameResult, LintId};
99

1010
use super::prelude::*;
11+
use crate::ShouldEmit;
1112
use crate::attributes::AcceptFn;
1213
use crate::session_diagnostics::UnknownToolInScopedLint;
1314

@@ -136,13 +137,21 @@ fn validate_lint_attr<T: Lint, S: Stage>(
136137
cx: &mut AcceptContext<'_, '_, S>,
137138
args: &ArgParser,
138139
) -> Option<LintAttribute> {
140+
// ShouldEmit is Nothing during early parsing, so to avoid delayed bugs, we just dont emit
141+
// The reason for why we don't want to delay bugs, is that when compiling lib
142+
// they usually skip this attr parsing but since lint-attrs is parsed in pre expansion,
143+
// these delayed bugs would never be emitted as errors and therefore ICE
144+
let early = matches!(cx.stage.should_emit(), ShouldEmit::Nothing);
145+
139146
let Some(lint_store) = cx.sess.lint_store.as_ref().map(|store| store.to_owned()) else {
140147
unreachable!("lint_store required while parsing attributes");
141148
};
142149
let lint_store = lint_store.as_ref();
143150
let Some(list) = args.list() else {
144151
let span = cx.inner_span;
145-
cx.adcx().expected_list(span, args);
152+
if !early {
153+
cx.adcx().expected_list(span, args);
154+
}
146155
return None;
147156
};
148157
let mut list = list.mixed().peekable();
@@ -155,7 +164,9 @@ fn validate_lint_attr<T: Lint, S: Stage>(
155164
let targeting_crate = matches!(cx.target, Target::Crate);
156165
while let Some(item) = list.next() {
157166
let Some(meta_item) = item.meta_item() else {
158-
cx.adcx().expected_identifier(item.span());
167+
if !early {
168+
cx.adcx().expected_identifier(item.span());
169+
}
159170
errored = true;
160171
continue;
161172
};
@@ -164,25 +175,33 @@ fn validate_lint_attr<T: Lint, S: Stage>(
164175
ArgParser::NameValue(nv_parser) if meta_item.path().word_is(sym::reason) => {
165176
//FIXME replace this with duplicate check?
166177
if list.peek().is_some() {
167-
cx.adcx().expected_nv_as_last_argument(meta_item.span(), sym::reason);
178+
if !early {
179+
cx.adcx().expected_nv_as_last_argument(meta_item.span(), sym::reason);
180+
}
168181
errored = true;
169182
continue;
170183
}
171184

172185
let val_lit = nv_parser.value_as_lit();
173186
let LitKind::Str(reason_sym, _) = val_lit.kind else {
174-
cx.adcx().expected_string_literal(nv_parser.value_span, Some(val_lit));
187+
if !early {
188+
cx.adcx().expected_string_literal(nv_parser.value_span, Some(val_lit));
189+
}
175190
errored = true;
176191
continue;
177192
};
178193
reason = Some(reason_sym);
179194
}
180195
ArgParser::NameValue(_) => {
181-
cx.adcx().expected_specific_argument(meta_item.span(), &[sym::reason]);
196+
if !early {
197+
cx.adcx().expected_specific_argument(meta_item.span(), &[sym::reason]);
198+
}
182199
errored = true;
183200
}
184201
ArgParser::List(list) => {
185-
cx.adcx().expected_no_args(list.span);
202+
if !early {
203+
cx.adcx().expected_no_args(list.span);
204+
}
186205
errored = true;
187206
}
188207
ArgParser::NoArgs => {
@@ -222,8 +241,12 @@ fn validate_lint_attr<T: Lint, S: Stage>(
222241
tool_name,
223242
tool_span,
224243
meta_item_span,
244+
early,
225245
) {
226-
if !targeting_crate && ids.iter().any(|lint_id| lint_id.lint.crate_level_only) {
246+
if !early
247+
&& !targeting_crate
248+
&& ids.iter().any(|lint_id| lint_id.lint.crate_level_only)
249+
{
227250
cx.emit_lint(
228251
UNUSED_ATTRIBUTES,
229252
AttributeLintKind::IgnoredUnlessCrateSpecified {
@@ -241,7 +264,7 @@ fn validate_lint_attr<T: Lint, S: Stage>(
241264
}
242265
}
243266
}
244-
if !skip_unused_check && !errored && lint_instances.is_empty() {
267+
if !early && !skip_unused_check && !errored && lint_instances.is_empty() {
245268
let span = cx.attr_span;
246269
cx.adcx().warn_empty_attribute(span);
247270
}
@@ -264,6 +287,7 @@ fn check_lint<'a, S: Stage>(
264287
tool_name: Option<Symbol>,
265288
tool_span: Option<Span>,
266289
span: Span,
290+
early: bool,
267291
) -> Option<&'a [LintId]> {
268292
let Some(tools) = cx.tools else {
269293
unreachable!("tools required while parsing attributes");
@@ -279,15 +303,17 @@ fn check_lint<'a, S: Stage>(
279303
None => original_name,
280304
Some(new_lint_name) => {
281305
let new_lint_name = Symbol::intern(&new_lint_name);
282-
cx.emit_lint(
283-
RENAMED_AND_REMOVED_LINTS,
284-
AttributeLintKind::DeprecatedLintName {
285-
name: *full_name,
286-
suggestion: span,
287-
replace: new_lint_name,
288-
},
289-
span,
290-
);
306+
if !early {
307+
cx.emit_lint(
308+
RENAMED_AND_REMOVED_LINTS,
309+
AttributeLintKind::DeprecatedLintName {
310+
name: *full_name,
311+
suggestion: span,
312+
replace: new_lint_name,
313+
},
314+
span,
315+
);
316+
}
291317
new_lint_name
292318
}
293319
};
@@ -303,21 +329,26 @@ fn check_lint<'a, S: Stage>(
303329
}
304330

305331
CheckLintNameResult::NoTool => {
306-
cx.emit_err(UnknownToolInScopedLint {
307-
span: tool_span,
308-
tool_name: tool_name.unwrap(),
309-
full_lint_name: *full_name,
310-
is_nightly_build: cx.sess.is_nightly_build(),
311-
});
332+
if !early {
333+
cx.emit_err(UnknownToolInScopedLint {
334+
span: tool_span,
335+
tool_name: tool_name.unwrap(),
336+
full_lint_name: *full_name,
337+
is_nightly_build: cx.sess.is_nightly_build(),
338+
});
339+
}
340+
312341
None
313342
}
314343

315344
CheckLintNameResult::Renamed(replace) => {
316-
cx.emit_lint(
317-
RENAMED_AND_REMOVED_LINTS,
318-
AttributeLintKind::RenamedLint { name: *full_name, replace, suggestion: span },
319-
span,
320-
);
345+
if !early {
346+
cx.emit_lint(
347+
RENAMED_AND_REMOVED_LINTS,
348+
AttributeLintKind::RenamedLint { name: *full_name, replace, suggestion: span },
349+
span,
350+
);
351+
}
321352

322353
// Since it was renamed, and we have emitted the warning
323354
// we replace the "full_name", to ensure we don't get notes with:
@@ -338,33 +369,39 @@ fn check_lint<'a, S: Stage>(
338369
}
339370

340371
CheckLintNameResult::RenamedToolLint(new_name) => {
341-
cx.emit_lint(
342-
RENAMED_AND_REMOVED_LINTS,
343-
AttributeLintKind::RenamedLint {
344-
name: *full_name,
345-
replace: new_name,
346-
suggestion: span,
347-
},
348-
span,
349-
);
372+
if !early {
373+
cx.emit_lint(
374+
RENAMED_AND_REMOVED_LINTS,
375+
AttributeLintKind::RenamedLint {
376+
name: *full_name,
377+
replace: new_name,
378+
suggestion: span,
379+
},
380+
span,
381+
);
382+
}
350383
None
351384
}
352385

353386
CheckLintNameResult::Removed(reason) => {
354-
cx.emit_lint(
355-
RENAMED_AND_REMOVED_LINTS,
356-
AttributeLintKind::RemovedLint { name: *full_name, reason },
357-
span,
358-
);
387+
if !early {
388+
cx.emit_lint(
389+
RENAMED_AND_REMOVED_LINTS,
390+
AttributeLintKind::RemovedLint { name: *full_name, reason },
391+
span,
392+
);
393+
}
359394
None
360395
}
361396

362397
CheckLintNameResult::NoLint(suggestion) => {
363-
cx.emit_lint(
364-
UNKNOWN_LINTS,
365-
AttributeLintKind::UnknownLint { name: *full_name, suggestion, span },
366-
span,
367-
);
398+
if !early {
399+
cx.emit_lint(
400+
UNKNOWN_LINTS,
401+
AttributeLintKind::UnknownLint { name: *full_name, suggestion, span },
402+
span,
403+
);
404+
}
368405
None
369406
}
370407
}

compiler/rustc_attr_parsing/src/parser.rs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,27 @@ impl ArgParser {
141141
}
142142

143143
if args.delim != Delimiter::Parenthesis {
144-
should_emit.emit_err(psess.dcx().create_err(MetaBadDelim {
145-
span: args.dspan.entire(),
146-
sugg: MetaBadDelimSugg { open: args.dspan.open, close: args.dspan.close },
147-
}));
144+
// FIXME we need a way to just turn off delayed bugs during early parsing of certain attrs,
145+
// in the case that they are parsed before expansion
146+
if !(matches!(should_emit, ShouldEmit::Nothing)
147+
&& matches!(
148+
parts,
149+
[sym::allow]
150+
| [sym::deny]
151+
| [sym::expect]
152+
| [sym::forbid]
153+
| [sym::warn]
154+
))
155+
{
156+
should_emit.emit_err(psess.dcx().create_err(MetaBadDelim {
157+
span: args.dspan.entire(),
158+
sugg: MetaBadDelimSugg {
159+
open: args.dspan.open,
160+
close: args.dspan.close,
161+
},
162+
}));
163+
}
164+
148165
return None;
149166
}
150167

0 commit comments

Comments
 (0)