&tcx.lint_levels(()).lint_expectations;
for (id, expectation) in lint_expectations {
- if fulfilled_expectations.contains(id) {
- continue;
+ if !fulfilled_expectations.contains(id) {
+ emit_unfulfilled_expectation_lint(tcx, expectation);
}
-
- emit_unfulfilled_expectation_lint(tcx, expectation);
}
}
--- /dev/null
+// check-pass
+
+#![feature(lint_reasons)]
+
+#![warn(unused)]
+
+// This expect attribute should catch all lint triggers
+#[expect(unused_variables)]
+fn check_multiple_lints_1() {
+ let value_i = 0xff00ff;
+ let value_ii = 0xff00ff;
+ let value_iii = 0xff00ff;
+ let value_iiii = 0xff00ff;
+ let value_iiiii = 0xff00ff;
+}
+
+// This expect attribute should catch all lint triggers
+#[expect(unused_mut)]
+fn check_multiple_lints_2() {
+ let mut a = 0xa;
+ let mut b = 0xb;
+ let mut c = 0xc;
+ println!("The ABC goes as: {:#x} {:#x} {:#x}", a, b, c);
+}
+
+// This expect attribute should catch all lint triggers
+#[expect(while_true)]
+fn check_multiple_lints_3() {
+ // `while_true` is an early lint
+ while true {}
+
+ while true {}
+
+ while true {}
+
+ while true {}
+
+ while true {}
+}
+
+fn main() {
+ check_multiple_lints_1();
+ check_multiple_lints_2();
+ check_multiple_lints_3();
+}
--- /dev/null
+// check-pass
+
+#![feature(lint_reasons)]
+
+#![warn(unused)]
+
+#![expect(unused_mut)]
+//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+//~| NOTE `#[warn(unfulfilled_lint_expectations)]` on by default
+
+#![expect(unused_variables)]
+
+fn main() {
+ let x = 0;
+}
--- /dev/null
+warning: this lint expectation is unfulfilled
+ --> $DIR/crate_level_expect.rs:7:1
+ |
+LL | #![expect(unused_mut)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(unfulfilled_lint_expectations)]` on by default
+
+warning: 1 warning emitted
+
--- /dev/null
+// check-pass
+
+#![feature(lint_reasons)]
+
+#![warn(unused)]
+
+macro_rules! expect_inside_macro {
+ () => {
+ #[expect(unused_variables)]
+ let x = 0;
+ };
+}
+
+fn main() {
+ expect_inside_macro!();
+}
--- /dev/null
+// check-pass
+
+#![feature(lint_reasons)]
+
+#![warn(unused_variables)]
+
+macro_rules! trigger_unused_variables_macro {
+ () => {
+ let x = 0;
+ //~^ WARNING unused variable: `x` [unused_variables]
+ //~| WARNING unused variable: `x` [unused_variables]
+ };
+}
+
+pub fn check_macro() {
+ // This should trigger the `unused_variables` from inside the macro
+ trigger_unused_variables_macro!();
+}
+
+// This should be fulfilled by the macro
+#[expect(unused_variables)]
+pub fn check_expect_on_item() {
+ trigger_unused_variables_macro!();
+}
+
+pub fn check_expect_on_macro() {
+ // This should be fulfilled by the macro
+ #[expect(unused_variables)]
+ trigger_unused_variables_macro!();
+
+ // FIXME: Lint attributes currently don't work directly on macros, and
+ // therefore also doesn't work for the new `expect` attribute. This bug
+ // is being tracked in rust#87391. The test will until then produce two
+ // warnings about the unused variable x.
+ //
+ // The expectation is still marked as fulfilled. I'm not totally why but
+ // my guess is that this will remain working when rust#87391 has been fixed.
+}
+
+fn main() {
+
+}
--- /dev/null
+warning: unused variable: `x`
+ --> $DIR/expect_lint_from_macro.rs:9:13
+ |
+LL | let x = 0;
+ | ^ help: if this is intentional, prefix it with an underscore: `_x`
+...
+LL | trigger_unused_variables_macro!();
+ | --------------------------------- in this macro invocation
+ |
+note: the lint level is defined here
+ --> $DIR/expect_lint_from_macro.rs:5:9
+ |
+LL | #![warn(unused_variables)]
+ | ^^^^^^^^^^^^^^^^
+ = note: this warning originates in the macro `trigger_unused_variables_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: unused variable: `x`
+ --> $DIR/expect_lint_from_macro.rs:9:13
+ |
+LL | let x = 0;
+ | ^ help: if this is intentional, prefix it with an underscore: `_x`
+...
+LL | trigger_unused_variables_macro!();
+ | --------------------------------- in this macro invocation
+ |
+ = note: this warning originates in the macro `trigger_unused_variables_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: 2 warnings emitted
+
--- /dev/null
+// should error due to missing feature gate.
+
+#![warn(unused)]
+
+#[expect(unused)]
+//~^ ERROR: the `#[expect]` attribute is an experimental feature [E0658]
+fn main() {
+ let x = 1;
+}
--- /dev/null
+error[E0658]: the `#[expect]` attribute is an experimental feature
+ --> $DIR/expect_missing_feature_gate.rs:5:1
+ |
+LL | #[expect(unused)]
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #54503 <https://github.com/rust-lang/rust/issues/54503> for more information
+ = help: add `#![feature(lint_reasons)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// check-pass
+
+#![feature(lint_reasons)]
+
+#![warn(unused)]
+
+#[expect(unused_variables, unused_mut, while_true)]
+fn check_multiple_lints_1() {
+ // This only trigger `unused_variables`
+ let who_am_i = 666;
+}
+
+#[expect(unused_variables, unused_mut, while_true)]
+fn check_multiple_lints_2() {
+ // This only triggers `unused_mut`
+ let mut x = 0;
+ println!("I use x: {}", x);
+}
+
+
+#[expect(unused_variables, unused_mut, while_true)]
+fn check_multiple_lints_3() {
+ // This only triggers `while_true` which is also an early lint
+ while true {}
+}
+
+fn main() {
+ check_multiple_lints_1();
+ check_multiple_lints_2();
+ check_multiple_lints_3();
+}
--- /dev/null
+// check-pass
+// ignore-tidy-linelength
+
+#![feature(lint_reasons)]
+#![warn(unused_mut)]
+
+#[expect(
+ unused_mut,
+ reason = "this `expect` is overridden by a `allow` attribute before the `unused_mut` lint is triggered"
+)]
+//~^^^^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+//~| NOTE this `expect` is overridden by a `allow` attribute before the `unused_mut` lint is triggered
+mod foo {
+ fn bar() {
+ #[allow(
+ unused_mut,
+ reason = "this overrides the previous `expect` lint level and allows the `unused_mut` lint here"
+ )]
+ let mut v = 0;
+ }
+}
+
+#[expect(
+ unused_mut,
+ reason = "this `expect` is overridden by a `warn` attribute before the `unused_mut` lint is triggered"
+)]
+//~^^^^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+//~| NOTE `#[warn(unfulfilled_lint_expectations)]` on by default
+//~| NOTE this `expect` is overridden by a `warn` attribute before the `unused_mut` lint is triggered
+mod oof {
+ #[warn(
+ unused_mut,
+ //~^ NOTE the lint level is defined here
+ reason = "this overrides the previous `expect` lint level and warns about the `unused_mut` lint here"
+ )]
+ fn bar() {
+ let mut v = 0;
+ //~^ WARNING variable does not need to be mutable [unused_mut]
+ //~| NOTE this overrides the previous `expect` lint level and warns about the `unused_mut` lint here
+ }
+}
+
+fn main() {}
--- /dev/null
+warning: variable does not need to be mutable
+ --> $DIR/expect_nested_lint_levels.rs:37:13
+ |
+LL | let mut v = 0;
+ | ----^
+ | |
+ | help: remove this `mut`
+ |
+ = note: this overrides the previous `expect` lint level and warns about the `unused_mut` lint here
+note: the lint level is defined here
+ --> $DIR/expect_nested_lint_levels.rs:32:9
+ |
+LL | unused_mut,
+ | ^^^^^^^^^^
+
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect_nested_lint_levels.rs:23:1
+ |
+LL | / #[expect(
+LL | | unused_mut,
+LL | | reason = "this `expect` is overridden by a `warn` attribute before the `unused_mut` lint is triggered"
+LL | | )]
+ | |__^
+ |
+ = note: `#[warn(unfulfilled_lint_expectations)]` on by default
+ = note: this `expect` is overridden by a `warn` attribute before the `unused_mut` lint is triggered
+
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect_nested_lint_levels.rs:7:1
+ |
+LL | / #[expect(
+LL | | unused_mut,
+LL | | reason = "this `expect` is overridden by a `allow` attribute before the `unused_mut` lint is triggered"
+LL | | )]
+ | |__^
+ |
+ = note: this `expect` is overridden by a `allow` attribute before the `unused_mut` lint is triggered
+
+warning: 3 warnings emitted
+
--- /dev/null
+// check-pass
+
+#![feature(lint_reasons)]
+#![warn(unused)]
+
+#![expect(unused_variables, reason = "<This should fail and display this reason>")]
+//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+//~| NOTE `#[warn(unfulfilled_lint_expectations)]` on by default
+//~| NOTE <This should fail and display this reason>
+
+fn main() {}
--- /dev/null
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect_with_reason.rs:6:1
+ |
+LL | #![expect(unused_variables, reason = "<This should fail and display this reason>")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(unfulfilled_lint_expectations)]` on by default
+ = note: <This should fail and display this reason>
+
+warning: 1 warning emitted
+
--- /dev/null
+// check-pass
+
+#![feature(lint_reasons)]
+
+fn expect_early_pass_lints() {
+ #[expect(while_true)]
+ while true {
+ println!("I never stop")
+ }
+
+ #[expect(unused_doc_comments)]
+ /// This comment triggers the `unused_doc_comments` lint
+ let _sheep = "wolf";
+
+ let x = 123;
+ #[expect(ellipsis_inclusive_range_patterns)]
+ match x {
+ 0...100 => {}
+ _ => {}
+ }
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+#![feature(lint_reasons)]
+#![warn(unused)]
+
+#[expect(unused_variables)]
+fn check_specific_lint() {
+ let x = 2;
+}
+
+#[expect(unused)]
+fn check_lint_group() {
+ let x = 15;
+}
+
+#[expect(unused_variables)]
+fn check_multiple_lint_emissions() {
+ let r = 1;
+ let u = 8;
+ let s = 2;
+ let t = 9;
+}
+
+mod check_multiple_expected_lints {
+ #[expect(unused_variables, unused_mut)]
+ pub fn check_lint_1() {
+ // unused_variables should fulfill the expectation
+ let c = 17;
+ }
+
+ #[expect(unused_variables, unused_mut)]
+ pub fn check_lint_2() {
+ // unused_mut should fulfill the expectation
+ let mut c = 17;
+ let _ = c;
+ }
+}
+
+mod check_fulfilled_expect_in_macro {
+ macro_rules! expect_inside_macro {
+ () => {
+ #[expect(unused_variables)]
+ let x = 0;
+ };
+ }
+
+ pub fn check_macro() {
+ expect_inside_macro!();
+ }
+}
+
+fn main() {
+ check_specific_lint();
+ check_lint_group();
+ check_multiple_lint_emissions();
+
+ check_multiple_expected_lints::check_lint_1();
+ check_multiple_expected_lints::check_lint_2();
+
+ check_fulfilled_expect_in_macro::check_macro();
+}
--- /dev/null
+// check-pass
+
+#![feature(lint_reasons)]
+#![warn(unused)]
+
+#[warn(unused_variables)]
+#[expect(unused_variables)]
+//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+//~| NOTE `#[warn(unfulfilled_lint_expectations)]` on by default
+#[allow(unused_variables)]
+#[expect(unused_variables)] // Only this expectation will be fulfilled
+fn main() {
+ let x = 2;
+}
--- /dev/null
+warning: this lint expectation is unfulfilled
+ --> $DIR/multiple_expect_attrs.rs:7:1
+ |
+LL | #[expect(unused_variables)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(unfulfilled_lint_expectations)]` on by default
+
+warning: 1 warning emitted
+