diff --git a/src/librustc_lint/levels.rs b/src/librustc_lint/levels.rs index 3d2ddf12a0a1f..05e7c9a0c780d 100644 --- a/src/librustc_lint/levels.rs +++ b/src/librustc_lint/levels.rs @@ -214,9 +214,9 @@ impl<'s> LintLevelsBuilder<'s> { match store.check_lint_name(&name.as_str(), tool_name) { CheckLintNameResult::Ok(ids) => { let src = LintSource::Node(name, li.span(), reason); - for id in ids { - self.check_gated_lint(*id, attr.span); - specs.insert(*id, (level, src)); + for &id in ids { + self.check_gated_lint(id, attr.span); + specs.insert(id, (level, src)); } } @@ -386,17 +386,18 @@ impl<'s> LintLevelsBuilder<'s> { BuilderPush { prev, changed: prev != self.cur } } - fn check_gated_lint(&self, id: LintId, span: Span) { - if id == LintId::of(builtin::UNSAFE_OP_IN_UNSAFE_FN) - && !self.sess.features_untracked().unsafe_block_in_unsafe_fn - { - feature_err( - &self.sess.parse_sess, - sym::unsafe_block_in_unsafe_fn, - span, - "the `unsafe_op_in_unsafe_fn` lint is unstable", - ) - .emit(); + /// Checks if the lint is gated on a feature that is not enabled. + fn check_gated_lint(&self, lint_id: LintId, span: Span) { + if let Some(feature) = lint_id.lint.feature_gate { + if !self.sess.features_untracked().enabled(feature) { + feature_err( + &self.sess.parse_sess, + feature, + span, + &format!("the `{}` lint is unstable", lint_id.lint.name_lower()), + ) + .emit(); + } } } diff --git a/src/librustc_session/lint.rs b/src/librustc_session/lint.rs index 8a66fac1e3634..ffb4579309075 100644 --- a/src/librustc_session/lint.rs +++ b/src/librustc_session/lint.rs @@ -85,6 +85,9 @@ pub struct Lint { pub future_incompatible: Option, pub is_plugin: bool, + + /// `Some` if this lint is feature gated, otherwise `None`. + pub feature_gate: Option, } /// Extra information for a future incompatibility lint. @@ -107,6 +110,7 @@ impl Lint { is_plugin: false, report_in_external_macro: false, future_incompatible: None, + feature_gate: None, } } @@ -276,7 +280,9 @@ macro_rules! declare_lint { ); ); ($vis: vis $NAME: ident, $Level: ident, $desc: expr, - $(@future_incompatible = $fi:expr;)? $($v:ident),*) => ( + $(@future_incompatible = $fi:expr;)? + $(@feature_gate = $gate:expr;)? + $($v:ident),*) => ( $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint { name: stringify!($NAME), default_level: $crate::lint::$Level, @@ -285,6 +291,7 @@ macro_rules! declare_lint { is_plugin: false, $($v: true,)* $(future_incompatible: Some($fi),)* + $(feature_gate: Some($gate),)* ..$crate::lint::Lint::default_fields_for_macro() }; ); @@ -328,6 +335,7 @@ macro_rules! declare_tool_lint { report_in_external_macro: $external, future_incompatible: None, is_plugin: true, + feature_gate: None, }; ); } diff --git a/src/librustc_session/lint/builtin.rs b/src/librustc_session/lint/builtin.rs index 7112ac35b082b..bb0d6e1a47ead 100644 --- a/src/librustc_session/lint/builtin.rs +++ b/src/librustc_session/lint/builtin.rs @@ -7,6 +7,7 @@ use crate::lint::FutureIncompatibleInfo; use crate::{declare_lint, declare_lint_pass}; use rustc_span::edition::Edition; +use rustc_span::symbol::sym; declare_lint! { pub ILL_FORMED_ATTRIBUTE_INPUT, @@ -530,6 +531,7 @@ declare_lint! { pub UNSAFE_OP_IN_UNSAFE_FN, Allow, "unsafe operations in unsafe functions without an explicit unsafe block are deprecated", + @feature_gate = sym::unsafe_block_in_unsafe_fn; } declare_lint_pass! { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 06293a987124e..1690b946bb625 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -225,11 +225,6 @@ where { let warnings_lint_name = lint::builtin::WARNINGS.name; - // Whitelist feature-gated lints to avoid feature errors when trying to - // allow all lints. - // FIXME(#72694): handle feature-gated lints properly. - let unsafe_op_in_unsafe_fn_name = rustc_lint::builtin::UNSAFE_OP_IN_UNSAFE_FN.name; - whitelisted_lints.push(warnings_lint_name.to_owned()); whitelisted_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned()); @@ -241,7 +236,9 @@ where let lint_opts = lints() .filter_map(|lint| { - if lint.name == warnings_lint_name || lint.name == unsafe_op_in_unsafe_fn_name { + // Whitelist feature-gated lints to avoid feature errors when trying to + // allow all lints. + if lint.name == warnings_lint_name || lint.feature_gate.is_some() { None } else { filter_call(lint)