Skip to content

Commit f09dd2d

Browse files
committed
dont delay bugs on lint attrs during pre-ast-expansion lint checking
1 parent 1006457 commit f09dd2d

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 {
@@ -251,7 +274,7 @@ fn validate_lint_attr<T: Lint, S: Stage>(
251274
return None;
252275
}
253276

254-
if !skip_unused_check && lint_instances.is_empty() {
277+
if !early && !skip_unused_check && lint_instances.is_empty() {
255278
let span = cx.attr_span;
256279
cx.adcx().warn_empty_attribute(span);
257280
}
@@ -274,6 +297,7 @@ fn check_lint<'a, S: Stage>(
274297
tool_name: Option<Symbol>,
275298
tool_span: Option<Span>,
276299
span: Span,
300+
early: bool,
277301
) -> Option<&'a [LintId]> {
278302
let Some(tools) = cx.tools else {
279303
unreachable!("tools required while parsing attributes");
@@ -289,15 +313,17 @@ fn check_lint<'a, S: Stage>(
289313
None => original_name,
290314
Some(new_lint_name) => {
291315
let new_lint_name = Symbol::intern(&new_lint_name);
292-
cx.emit_lint(
293-
RENAMED_AND_REMOVED_LINTS,
294-
AttributeLintKind::DeprecatedLintName {
295-
name: *full_name,
296-
suggestion: span,
297-
replace: new_lint_name,
298-
},
299-
span,
300-
);
316+
if !early {
317+
cx.emit_lint(
318+
RENAMED_AND_REMOVED_LINTS,
319+
AttributeLintKind::DeprecatedLintName {
320+
name: *full_name,
321+
suggestion: span,
322+
replace: new_lint_name,
323+
},
324+
span,
325+
);
326+
}
301327
new_lint_name
302328
}
303329
};
@@ -313,21 +339,26 @@ fn check_lint<'a, S: Stage>(
313339
}
314340

315341
CheckLintNameResult::NoTool => {
316-
cx.emit_err(UnknownToolInScopedLint {
317-
span: tool_span,
318-
tool_name: tool_name.unwrap(),
319-
full_lint_name: *full_name,
320-
is_nightly_build: cx.sess.is_nightly_build(),
321-
});
342+
if !early {
343+
cx.emit_err(UnknownToolInScopedLint {
344+
span: tool_span,
345+
tool_name: tool_name.unwrap(),
346+
full_lint_name: *full_name,
347+
is_nightly_build: cx.sess.is_nightly_build(),
348+
});
349+
}
350+
322351
None
323352
}
324353

325354
CheckLintNameResult::Renamed(replace) => {
326-
cx.emit_lint(
327-
RENAMED_AND_REMOVED_LINTS,
328-
AttributeLintKind::RenamedLint { name: *full_name, replace, suggestion: span },
329-
span,
330-
);
355+
if !early {
356+
cx.emit_lint(
357+
RENAMED_AND_REMOVED_LINTS,
358+
AttributeLintKind::RenamedLint { name: *full_name, replace, suggestion: span },
359+
span,
360+
);
361+
}
331362

332363
// Since it was renamed, and we have emitted the warning
333364
// we replace the "full_name", to ensure we don't get notes with:
@@ -348,33 +379,39 @@ fn check_lint<'a, S: Stage>(
348379
}
349380

350381
CheckLintNameResult::RenamedToolLint(new_name) => {
351-
cx.emit_lint(
352-
RENAMED_AND_REMOVED_LINTS,
353-
AttributeLintKind::RenamedLint {
354-
name: *full_name,
355-
replace: new_name,
356-
suggestion: span,
357-
},
358-
span,
359-
);
382+
if !early {
383+
cx.emit_lint(
384+
RENAMED_AND_REMOVED_LINTS,
385+
AttributeLintKind::RenamedLint {
386+
name: *full_name,
387+
replace: new_name,
388+
suggestion: span,
389+
},
390+
span,
391+
);
392+
}
360393
None
361394
}
362395

363396
CheckLintNameResult::Removed(reason) => {
364-
cx.emit_lint(
365-
RENAMED_AND_REMOVED_LINTS,
366-
AttributeLintKind::RemovedLint { name: *full_name, reason },
367-
span,
368-
);
397+
if !early {
398+
cx.emit_lint(
399+
RENAMED_AND_REMOVED_LINTS,
400+
AttributeLintKind::RemovedLint { name: *full_name, reason },
401+
span,
402+
);
403+
}
369404
None
370405
}
371406

372407
CheckLintNameResult::NoLint(suggestion) => {
373-
cx.emit_lint(
374-
UNKNOWN_LINTS,
375-
AttributeLintKind::UnknownLint { name: *full_name, suggestion, span },
376-
span,
377-
);
408+
if !early {
409+
cx.emit_lint(
410+
UNKNOWN_LINTS,
411+
AttributeLintKind::UnknownLint { name: *full_name, suggestion, span },
412+
span,
413+
);
414+
}
378415
None
379416
}
380417
}

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)