-
Notifications
You must be signed in to change notification settings - Fork 13.8k
introduce future-compatibility warning for forbidden lint groups #81556
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,6 +39,7 @@ use rustc_session::SessionLintStore; | |
use rustc_span::lev_distance::find_best_match_for_name; | ||
use rustc_span::{symbol::Symbol, MultiSpan, Span, DUMMY_SP}; | ||
use rustc_target::abi::LayoutOf; | ||
use tracing::debug; | ||
|
||
use std::cell::Cell; | ||
use std::slice; | ||
|
@@ -336,6 +337,20 @@ impl LintStore { | |
} | ||
} | ||
|
||
/// True if this symbol represents a lint group name. | ||
pub fn is_lint_group(&self, lint_name: Symbol) -> bool { | ||
debug!( | ||
"is_lint_group(lint_name={:?}, lint_groups={:?})", | ||
lint_name, | ||
self.lint_groups.keys().collect::<Vec<_>>() | ||
); | ||
let lint_name_str = &*lint_name.as_str(); | ||
self.lint_groups.contains_key(&lint_name_str) || { | ||
let warnings_name_str = crate::WARNINGS.name_lower(); | ||
|
||
lint_name_str == &*warnings_name_str | ||
} | ||
} | ||
|
||
/// Checks the name of a lint for its existence, and whether it was | ||
/// renamed or removed. Generates a DiagnosticBuilder containing a | ||
/// warning for renamed and removed lints. This is over both lint | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,7 @@ use rustc_ast::attr; | |
use rustc_ast::unwrap_or; | ||
use rustc_ast_pretty::pprust; | ||
use rustc_data_structures::fx::FxHashMap; | ||
use rustc_errors::{struct_span_err, Applicability}; | ||
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; | ||
use rustc_hir as hir; | ||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; | ||
use rustc_hir::{intravisit, HirId}; | ||
|
@@ -17,11 +17,15 @@ use rustc_middle::lint::{ | |
}; | ||
use rustc_middle::ty::query::Providers; | ||
use rustc_middle::ty::TyCtxt; | ||
use rustc_session::lint::{builtin, Level, Lint, LintId}; | ||
use rustc_session::lint::{ | ||
builtin::{self, FORBIDDEN_LINT_GROUPS}, | ||
Level, Lint, LintId, | ||
}; | ||
use rustc_session::parse::feature_err; | ||
use rustc_session::Session; | ||
use rustc_span::symbol::{sym, Symbol}; | ||
use rustc_span::{source_map::MultiSpan, Span, DUMMY_SP}; | ||
use tracing::debug; | ||
|
||
use std::cmp; | ||
|
||
|
@@ -51,6 +55,7 @@ pub struct LintLevelsBuilder<'s> { | |
id_to_set: FxHashMap<HirId, u32>, | ||
cur: u32, | ||
warn_about_weird_lints: bool, | ||
store: &'s LintStore, | ||
} | ||
|
||
pub struct BuilderPush { | ||
|
@@ -59,13 +64,14 @@ pub struct BuilderPush { | |
} | ||
|
||
impl<'s> LintLevelsBuilder<'s> { | ||
pub fn new(sess: &'s Session, warn_about_weird_lints: bool, store: &LintStore) -> Self { | ||
pub fn new(sess: &'s Session, warn_about_weird_lints: bool, store: &'s LintStore) -> Self { | ||
let mut builder = LintLevelsBuilder { | ||
sess, | ||
sets: LintLevelSets::new(), | ||
cur: 0, | ||
id_to_set: Default::default(), | ||
warn_about_weird_lints, | ||
store, | ||
}; | ||
builder.process_command_line(sess, store); | ||
assert_eq!(builder.sets.list.len(), 1); | ||
|
@@ -120,36 +126,75 @@ impl<'s> LintLevelsBuilder<'s> { | |
if let (Level::Forbid, old_src) = | ||
self.sets.get_lint_level(id.lint, self.cur, Some(&specs), &self.sess) | ||
{ | ||
let mut diag_builder = struct_span_err!( | ||
self.sess, | ||
src.span(), | ||
E0453, | ||
"{}({}) incompatible with previous forbid", | ||
level.as_str(), | ||
src.name(), | ||
// Backwards compatibility check: | ||
// | ||
// We used to not consider `forbid(lint_group)` | ||
// as preventing `allow(lint)` for some lint `lint` in | ||
// `lint_group`. For now, issue a future-compatibility | ||
// warning for this case. | ||
let id_name = id.lint.name_lower(); | ||
let fcw_warning = match old_src { | ||
LintLevelSource::Default => false, | ||
LintLevelSource::Node(symbol, _, _) => self.store.is_lint_group(symbol), | ||
LintLevelSource::CommandLine(symbol, _) => self.store.is_lint_group(symbol), | ||
}; | ||
debug!( | ||
"fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}", | ||
fcw_warning, specs, old_src, id_name | ||
); | ||
diag_builder.span_label(src.span(), "overruled by previous forbid"); | ||
match old_src { | ||
LintLevelSource::Default => { | ||
diag_builder.note(&format!( | ||
"`forbid` lint level is the default for {}", | ||
id.to_string() | ||
)); | ||
} | ||
LintLevelSource::Node(_, forbid_source_span, reason) => { | ||
diag_builder.span_label(forbid_source_span, "`forbid` level set here"); | ||
if let Some(rationale) = reason { | ||
diag_builder.note(&rationale.as_str()); | ||
|
||
let decorate_diag_builder = |mut diag_builder: DiagnosticBuilder<'_>| { | ||
diag_builder.span_label(src.span(), "overruled by previous forbid"); | ||
match old_src { | ||
LintLevelSource::Default => { | ||
diag_builder.note(&format!( | ||
"`forbid` lint level is the default for {}", | ||
id.to_string() | ||
)); | ||
} | ||
LintLevelSource::Node(_, forbid_source_span, reason) => { | ||
diag_builder.span_label(forbid_source_span, "`forbid` level set here"); | ||
if let Some(rationale) = reason { | ||
diag_builder.note(&rationale.as_str()); | ||
} | ||
} | ||
LintLevelSource::CommandLine(_, _) => { | ||
diag_builder.note("`forbid` lint level was set on command line"); | ||
} | ||
} | ||
LintLevelSource::CommandLine(_, _) => { | ||
diag_builder.note("`forbid` lint level was set on command line"); | ||
} | ||
diag_builder.emit(); | ||
}; | ||
if !fcw_warning { | ||
let diag_builder = struct_span_err!( | ||
self.sess, | ||
src.span(), | ||
E0453, | ||
"{}({}) incompatible with previous forbid", | ||
level.as_str(), | ||
src.name(), | ||
); | ||
decorate_diag_builder(diag_builder); | ||
} else { | ||
self.struct_lint( | ||
|
||
FORBIDDEN_LINT_GROUPS, | ||
Some(src.span().into()), | ||
|diag_builder| { | ||
let diag_builder = diag_builder.build(&format!( | ||
"{}({}) incompatible with previous forbid", | ||
level.as_str(), | ||
src.name(), | ||
)); | ||
decorate_diag_builder(diag_builder); | ||
}, | ||
); | ||
} | ||
diag_builder.emit(); | ||
|
||
// Retain the forbid lint level | ||
return; | ||
// Retain the forbid lint level, unless we are | ||
// issuing a FCW. In the FCW case, we want to | ||
// respect the new setting. | ||
if !fcw_warning { | ||
return; | ||
} | ||
} | ||
} | ||
specs.insert(id, (level, src)); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// Check what happens when we forbid a smaller group but | ||
// then allow a superset of that group. | ||
|
||
#![forbid(nonstandard_style)] | ||
|
||
// FIXME: Arguably this should be an error, but the WARNINGS group is | ||
|
||
// treated in a very special (and rather ad-hoc) way and | ||
// it fails to trigger. | ||
#[allow(warnings)] | ||
fn main() { | ||
let A: (); | ||
//~^ ERROR should have a snake case name | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
error: variable `A` should have a snake case name | ||
--> $DIR/forbid-group-group-1.rs:11:9 | ||
| | ||
LL | let A: (); | ||
| ^ help: convert the identifier to snake case: `a` | ||
| | ||
note: the lint level is defined here | ||
--> $DIR/forbid-group-group-1.rs:4:11 | ||
| | ||
LL | #![forbid(nonstandard_style)] | ||
| ^^^^^^^^^^^^^^^^^ | ||
= note: `#[forbid(non_snake_case)]` implied by `#[forbid(nonstandard_style)]` | ||
|
||
error: aborting due to previous error | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// Check what happens when we forbid a bigger group but | ||
// then deny a subset of that group. | ||
|
||
#![forbid(warnings)] | ||
#![deny(forbidden_lint_groups)] | ||
|
||
#[allow(nonstandard_style)] | ||
//~^ ERROR incompatible with previous | ||
//~| WARNING previously accepted by the compiler | ||
//~| ERROR incompatible with previous | ||
//~| WARNING previously accepted by the compiler | ||
//~| ERROR incompatible with previous | ||
//~| WARNING previously accepted by the compiler | ||
//~| ERROR incompatible with previous | ||
//~| WARNING previously accepted by the compiler | ||
//~| ERROR incompatible with previous | ||
//~| WARNING previously accepted by the compiler | ||
//~| ERROR incompatible with previous | ||
//~| WARNING previously accepted by the compiler | ||
//~| ERROR incompatible with previous | ||
//~| WARNING previously accepted by the compiler | ||
//~| ERROR incompatible with previous | ||
//~| WARNING previously accepted by the compiler | ||
//~| ERROR incompatible with previous | ||
//~| WARNING previously accepted by the compiler | ||
fn main() {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know why everything with lints uses as keys, but I couldn't find other ways to do comparisons.