about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_feature/src/active.rs2
-rw-r--r--compiler/rustc_lint/src/levels.rs92
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs9
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-command-line.rs4
-rw-r--r--src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-inline.rs5
-rw-r--r--src/test/ui/unknown-unstable-lints/unstable-lint-command-line.rs5
-rw-r--r--src/test/ui/unknown-unstable-lints/unstable-lint-command-line.stderr11
-rw-r--r--src/test/ui/unknown-unstable-lints/unstable-lint-inline.rs6
-rw-r--r--src/test/ui/unknown-unstable-lints/unstable-lint-inline.stderr19
10 files changed, 119 insertions, 35 deletions
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index a69d28b184a..09557332fd7 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -169,6 +169,8 @@ declare_features! (
     (active, staged_api, "1.0.0", None, None),
     /// Added for testing E0705; perma-unstable.
     (active, test_2018_feature, "1.31.0", None, Some(Edition::Edition2018)),
+    /// Added for testing unstable lints; perma-unstable.
+    (active, test_unstable_lint, "1.60.0", None, None),
     /// Allows non-`unsafe` —and thus, unsound— access to `Pin` constructions.
     /// Marked `incomplete` since perma-unstable and unsound.
     (incomplete, unsafe_pin_internals, "1.60.0", None, None),
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index bbfbf61f486..a72e0336db9 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -93,10 +93,21 @@ impl<'s> LintLevelsBuilder<'s> {
         self.store
     }
 
+    fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource> {
+        &self.sets.list[self.cur].specs
+    }
+
+    fn current_specs_mut(&mut self) -> &mut FxHashMap<LintId, LevelAndSource> {
+        &mut self.sets.list[self.cur].specs
+    }
+
     fn process_command_line(&mut self, sess: &Session, store: &LintStore) {
-        let mut specs = FxHashMap::default();
         self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
 
+        self.cur = self.sets.list.push(LintSet {
+            specs: FxHashMap::default(),
+            parent: COMMAND_LINE,
+        });
         for &(ref lint_name, level) in &sess.opts.lint_opts {
             store.check_lint_name_cmdline(sess, &lint_name, level, self.registered_tools);
             let orig_level = level;
@@ -108,17 +119,16 @@ impl<'s> LintLevelsBuilder<'s> {
             };
             for id in ids {
                 // ForceWarn and Forbid cannot be overriden
-                if let Some((Level::ForceWarn | Level::Forbid, _)) = specs.get(&id) {
+                if let Some((Level::ForceWarn | Level::Forbid, _)) = self.current_specs().get(&id) {
                     continue;
                 }
 
-                self.check_gated_lint(id, DUMMY_SP);
-                let src = LintLevelSource::CommandLine(lint_flag_val, orig_level);
-                specs.insert(id, (level, src));
+                if self.check_gated_lint(id, DUMMY_SP) {
+                    let src = LintLevelSource::CommandLine(lint_flag_val, orig_level);
+                    self.current_specs_mut().insert(id, (level, src));
+                }
             }
         }
-
-        self.cur = self.sets.list.push(LintSet { specs, parent: COMMAND_LINE });
     }
 
     /// Attempts to insert the `id` to `level_src` map entry. If unsuccessful
@@ -126,12 +136,11 @@ impl<'s> LintLevelsBuilder<'s> {
     /// diagnostic with no change to `specs`.
     fn insert_spec(
         &mut self,
-        specs: &mut FxHashMap<LintId, LevelAndSource>,
         id: LintId,
         (level, src): LevelAndSource,
     ) {
         let (old_level, old_src) =
-            self.sets.get_lint_level(id.lint, self.cur, Some(&specs), &self.sess);
+            self.sets.get_lint_level(id.lint, self.cur, Some(self.current_specs()), &self.sess);
         // Setting to a non-forbid level is an error if the lint previously had
         // a forbid level. Note that this is not necessarily true even with a
         // `#[forbid(..)]` attribute present, as that is overriden by `--cap-lints`.
@@ -154,7 +163,7 @@ impl<'s> LintLevelsBuilder<'s> {
                 };
                 debug!(
                     "fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}",
-                    fcw_warning, specs, old_src, id_name
+                    fcw_warning, self.current_specs(), old_src, id_name
                 );
 
                 let decorate_diag = |diag: &mut Diagnostic| {
@@ -213,9 +222,9 @@ impl<'s> LintLevelsBuilder<'s> {
             }
         }
         if let Level::ForceWarn = old_level {
-            specs.insert(id, (old_level, old_src));
+            self.current_specs_mut().insert(id, (old_level, old_src));
         } else {
-            specs.insert(id, (level, src));
+            self.current_specs_mut().insert(id, (level, src));
         }
     }
 
@@ -239,7 +248,11 @@ impl<'s> LintLevelsBuilder<'s> {
         is_crate_node: bool,
         source_hir_id: Option<HirId>,
     ) -> BuilderPush {
-        let mut specs = FxHashMap::default();
+        let prev = self.cur;
+        self.cur = self.sets.list.push(LintSet {
+            specs: FxHashMap::default(),
+            parent: prev,
+        });
         let sess = self.sess;
         let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
         for (attr_index, attr) in attrs.iter().enumerate() {
@@ -348,8 +361,9 @@ impl<'s> LintLevelsBuilder<'s> {
                             reason,
                         );
                         for &id in *ids {
-                            self.check_gated_lint(id, attr.span);
-                            self.insert_spec(&mut specs, id, (level, src));
+                            if self.check_gated_lint(id, attr.span) {
+                                self.insert_spec(id, (level, src));
+                            }
                         }
                         if let Level::Expect(expect_id) = level {
                             self.lint_expectations
@@ -368,7 +382,7 @@ impl<'s> LintLevelsBuilder<'s> {
                                     reason,
                                 );
                                 for id in ids {
-                                    self.insert_spec(&mut specs, *id, (level, src));
+                                    self.insert_spec(*id, (level, src));
                                 }
                                 if let Level::Expect(expect_id) = level {
                                     self.lint_expectations
@@ -378,7 +392,7 @@ impl<'s> LintLevelsBuilder<'s> {
                             Err((Some(ids), ref new_lint_name)) => {
                                 let lint = builtin::RENAMED_AND_REMOVED_LINTS;
                                 let (lvl, src) =
-                                    self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess);
+                                    self.sets.get_lint_level(lint, self.cur, Some(self.current_specs()), &sess);
                                 struct_lint_level(
                                     self.sess,
                                     lint,
@@ -408,7 +422,7 @@ impl<'s> LintLevelsBuilder<'s> {
                                     reason,
                                 );
                                 for id in ids {
-                                    self.insert_spec(&mut specs, *id, (level, src));
+                                    self.insert_spec(*id, (level, src));
                                 }
                                 if let Level::Expect(expect_id) = level {
                                     self.lint_expectations
@@ -449,7 +463,7 @@ impl<'s> LintLevelsBuilder<'s> {
                     CheckLintNameResult::Warning(msg, renamed) => {
                         let lint = builtin::RENAMED_AND_REMOVED_LINTS;
                         let (renamed_lint_level, src) =
-                            self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess);
+                            self.sets.get_lint_level(lint, self.cur, Some(self.current_specs()), &sess);
                         struct_lint_level(
                             self.sess,
                             lint,
@@ -473,7 +487,7 @@ impl<'s> LintLevelsBuilder<'s> {
                     CheckLintNameResult::NoLint(suggestion) => {
                         let lint = builtin::UNKNOWN_LINTS;
                         let (level, src) =
-                            self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess);
+                            self.sets.get_lint_level(lint, self.cur, Some(self.current_specs()), self.sess);
                         struct_lint_level(self.sess, lint, level, src, Some(sp.into()), |lint| {
                             let name = if let Some(tool_ident) = tool_ident {
                                 format!("{}::{}", tool_ident.name, name)
@@ -504,8 +518,9 @@ impl<'s> LintLevelsBuilder<'s> {
                     {
                         let src = LintLevelSource::Node(Symbol::intern(&new_name), sp, reason);
                         for &id in ids {
-                            self.check_gated_lint(id, attr.span);
-                            self.insert_spec(&mut specs, id, (level, src));
+                            if self.check_gated_lint(id, attr.span) {
+                                self.insert_spec(id, (level, src));
+                            }
                         }
                         if let Level::Expect(expect_id) = level {
                             self.lint_expectations
@@ -519,7 +534,7 @@ impl<'s> LintLevelsBuilder<'s> {
         }
 
         if !is_crate_node {
-            for (id, &(level, ref src)) in specs.iter() {
+            for (id, &(level, ref src)) in self.current_specs().iter() {
                 if !id.lint.crate_level_only {
                     continue;
                 }
@@ -530,7 +545,7 @@ impl<'s> LintLevelsBuilder<'s> {
 
                 let lint = builtin::UNUSED_ATTRIBUTES;
                 let (lint_level, lint_src) =
-                    self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess);
+                    self.sets.get_lint_level(lint, self.cur, Some(self.current_specs()), self.sess);
                 struct_lint_level(
                     self.sess,
                     lint,
@@ -551,9 +566,9 @@ impl<'s> LintLevelsBuilder<'s> {
             }
         }
 
-        let prev = self.cur;
-        if !specs.is_empty() {
-            self.cur = self.sets.list.push(LintSet { specs, parent: prev });
+        if self.current_specs().is_empty() {
+            self.sets.list.pop();
+            self.cur = prev;
         }
 
         BuilderPush { prev, changed: prev != self.cur }
@@ -574,18 +589,25 @@ impl<'s> LintLevelsBuilder<'s> {
     }
 
     /// Checks if the lint is gated on a feature that is not enabled.
-    fn check_gated_lint(&self, lint_id: LintId, span: Span) {
+    ///
+    /// Returns `true` if the lint's feature is enabled.
+    fn check_gated_lint(&self, lint_id: LintId, span: Span) -> bool {
         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();
+                let (unknown_lints_level, _) = self.lint_level(builtin::UNKNOWN_LINTS);
+                if unknown_lints_level != Level::Allow {
+                    feature_err(
+                        &self.sess.parse_sess,
+                        feature,
+                        span,
+                        &format!("the `{}` lint is unstable", lint_id.lint.name_lower()),
+                    )
+                    .emit();
+                }
+                return false;
             }
         }
+        true
     }
 
     /// Called after `push` when the scope of a set of attributes are exited.
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 04a339f3c95..e1c88f74ab3 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3128,6 +3128,7 @@ declare_lint_pass! {
         SUSPICIOUS_AUTO_TRAIT_IMPLS,
         UNEXPECTED_CFGS,
         DEPRECATED_WHERE_CLAUSE_LOCATION,
+        TEST_UNSTABLE_LINT,
     ]
 }
 
@@ -3771,3 +3772,11 @@ declare_lint! {
     Warn,
     "deprecated where clause location"
 }
+
+declare_lint! {
+    #[doc(hidden)]
+    pub TEST_UNSTABLE_LINT,
+    Deny,
+    "this unstable lint is only for testing",
+    @feature_gate = sym::test_unstable_lint;
+}
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 3f44292e034..24f802c1d4f 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1383,6 +1383,7 @@ symbols! {
         test_case,
         test_removed_feature,
         test_runner,
+        test_unstable_lint,
         then_with,
         thread,
         thread_local,
diff --git a/src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-command-line.rs b/src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-command-line.rs
new file mode 100644
index 00000000000..80e30f23993
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-command-line.rs
@@ -0,0 +1,4 @@
+// check-pass
+// compile-flags: -Aunknown_lints -Atest_unstable_lint
+
+fn main() {}
diff --git a/src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-inline.rs b/src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-inline.rs
new file mode 100644
index 00000000000..992472c894a
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-inline.rs
@@ -0,0 +1,5 @@
+// check-pass
+
+#![allow(unknown_lints, test_unstable_lint)]
+
+fn main() {}
diff --git a/src/test/ui/unknown-unstable-lints/unstable-lint-command-line.rs b/src/test/ui/unknown-unstable-lints/unstable-lint-command-line.rs
new file mode 100644
index 00000000000..7663abffd9b
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/unstable-lint-command-line.rs
@@ -0,0 +1,5 @@
+// check-fail
+// compile-flags: -Atest_unstable_lint
+// error-pattern: the `test_unstable_lint` lint is unstable
+
+fn main() {}
diff --git a/src/test/ui/unknown-unstable-lints/unstable-lint-command-line.stderr b/src/test/ui/unknown-unstable-lints/unstable-lint-command-line.stderr
new file mode 100644
index 00000000000..d088f4c8fe5
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/unstable-lint-command-line.stderr
@@ -0,0 +1,11 @@
+error[E0658]: the `test_unstable_lint` lint is unstable
+   |
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error[E0658]: the `test_unstable_lint` lint is unstable
+   |
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/unknown-unstable-lints/unstable-lint-inline.rs b/src/test/ui/unknown-unstable-lints/unstable-lint-inline.rs
new file mode 100644
index 00000000000..43789906ed6
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/unstable-lint-inline.rs
@@ -0,0 +1,6 @@
+// check-fail
+// error-pattern: the `test_unstable_lint` lint is unstable
+
+#![allow(test_unstable_lint)]
+
+fn main() {}
diff --git a/src/test/ui/unknown-unstable-lints/unstable-lint-inline.stderr b/src/test/ui/unknown-unstable-lints/unstable-lint-inline.stderr
new file mode 100644
index 00000000000..5ec85f346fe
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/unstable-lint-inline.stderr
@@ -0,0 +1,19 @@
+error[E0658]: the `test_unstable_lint` lint is unstable
+  --> $DIR/unstable-lint-inline.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error[E0658]: the `test_unstable_lint` lint is unstable
+  --> $DIR/unstable-lint-inline.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.