From d3d22e1e664d33519ddc1b4bbc00cc93eed3e7be Mon Sep 17 00:00:00 2001 From: KarlWithK Date: Wed, 15 Jun 2022 01:41:56 -0500 Subject: [PATCH 1/7] Add examples using `add_modify` to HashMap Updated the HashMap's documentation to include two references to add_modify. The first is when the `Entry` API is mentioned at the beginning. I was hesitant to change the "attack" example (although I believe that it is perfect example of where `add_modify` should be used) because both uses work equally, but one is more idiomatic (`add_modify`). The second is with the `entry` function that is used for the `Entry` API. The code example was a perfect use for `add_modify`, which is why it was changed to reflect that. --- library/std/src/collections/hash/map.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index d38fecc45b2fc..192a21f2ffc2d 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -164,6 +164,9 @@ use crate::sys; /// // update a key, guarding against the key possibly not being set /// let stat = player_stats.entry("attack").or_insert(100); /// *stat += random_stat_buff(); +/// +/// // modify an entry before an insert with in-place mutation +/// player_stats.entry("mana").and_modify(|mana| *mana += 200).or_insert(100); /// ``` /// /// The easiest way to use `HashMap` with a custom key type is to derive [`Eq`] and [`Hash`]. @@ -829,8 +832,7 @@ where /// let mut letters = HashMap::new(); /// /// for ch in "a short treatise on fungi".chars() { - /// let counter = letters.entry(ch).or_insert(0); - /// *counter += 1; + /// letters.entry(ch).and_modify(|counter| *counter += 1).or_insert(1); /// } /// /// assert_eq!(letters[&'s'], 2); From cec72acdcae939023d7d4e09ad1b06d49f269276 Mon Sep 17 00:00:00 2001 From: KarlWithK Date: Wed, 15 Jun 2022 02:04:18 -0500 Subject: [PATCH 2/7] Add examples using `add_modify` to btree Updated the btree's documentation to include two references to add_modify. The first is when the `Entry` API is mentioned at the beginning. With the same reasoning as HashMap's documentation, I thought it would best to keep `attack`, but show the `mana` example. The second is with the `entry` function that is used for the `Entry` API. The code example was a perfect use for `add_modify`, which is why it was changed to reflect that. --- library/alloc/src/collections/btree/map.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 6027991a0ed2f..7532c1d511474 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -159,6 +159,9 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; /// // update a key, guarding against the key possibly not being set /// let stat = player_stats.entry("attack").or_insert(100); /// *stat += random_stat_buff(); +/// +/// // modify an entry before an insert with in-place mutation +/// player_stats.entry("mana").and_modify(|mana| *mana += 200).or_insert(100); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "BTreeMap")] @@ -1135,10 +1138,12 @@ impl BTreeMap { /// /// // count the number of occurrences of letters in the vec /// for x in ["a", "b", "a", "c", "a", "b"] { - /// *count.entry(x).or_insert(0) += 1; + /// count.entry(x).and_modify(|curr| *curr += 1).or_insert(1); /// } /// /// assert_eq!(count["a"], 3); + /// assert_eq!(count["b"], 2); + /// assert_eq!(count["1"], 1); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn entry(&mut self, key: K) -> Entry<'_, K, V> From 791923aacbbab0933f8ff1108a120194addccf6b Mon Sep 17 00:00:00 2001 From: KarlWithK Date: Wed, 15 Jun 2022 03:19:22 -0500 Subject: [PATCH 3/7] change "1" to "c" to pass test Incorrectly wrote "1" twice when writing test. --- library/alloc/src/collections/btree/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 7532c1d511474..11845f50d7849 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1143,7 +1143,7 @@ impl BTreeMap { /// /// assert_eq!(count["a"], 3); /// assert_eq!(count["b"], 2); - /// assert_eq!(count["1"], 1); + /// assert_eq!(count["c"], 1); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn entry(&mut self, key: K) -> Entry<'_, K, V> From 2b5efa4f79b2def8f1cfe335890867a07d2bed16 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 15 Jun 2022 16:49:52 +0200 Subject: [PATCH 4/7] debuginfo: Fix NatVis for Rc and Arc with unsized pointees. --- src/etc/natvis/liballoc.natvis | 126 +++++++++++++++++++++++++---- src/test/debuginfo/rc_arc.rs | 144 ++++++++++++++++++++++++--------- 2 files changed, 214 insertions(+), 56 deletions(-) diff --git a/src/etc/natvis/liballoc.natvis b/src/etc/natvis/liballoc.natvis index 83ca8ed932e46..912418fa7d1eb 100644 --- a/src/etc/natvis/liballoc.natvis +++ b/src/etc/natvis/liballoc.natvis @@ -59,39 +59,133 @@ + + - {ptr.pointer->value} + {ptr.pointer->value} - ptr.pointer->value - ptr.pointer->strong - ptr.pointer->weak + + ptr.pointer->value + ptr.pointer->strong + ptr.pointer->weak + + + ptr.pointer.pointer->strong + ptr.pointer.pointer->weak + + + + + + {{ len={ptr.pointer.length} }} + + ptr.pointer.length + ptr.pointer.data_ptr->strong + ptr.pointer.data_ptr->weak + + ptr.pointer.length + + ($T1*)(((size_t*)ptr.pointer.data_ptr) + 2) + + + - {ptr.pointer->value} + {ptr.pointer->value} + + + ptr.pointer->value + ptr.pointer->strong + ptr.pointer->weak + + + ptr.pointer.pointer->strong + ptr.pointer.pointer->weak + + + + + + {{ len={ptr.pointer.length} }} - ptr.pointer->value - ptr.pointer->strong - ptr.pointer->weak + ptr.pointer.length + ptr.pointer.data_ptr->strong + ptr.pointer.data_ptr->weak + + ptr.pointer.length + ($T1*)(((size_t*)ptr.pointer.data_ptr) + 2) + + - {ptr.pointer->data} + {ptr.pointer->data} - ptr.pointer->data - ptr.pointer->strong - ptr.pointer->weak + + ptr.pointer->data + ptr.pointer->strong + ptr.pointer->weak + + + ptr.pointer.pointer->strong + ptr.pointer.pointer->weak + + + + + + {{ len={ptr.pointer.length} }} + + ptr.pointer.length + ptr.pointer.data_ptr->strong + ptr.pointer.data_ptr->weak + + ptr.pointer.length + ($T1*)(((size_t*)ptr.pointer.data_ptr) + 2) + + + - {ptr.pointer->data} + {ptr.pointer->data} - ptr.pointer->data - ptr.pointer->strong - ptr.pointer->weak + + ptr.pointer->data + ptr.pointer->strong + ptr.pointer->weak + + + ptr.pointer.pointer->strong + ptr.pointer.pointer->weak + + + + + + {{ len={ptr.pointer.length} }} + + ptr.pointer.length + ptr.pointer.data_ptr->strong + ptr.pointer.data_ptr->weak + + ptr.pointer.length + ($T1*)(((size_t*)ptr.pointer.data_ptr) + 2) + + Borrowed({__0}) Owned({__0}) diff --git a/src/test/debuginfo/rc_arc.rs b/src/test/debuginfo/rc_arc.rs index 8470ace24b845..37e870d8a8e72 100644 --- a/src/test/debuginfo/rc_arc.rs +++ b/src/test/debuginfo/rc_arc.rs @@ -8,74 +8,138 @@ // gdb-command:run -// gdb-command:print r -// gdb-check:[...]$1 = Rc(strong=2, weak=1) = {value = 42, strong = 2, weak = 1} -// gdb-command:print a -// gdb-check:[...]$2 = Arc(strong=2, weak=1) = {value = 42, strong = 2, weak = 1} - +// gdb-command:print rc +// gdb-check:[...]$1 = Rc(strong=11, weak=1) = {value = 111, strong = 11, weak = 1} +// gdb-command:print arc +// gdb-check:[...]$2 = Arc(strong=21, weak=1) = {value = 222, strong = 21, weak = 1} // === LLDB TESTS ================================================================================== // lldb-command:run -// lldb-command:print r -// lldb-check:[...]$0 = strong=2, weak=1 { value = 42 } -// lldb-command:print a -// lldb-check:[...]$1 = strong=2, weak=1 { data = 42 } +// lldb-command:print rc +// lldb-check:[...]$0 = strong=11, weak=1 { value = 111 } +// lldb-command:print arc +// lldb-check:[...]$1 = strong=21, weak=1 { data = 222 } // === CDB TESTS ================================================================================== // cdb-command:g -// cdb-command:dx r,d -// cdb-check:r,d : 42 [Type: alloc::rc::Rc] -// cdb-check: [] [Type: alloc::rc::Rc] -// cdb-check: [Reference count] : 2 [Type: core::cell::Cell] +// cdb-command:dx rc,d +// cdb-check:rc,d : 111 [Type: alloc::rc::Rc] +// cdb-check: [Reference count] : 11 [Type: core::cell::Cell] +// cdb-check: [Weak reference count] : 2 [Type: core::cell::Cell] + +// cdb-command:dx weak_rc,d +// cdb-check:weak_rc,d : 111 [Type: alloc::rc::Weak] +// cdb-check: [Reference count] : 11 [Type: core::cell::Cell] +// cdb-check: [Weak reference count] : 2 [Type: core::cell::Cell] + +// cdb-command:dx arc,d +// cdb-check:arc,d : 222 [Type: alloc::sync::Arc] +// cdb-check: [Reference count] : 21 [Type: core::sync::atomic::AtomicUsize] +// cdb-check: [Weak reference count] : 2 [Type: core::sync::atomic::AtomicUsize] + +// cdb-command:dx weak_arc,d +// cdb-check:weak_arc,d : 222 [Type: alloc::sync::Weak] +// cdb-check: [Reference count] : 21 [Type: core::sync::atomic::AtomicUsize] +// cdb-check: [Weak reference count] : 2 [Type: core::sync::atomic::AtomicUsize] + +// cdb-command:dx dyn_rc,d +// cdb-check:dyn_rc,d [Type: alloc::rc::Rc >] +// cdb-check: [Reference count] : 31 [Type: core::cell::Cell] // cdb-check: [Weak reference count] : 2 [Type: core::cell::Cell] -// cdb-command:dx r1,d -// cdb-check:r1,d : 42 [Type: alloc::rc::Rc] -// cdb-check: [] [Type: alloc::rc::Rc] -// cdb-check: [Reference count] : 2 [Type: core::cell::Cell] +// cdb-command:dx dyn_rc_weak,d +// cdb-check:dyn_rc_weak,d [Type: alloc::rc::Weak >] +// cdb-check: [Reference count] : 31 [Type: core::cell::Cell] // cdb-check: [Weak reference count] : 2 [Type: core::cell::Cell] -// cdb-command:dx w1,d -// cdb-check:w1,d : 42 [Type: alloc::rc::Weak] -// cdb-check: [] [Type: alloc::rc::Weak] -// cdb-check: [Reference count] : 2 [Type: core::cell::Cell] +// cdb-command:dx slice_rc,d +// cdb-check:slice_rc,d : { len=3 } [Type: alloc::rc::Rc >] +// cdb-check: [Length] : 3 [Type: unsigned __int64] +// cdb-check: [Reference count] : 41 [Type: core::cell::Cell] // cdb-check: [Weak reference count] : 2 [Type: core::cell::Cell] +// cdb-check: [0] : 1 [Type: u32] +// cdb-check: [1] : 2 [Type: u32] +// cdb-check: [2] : 3 [Type: u32] + +// cdb-command:dx slice_rc_weak,d +// cdb-check:slice_rc_weak,d : { len=3 } [Type: alloc::rc::Weak >] +// cdb-check: [Length] : 3 [Type: unsigned __int64] +// cdb-check: [Reference count] : 41 [Type: core::cell::Cell] +// cdb-check: [Weak reference count] : 2 [Type: core::cell::Cell] +// cdb-check: [0] : 1 [Type: u32] +// cdb-check: [1] : 2 [Type: u32] +// cdb-check: [2] : 3 [Type: u32] -// cdb-command:dx a,d -// cdb-check:a,d : 42 [Type: alloc::sync::Arc] -// cdb-check: [] [Type: alloc::sync::Arc] -// cdb-check: [Reference count] : 2 [Type: core::sync::atomic::AtomicUsize] +// cdb-command:dx dyn_arc,d +// cdb-check:dyn_arc,d [Type: alloc::sync::Arc >] +// cdb-check: [Reference count] : 51 [Type: core::sync::atomic::AtomicUsize] // cdb-check: [Weak reference count] : 2 [Type: core::sync::atomic::AtomicUsize] -// cdb-command:dx a1,d -// cdb-check:a1,d : 42 [Type: alloc::sync::Arc] -// cdb-check: [] [Type: alloc::sync::Arc] -// cdb-check: [Reference count] : 2 [Type: core::sync::atomic::AtomicUsize] +// cdb-command:dx dyn_arc_weak,d +// cdb-check:dyn_arc_weak,d [Type: alloc::sync::Weak >] +// cdb-check: [Reference count] : 51 [Type: core::sync::atomic::AtomicUsize] // cdb-check: [Weak reference count] : 2 [Type: core::sync::atomic::AtomicUsize] -// cdb-command:dx w2,d -// cdb-check:w2,d : 42 [Type: alloc::sync::Weak] -// cdb-check: [] [Type: alloc::sync::Weak] -// cdb-check: [Reference count] : 2 [Type: core::sync::atomic::AtomicUsize] +// cdb-command:dx slice_arc,d +// cdb-check:slice_arc,d : { len=3 } [Type: alloc::sync::Arc >] +// cdb-check: [Length] : 3 [Type: unsigned __int64] +// cdb-check: [Reference count] : 61 [Type: core::sync::atomic::AtomicUsize] +// cdb-check: [Weak reference count] : 2 [Type: core::sync::atomic::AtomicUsize] +// cdb-check: [0] : 4 [Type: u32] +// cdb-check: [1] : 5 [Type: u32] +// cdb-check: [2] : 6 [Type: u32] + +// cdb-command:dx slice_arc_weak,d +// cdb-check:slice_arc_weak,d : { len=3 } [Type: alloc::sync::Weak >] +// cdb-check: [Length] : 3 [Type: unsigned __int64] +// cdb-check: [Reference count] : 61 [Type: core::sync::atomic::AtomicUsize] // cdb-check: [Weak reference count] : 2 [Type: core::sync::atomic::AtomicUsize] +// cdb-check: [0] : 4 [Type: u32] +// cdb-check: [1] : 5 [Type: u32] +// cdb-check: [2] : 6 [Type: u32] +use std::fmt::Debug; use std::rc::Rc; use std::sync::Arc; fn main() { - let r = Rc::new(42); - let r1 = Rc::clone(&r); - let w1 = Rc::downgrade(&r); + let rc = Rc::new(111); + inc_ref_count(&rc, 10); + let weak_rc = Rc::downgrade(&rc); + + let arc = Arc::new(222); + inc_ref_count(&arc, 20); + let weak_arc = Arc::downgrade(&arc); + + let dyn_rc: Rc = Rc::new(333); + inc_ref_count(&dyn_rc, 30); + let dyn_rc_weak = Rc::downgrade(&dyn_rc); + + let slice_rc: Rc<[u32]> = Rc::from(vec![1, 2, 3]); + inc_ref_count(&slice_rc, 40); + let slice_rc_weak = Rc::downgrade(&slice_rc); - let a = Arc::new(42); - let a1 = Arc::clone(&a); - let w2 = Arc::downgrade(&a); + let dyn_arc: Arc = Arc::new(444); + inc_ref_count(&dyn_arc, 50); + let dyn_arc_weak = Arc::downgrade(&dyn_arc); + + let slice_arc: Arc<[u32]> = Arc::from(vec![4, 5, 6]); + inc_ref_count(&slice_arc, 60); + let slice_arc_weak = Arc::downgrade(&slice_arc); zzz(); // #break } -fn zzz() { () } +fn inc_ref_count(rc: &T, count: usize) { + for _ in 0..count { + std::mem::forget(rc.clone()); + } +} + +fn zzz() { + () +} From 471fa05fef0b09e0430a80e3d7f205ef19fc4a86 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 15 Jun 2022 21:31:28 +0200 Subject: [PATCH 5/7] Make #[cfg(bootstrap)] not error in proc macros on later stages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As was discovered in https://github.com/rust-lang/rust/pull/93628#issuecomment-1154697627 , adding #[cfg(bootstrap)] to a rust-internal proc macro crate would yield an unexpected cfg name error, at least on later stages wher the bootstrap cfg arg wasn't set. rustc already passes arguments to mark bootstrap as expected, however the means of delivery through the RUSTFLAGS env var is unable to reach proc macro crates, as described in the issue linked in the code this commit touches. This wouldn't be an issue for cfg args that get passed through RUSTFLAGS, as they would never become *active* either, so any usage of one of these flags in a proc macro's code would legitimately yield a lint warning. But since dc302587e2cf5105a3a864319d7e7bcb434bba20, rust takes extra measures to pass --cfg=bootstrap even in proc macros, by passing it via the wrapper. Thus, we need to send the flags to mark bootstrap as expected also from the wrapper, so that #[cfg(bootstrap)] also works from proc macros. I want to thank Urgau and jplatte for helping me find the cause of this. ❤️ --- src/bootstrap/bin/rustc.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index d9467e8fd6bc1..40a3cc6d12cac 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -127,12 +127,18 @@ fn main() { } } + // Cargo doesn't pass RUSTFLAGS to proc_macros: + // https://github.com/rust-lang/cargo/issues/4423 + // Thus, if we are on stage 0, we explicitly set `--cfg=bootstrap`. + // We also declare that the flag is expected, which is mainly needed for + // later stages so that they don't warn about #[cfg(bootstrap)], + // but enabling it for stage 0 too lets any warnings, if they occur, + // occur more early on, e.g. about #[cfg(bootstrap = "foo")]. if stage == "0" { - // Cargo doesn't pass RUSTFLAGS to proc_macros: - // https://github.com/rust-lang/cargo/issues/4423 - // Set `--cfg=bootstrap` explicitly instead. cmd.arg("--cfg=bootstrap"); } + cmd.arg("-Zunstable-options"); + cmd.arg("--check-cfg=values(bootstrap)"); } if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") { From 95adaa22e0e2cb6ce9cf0521232620ffdb7b5f00 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Wed, 15 Jun 2022 18:35:41 -0400 Subject: [PATCH 6/7] The type of the slice length field is architecture dependent --- src/test/debuginfo/rc_arc.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/debuginfo/rc_arc.rs b/src/test/debuginfo/rc_arc.rs index 37e870d8a8e72..c05c565d95634 100644 --- a/src/test/debuginfo/rc_arc.rs +++ b/src/test/debuginfo/rc_arc.rs @@ -58,7 +58,7 @@ // cdb-command:dx slice_rc,d // cdb-check:slice_rc,d : { len=3 } [Type: alloc::rc::Rc >] -// cdb-check: [Length] : 3 [Type: unsigned __int64] +// cdb-check: [Length] : 3 [Type: [...]] // cdb-check: [Reference count] : 41 [Type: core::cell::Cell] // cdb-check: [Weak reference count] : 2 [Type: core::cell::Cell] // cdb-check: [0] : 1 [Type: u32] @@ -67,7 +67,7 @@ // cdb-command:dx slice_rc_weak,d // cdb-check:slice_rc_weak,d : { len=3 } [Type: alloc::rc::Weak >] -// cdb-check: [Length] : 3 [Type: unsigned __int64] +// cdb-check: [Length] : 3 [Type: [...]] // cdb-check: [Reference count] : 41 [Type: core::cell::Cell] // cdb-check: [Weak reference count] : 2 [Type: core::cell::Cell] // cdb-check: [0] : 1 [Type: u32] @@ -86,7 +86,7 @@ // cdb-command:dx slice_arc,d // cdb-check:slice_arc,d : { len=3 } [Type: alloc::sync::Arc >] -// cdb-check: [Length] : 3 [Type: unsigned __int64] +// cdb-check: [Length] : 3 [Type: [...]] // cdb-check: [Reference count] : 61 [Type: core::sync::atomic::AtomicUsize] // cdb-check: [Weak reference count] : 2 [Type: core::sync::atomic::AtomicUsize] // cdb-check: [0] : 4 [Type: u32] @@ -95,7 +95,7 @@ // cdb-command:dx slice_arc_weak,d // cdb-check:slice_arc_weak,d : { len=3 } [Type: alloc::sync::Weak >] -// cdb-check: [Length] : 3 [Type: unsigned __int64] +// cdb-check: [Length] : 3 [Type: [...]] // cdb-check: [Reference count] : 61 [Type: core::sync::atomic::AtomicUsize] // cdb-check: [Weak reference count] : 2 [Type: core::sync::atomic::AtomicUsize] // cdb-check: [0] : 4 [Type: u32] From 8527a3d36985bed55de1832c3c1f3d470720bb0b Mon Sep 17 00:00:00 2001 From: xFrednet Date: Sun, 5 Jun 2022 12:33:45 +0200 Subject: [PATCH 7/7] Support lint expectations for `--force-warn` lints (RFC 2383) --- compiler/rustc_codegen_llvm/src/back/write.rs | 2 +- compiler/rustc_codegen_ssa/src/back/write.rs | 2 +- .../src/annotate_snippet_emitter_writer.rs | 2 +- compiler/rustc_errors/src/diagnostic.rs | 10 +- compiler/rustc_errors/src/json.rs | 2 +- compiler/rustc_errors/src/lib.rs | 96 ++++++++++++------- .../rustc_expand/src/proc_macro_server.rs | 2 +- compiler/rustc_lint/src/context.rs | 4 +- compiler/rustc_lint/src/expect.rs | 16 ++-- compiler/rustc_lint/src/levels.rs | 22 +++-- compiler/rustc_lint_defs/src/lib.rs | 14 ++- compiler/rustc_middle/src/lint.rs | 16 +++- compiler/rustc_session/src/config.rs | 2 +- compiler/rustc_session/src/session.rs | 15 +++ .../force_warn_expected_lints_fulfilled.rs | 48 ++++++++++ ...force_warn_expected_lints_fulfilled.stderr | 40 ++++++++ .../force_warn_expected_lints_unfulfilled.rs | 49 ++++++++++ ...rce_warn_expected_lints_unfulfilled.stderr | 38 ++++++++ src/tools/rustfmt/src/parse/session.rs | 8 +- 19 files changed, 317 insertions(+), 71 deletions(-) create mode 100644 src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.rs create mode 100644 src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.stderr create mode 100644 src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_unfulfilled.rs create mode 100644 src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_unfulfilled.stderr diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 99e30531c226f..dce95e932ddfa 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -340,7 +340,7 @@ fn report_inline_asm( } let level = match level { llvm::DiagnosticLevel::Error => Level::Error { lint: false }, - llvm::DiagnosticLevel::Warning => Level::Warning, + llvm::DiagnosticLevel::Warning => Level::Warning(None), llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note, }; cgcx.diag_emitter.inline_asm_error(cookie as u32, msg, level, source); diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 02c7c1a435fae..632f07c5c2d80 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1761,7 +1761,7 @@ impl SharedEmitterMain { let mut err = match level { Level::Error { lint: false } => sess.struct_err(msg).forget_guarantee(), - Level::Warning => sess.struct_warn(msg), + Level::Warning(_) => sess.struct_warn(msg), Level::Note => sess.struct_note_without_error(msg), _ => bug!("Invalid inline asm diagnostic level"), }; diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index 1f270fcf56baa..0fcd61d1e58c3 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -87,7 +87,7 @@ fn annotation_type_for_level(level: Level) -> AnnotationType { Level::Bug | Level::DelayedBug | Level::Fatal | Level::Error { .. } => { AnnotationType::Error } - Level::Warning => AnnotationType::Warning, + Level::Warning(_) => AnnotationType::Warning, Level::Note | Level::OnceNote => AnnotationType::Note, Level::Help => AnnotationType::Help, // FIXME(#59346): Not sure how to map this level diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index eaceecc166778..e559053bdfbd8 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -208,7 +208,7 @@ impl Diagnostic { | Level::Error { .. } | Level::FailureNote => true, - Level::Warning + Level::Warning(_) | Level::Note | Level::OnceNote | Level::Help @@ -221,7 +221,9 @@ impl Diagnostic { &mut self, unstable_to_stable: &FxHashMap, ) { - if let Level::Expect(expectation_id) = &mut self.level { + if let Level::Expect(expectation_id) | Level::Warning(Some(expectation_id)) = + &mut self.level + { if expectation_id.is_stable() { return; } @@ -445,7 +447,7 @@ impl Diagnostic { /// Add a warning attached to this diagnostic. pub fn warn(&mut self, msg: impl Into) -> &mut Self { - self.sub(Level::Warning, msg, MultiSpan::new(), None); + self.sub(Level::Warning(None), msg, MultiSpan::new(), None); self } @@ -456,7 +458,7 @@ impl Diagnostic { sp: S, msg: impl Into, ) -> &mut Self { - self.sub(Level::Warning, msg, sp.into(), None); + self.sub(Level::Warning(None), msg, sp.into(), None); self } diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index fff35ac6ac894..d4d1491c16945 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -154,7 +154,7 @@ impl Emitter for JsonEmitter { .into_iter() .map(|mut diag| { if diag.level == crate::Level::Allow { - diag.level = crate::Level::Warning; + diag.level = crate::Level::Warning(None); } FutureBreakageItem { diagnostic: Diagnostic::from_errors_diagnostic(&diag, self) } }) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 83fe2a2df892f..1f6f271899d92 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -658,6 +658,23 @@ impl Handler { result } + /// Construct a builder at the `Warning` level at the given `span` and with the `msg`. + /// The `id` is used for lint emissions which should also fulfill a lint expectation. + /// + /// Attempting to `.emit()` the builder will only emit if either: + /// * `can_emit_warnings` is `true` + /// * `is_force_warn` was set in `DiagnosticId::Lint` + pub fn struct_span_warn_with_expectation( + &self, + span: impl Into, + msg: impl Into, + id: LintExpectationId, + ) -> DiagnosticBuilder<'_, ()> { + let mut result = self.struct_warn_with_expectation(msg, id); + result.set_span(span); + result + } + /// Construct a builder at the `Allow` level at the given `span` and with the `msg`. pub fn struct_span_allow( &self, @@ -688,7 +705,21 @@ impl Handler { /// * `can_emit_warnings` is `true` /// * `is_force_warn` was set in `DiagnosticId::Lint` pub fn struct_warn(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { - DiagnosticBuilder::new(self, Level::Warning, msg) + DiagnosticBuilder::new(self, Level::Warning(None), msg) + } + + /// Construct a builder at the `Warning` level with the `msg`. The `id` is used for + /// lint emissions which should also fulfill a lint expectation. + /// + /// Attempting to `.emit()` the builder will only emit if either: + /// * `can_emit_warnings` is `true` + /// * `is_force_warn` was set in `DiagnosticId::Lint` + pub fn struct_warn_with_expectation( + &self, + msg: impl Into, + id: LintExpectationId, + ) -> DiagnosticBuilder<'_, ()> { + DiagnosticBuilder::new(self, Level::Warning(Some(id)), msg) } /// Construct a builder at the `Allow` level with the `msg`. @@ -842,7 +873,7 @@ impl Handler { } pub fn span_warn(&self, span: impl Into, msg: impl Into) { - self.emit_diag_at_span(Diagnostic::new(Warning, msg), span); + self.emit_diag_at_span(Diagnostic::new(Warning(None), msg), span); } pub fn span_warn_with_code( @@ -851,7 +882,7 @@ impl Handler { msg: impl Into, code: DiagnosticId, ) { - self.emit_diag_at_span(Diagnostic::new_with_code(Warning, Some(code), msg), span); + self.emit_diag_at_span(Diagnostic::new_with_code(Warning(None), Some(code), msg), span); } pub fn span_bug(&self, span: impl Into, msg: impl Into) -> ! { @@ -905,7 +936,7 @@ impl Handler { } pub fn warn(&self, msg: impl Into) { - let mut db = DiagnosticBuilder::new(self, Warning, msg); + let mut db = DiagnosticBuilder::new(self, Warning(None), msg); db.emit(); } @@ -1010,13 +1041,10 @@ impl Handler { for mut diag in diags.into_iter() { diag.update_unstable_expectation_id(unstable_to_stable); - let stable_id = diag - .level - .get_expectation_id() - .expect("all diagnostics inside `unstable_expect_diagnostics` must have a `LintExpectationId`"); - inner.fulfilled_expectations.insert(stable_id); - - (*TRACK_DIAGNOSTICS)(&diag); + // Here the diagnostic is given back to `emit_diagnostic` where it was first + // intercepted. Now it should be processed as usual, since the unstable expectation + // id is now stable. + inner.emit_diagnostic(&mut diag); } } @@ -1066,6 +1094,15 @@ impl HandlerInner { // FIXME(eddyb) this should ideally take `diagnostic` by value. fn emit_diagnostic(&mut self, diagnostic: &mut Diagnostic) -> Option { + // The `LintExpectationId` can be stable or unstable depending on when it was created. + // Diagnostics created before the definition of `HirId`s are unstable and can not yet + // be stored. Instead, they are buffered until the `LintExpectationId` is replaced by + // a stable one by the `LintLevelsBuilder`. + if let Some(LintExpectationId::Unstable { .. }) = diagnostic.level.get_expectation_id() { + self.unstable_expect_diagnostics.push(diagnostic.clone()); + return None; + } + if diagnostic.level == Level::DelayedBug { // FIXME(eddyb) this should check for `has_errors` and stop pushing // once *any* errors were emitted (and truncate `delayed_span_bugs` @@ -1082,7 +1119,12 @@ impl HandlerInner { self.future_breakage_diagnostics.push(diagnostic.clone()); } - if diagnostic.level == Warning + if let Some(expectation_id) = diagnostic.level.get_expectation_id() { + self.suppressed_expected_diag = true; + self.fulfilled_expectations.insert(expectation_id); + } + + if matches!(diagnostic.level, Warning(_)) && !self.flags.can_emit_warnings && !diagnostic.is_force_warn() { @@ -1092,22 +1134,9 @@ impl HandlerInner { return None; } - // The `LintExpectationId` can be stable or unstable depending on when it was created. - // Diagnostics created before the definition of `HirId`s are unstable and can not yet - // be stored. Instead, they are buffered until the `LintExpectationId` is replaced by - // a stable one by the `LintLevelsBuilder`. - if let Level::Expect(LintExpectationId::Unstable { .. }) = diagnostic.level { - self.unstable_expect_diagnostics.push(diagnostic.clone()); - return None; - } - (*TRACK_DIAGNOSTICS)(diagnostic); - if let Level::Expect(expectation_id) = diagnostic.level { - self.suppressed_expected_diag = true; - self.fulfilled_expectations.insert(expectation_id); - return None; - } else if diagnostic.level == Allow { + if matches!(diagnostic.level, Level::Expect(_) | Level::Allow) { return None; } @@ -1144,7 +1173,7 @@ impl HandlerInner { self.emitter.emit_diagnostic(&diagnostic); if diagnostic.is_error() { self.deduplicated_err_count += 1; - } else if diagnostic.level == Warning { + } else if let Warning(_) = diagnostic.level { self.deduplicated_warn_count += 1; } } @@ -1197,7 +1226,7 @@ impl HandlerInner { match (errors.len(), warnings.len()) { (0, 0) => return, (0, _) => self.emitter.emit_diagnostic(&Diagnostic::new( - Level::Warning, + Level::Warning(None), DiagnosticMessage::Str(warnings), )), (_, 0) => { @@ -1430,7 +1459,10 @@ pub enum Level { /// If this error comes from a lint, don't abort compilation even when abort_if_errors() is called. lint: bool, }, - Warning, + /// This [`LintExpectationId`] is used for expected lint diagnostics, which should + /// also emit a warning due to the `force-warn` flag. In all other cases this should + /// be `None`. + Warning(Option), Note, /// A note that is only emitted once. OnceNote, @@ -1453,7 +1485,7 @@ impl Level { Bug | DelayedBug | Fatal | Error { .. } => { spec.set_fg(Some(Color::Red)).set_intense(true); } - Warning => { + Warning(_) => { spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows)); } Note | OnceNote => { @@ -1472,7 +1504,7 @@ impl Level { match self { Bug | DelayedBug => "error: internal compiler error", Fatal | Error { .. } => "error", - Warning => "warning", + Warning(_) => "warning", Note | OnceNote => "note", Help => "help", FailureNote => "failure-note", @@ -1487,7 +1519,7 @@ impl Level { pub fn get_expectation_id(&self) -> Option { match self { - Level::Expect(id) => Some(*id), + Level::Expect(id) | Level::Warning(Some(id)) => Some(*id), _ => None, } } diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index d4407c03d03f5..e7ce9e7f1b705 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -267,7 +267,7 @@ impl ToInternal for Level { fn to_internal(self) -> rustc_errors::Level { match self { Level::Error => rustc_errors::Level::Error { lint: false }, - Level::Warning => rustc_errors::Level::Warning, + Level::Warning => rustc_errors::Level::Warning(None), Level::Note => rustc_errors::Level::Note, Level::Help => rustc_errors::Level::Help, _ => unreachable!("unknown proc_macro::Level variant: {:?}", self), diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 2c6bdef361aab..d1950ed9aee08 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -324,7 +324,7 @@ impl LintStore { registered_tools: &RegisteredTools, ) { let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name); - if lint_name_only == crate::WARNINGS.name_lower() && level == Level::ForceWarn { + if lint_name_only == crate::WARNINGS.name_lower() && matches!(level, Level::ForceWarn(_)) { struct_span_err!( sess, DUMMY_SP, @@ -375,7 +375,7 @@ impl LintStore { match level { Level::Allow => "-A", Level::Warn => "-W", - Level::ForceWarn => "--force-warn", + Level::ForceWarn(_) => "--force-warn", Level::Deny => "-D", Level::Forbid => "-F", Level::Expect(_) => { diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index dc48ac0a618e7..95e3125045db4 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -19,16 +19,16 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option) { let lint_expectations = &tcx.lint_levels(()).lint_expectations; for (id, expectation) in lint_expectations { - if !fulfilled_expectations.contains(id) - && tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter)) - { - // This check will always be true, since `lint_expectations` only - // holds stable ids - if let LintExpectationId::Stable { hir_id, .. } = id { + // This check will always be true, since `lint_expectations` only + // holds stable ids + if let LintExpectationId::Stable { hir_id, .. } = id { + if !fulfilled_expectations.contains(&id) + && tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter)) + { emit_unfulfilled_expectation_lint(tcx, *hir_id, expectation); - } else { - unreachable!("at this stage all `LintExpectationId`s are stable"); } + } else { + unreachable!("at this stage all `LintExpectationId`s are stable"); } } } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 54f2c72527924..0c7b9a7ccb09a 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -117,7 +117,9 @@ impl<'s> LintLevelsBuilder<'s> { }; for id in ids { // ForceWarn and Forbid cannot be overridden - if let Some((Level::ForceWarn | Level::Forbid, _)) = self.current_specs().get(&id) { + if let Some((Level::ForceWarn(_) | Level::Forbid, _)) = + self.current_specs().get(&id) + { continue; } @@ -226,11 +228,18 @@ impl<'s> LintLevelsBuilder<'s> { return; } - if let Level::ForceWarn = old_level { - self.current_specs_mut().insert(id, (old_level, old_src)); - } else { - self.current_specs_mut().insert(id, (level, src)); - } + match (old_level, level) { + // If the new level is an expectation store it in `ForceWarn` + (Level::ForceWarn(_), Level::Expect(expectation_id)) => self + .current_specs_mut() + .insert(id, (Level::ForceWarn(Some(expectation_id)), old_src)), + // Keep `ForceWarn` level but drop the expectation + (Level::ForceWarn(_), _) => { + self.current_specs_mut().insert(id, (Level::ForceWarn(None), old_src)) + } + // Set the lint level as normal + _ => self.current_specs_mut().insert(id, (level, src)), + }; } /// Pushes a list of AST lint attributes onto this context. @@ -269,6 +278,7 @@ impl<'s> LintLevelsBuilder<'s> { let level = match Level::from_attr(attr) { None => continue, + // This is the only lint level with a `LintExpectationId` that can be created from an attribute Some(Level::Expect(unstable_id)) if let Some(hir_id) = source_hir_id => { let stable_id = self.create_stable_id(unstable_id, hir_id, attr_index); diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 913dc58a10259..cb1c6f4098767 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -162,13 +162,19 @@ pub enum Level { /// /// See RFC 2383. /// - /// The `LintExpectationId` is used to later link a lint emission to the actual + /// The [`LintExpectationId`] is used to later link a lint emission to the actual /// expectation. It can be ignored in most cases. Expect(LintExpectationId), /// The `warn` level will produce a warning if the lint was violated, however the /// compiler will continue with its execution. Warn, - ForceWarn, + /// This lint level is a special case of [`Warn`], that can't be overridden. This is used + /// to ensure that a lint can't be suppressed. This lint level can currently only be set + /// via the console and is therefore session specific. + /// + /// The [`LintExpectationId`] is intended to fulfill expectations marked via the + /// `#[expect]` attribute, that will still be suppressed due to the level. + ForceWarn(Option), /// The `deny` level will produce an error and stop further execution after the lint /// pass is complete. Deny, @@ -184,7 +190,7 @@ impl Level { Level::Allow => "allow", Level::Expect(_) => "expect", Level::Warn => "warn", - Level::ForceWarn => "force-warn", + Level::ForceWarn(_) => "force-warn", Level::Deny => "deny", Level::Forbid => "forbid", } @@ -219,7 +225,7 @@ impl Level { pub fn is_error(self) -> bool { match self { - Level::Allow | Level::Expect(_) | Level::Warn | Level::ForceWarn => false, + Level::Allow | Level::Expect(_) | Level::Warn | Level::ForceWarn(_) => false, Level::Deny | Level::Forbid => true, } } diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index c7c5f56867a5d..215d8decf2a88 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -115,7 +115,7 @@ impl LintLevelSets { // Ensure that we never exceed the `--cap-lints` argument // unless the source is a --force-warn - level = if let LintLevelSource::CommandLine(_, Level::ForceWarn) = src { + level = if let LintLevelSource::CommandLine(_, Level::ForceWarn(_)) = src { level } else { cmp::min(level, self.lint_cap) @@ -266,7 +266,7 @@ pub fn explain_lint_level_source( Level::Deny => "-D", Level::Forbid => "-F", Level::Allow => "-A", - Level::ForceWarn => "--force-warn", + Level::ForceWarn(_) => "--force-warn", Level::Expect(_) => { unreachable!("the expect level does not have a commandline flag") } @@ -352,8 +352,14 @@ pub fn struct_lint_level<'s, 'd>( // create a `DiagnosticBuilder` and continue as we would for warnings. sess.struct_expect("", expect_id) } - (Level::Warn | Level::ForceWarn, Some(span)) => sess.struct_span_warn(span, ""), - (Level::Warn | Level::ForceWarn, None) => sess.struct_warn(""), + (Level::ForceWarn(Some(expect_id)), Some(span)) => { + sess.struct_span_warn_with_expectation(span, "", expect_id) + } + (Level::ForceWarn(Some(expect_id)), None) => { + sess.struct_warn_with_expectation("", expect_id) + } + (Level::Warn | Level::ForceWarn(None), Some(span)) => sess.struct_span_warn(span, ""), + (Level::Warn | Level::ForceWarn(None), None) => sess.struct_warn(""), (Level::Deny | Level::Forbid, Some(span)) => { let mut builder = sess.diagnostic().struct_err_lint(""); builder.set_span(span); @@ -398,7 +404,7 @@ pub fn struct_lint_level<'s, 'd>( explain_lint_level_source(lint, level, src, &mut err); let name = lint.name_lower(); - let is_force_warn = matches!(level, Level::ForceWarn); + let is_force_warn = matches!(level, Level::ForceWarn(_)); err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn }); if let Some(future_incompatible) = future_incompatible { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index c4a67006504fd..89d724626ccc0 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1432,7 +1432,7 @@ pub fn get_cmd_lint_options( let mut lint_opts_with_position = vec![]; let mut describe_lints = false; - for level in [lint::Allow, lint::Warn, lint::ForceWarn, lint::Deny, lint::Forbid] { + for level in [lint::Allow, lint::Warn, lint::ForceWarn(None), lint::Deny, lint::Forbid] { for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) { if lint_name == "help" { describe_lints = true; diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index b2c23cda6aae5..06f3e59f9f783 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -286,6 +286,14 @@ impl Session { ) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_span_warn(sp, msg) } + pub fn struct_span_warn_with_expectation>( + &self, + sp: S, + msg: impl Into, + id: lint::LintExpectationId, + ) -> DiagnosticBuilder<'_, ()> { + self.diagnostic().struct_span_warn_with_expectation(sp, msg, id) + } pub fn struct_span_warn_with_code>( &self, sp: S, @@ -297,6 +305,13 @@ impl Session { pub fn struct_warn(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_warn(msg) } + pub fn struct_warn_with_expectation( + &self, + msg: impl Into, + id: lint::LintExpectationId, + ) -> DiagnosticBuilder<'_, ()> { + self.diagnostic().struct_warn_with_expectation(msg, id) + } pub fn struct_span_allow>( &self, sp: S, diff --git a/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.rs b/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.rs new file mode 100644 index 0000000000000..a3c3933d70038 --- /dev/null +++ b/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.rs @@ -0,0 +1,48 @@ +// compile-flags: --force-warn while_true +// compile-flags: --force-warn unused_variables +// compile-flags: --force-warn unused_mut +// check-pass + +#![feature(lint_reasons)] + +fn expect_early_pass_lint() { + #[expect(while_true)] + while true { + //~^ WARNING denote infinite loops with `loop { ... }` [while_true] + //~| NOTE requested on the command line with `--force-warn while-true` + //~| HELP use `loop` + println!("I never stop") + } +} + +#[expect(unused_variables, reason="")] +fn check_specific_lint() { + let x = 2; + //~^ WARNING unused variable: `x` [unused_variables] + //~| NOTE requested on the command line with `--force-warn unused-variables` + //~| HELP if this is intentional, prefix it with an underscore +} + +#[expect(unused)] +fn check_multiple_lints_with_lint_group() { + let fox_name = "Sir Nibbles"; + //~^ WARNING unused variable: `fox_name` [unused_variables] + //~| HELP if this is intentional, prefix it with an underscore + + let mut what_does_the_fox_say = "*ding* *deng* *dung*"; + //~^ WARNING variable does not need to be mutable [unused_mut] + //~| NOTE requested on the command line with `--force-warn unused-mut` + //~| HELP remove this `mut` + + println!("The fox says: {what_does_the_fox_say}"); +} + +#[allow(unused_variables)] +fn check_expect_overrides_allow_lint_level() { + #[expect(unused_variables)] + let this_should_fulfill_the_expectation = "The `#[allow]` has no power here"; + //~^ WARNING unused variable: `this_should_fulfill_the_expectation` [unused_variables] + //~| HELP if this is intentional, prefix it with an underscore +} + +fn main() {} diff --git a/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.stderr b/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.stderr new file mode 100644 index 0000000000000..06befcbb5117e --- /dev/null +++ b/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.stderr @@ -0,0 +1,40 @@ +warning: denote infinite loops with `loop { ... }` + --> $DIR/force_warn_expected_lints_fulfilled.rs:10:5 + | +LL | while true { + | ^^^^^^^^^^ help: use `loop` + | + = note: requested on the command line with `--force-warn while-true` + +warning: unused variable: `x` + --> $DIR/force_warn_expected_lints_fulfilled.rs:20:9 + | +LL | let x = 2; + | ^ help: if this is intentional, prefix it with an underscore: `_x` + | + = note: requested on the command line with `--force-warn unused-variables` + +warning: unused variable: `fox_name` + --> $DIR/force_warn_expected_lints_fulfilled.rs:28:9 + | +LL | let fox_name = "Sir Nibbles"; + | ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_fox_name` + +warning: unused variable: `this_should_fulfill_the_expectation` + --> $DIR/force_warn_expected_lints_fulfilled.rs:43:9 + | +LL | let this_should_fulfill_the_expectation = "The `#[allow]` has no power here"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_this_should_fulfill_the_expectation` + +warning: variable does not need to be mutable + --> $DIR/force_warn_expected_lints_fulfilled.rs:32:9 + | +LL | let mut what_does_the_fox_say = "*ding* *deng* *dung*"; + | ----^^^^^^^^^^^^^^^^^^^^^ + | | + | help: remove this `mut` + | + = note: requested on the command line with `--force-warn unused-mut` + +warning: 5 warnings emitted + diff --git a/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_unfulfilled.rs b/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_unfulfilled.rs new file mode 100644 index 0000000000000..080e300232b03 --- /dev/null +++ b/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_unfulfilled.rs @@ -0,0 +1,49 @@ +// compile-flags: --force-warn while_true +// compile-flags: --force-warn unused_variables +// compile-flags: --force-warn unused_mut +// check-pass + +#![feature(lint_reasons)] + +fn expect_early_pass_lint(terminate: bool) { + #[expect(while_true)] + //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations] + //~| NOTE `#[warn(unfulfilled_lint_expectations)]` on by default + while !terminate { + println!("Do you know what a spin lock is?") + } +} + +#[expect(unused_variables, reason="")] +//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations] +//~| NOTE +fn check_specific_lint() { + let _x = 2; +} + +#[expect(unused)] +//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations] +fn check_multiple_lints_with_lint_group() { + let fox_name = "Sir Nibbles"; + + let what_does_the_fox_say = "*ding* *deng* *dung*"; + + println!("The fox says: {what_does_the_fox_say}"); + println!("~ {fox_name}") +} + + +#[expect(unused)] +//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations] +fn check_overridden_expectation_lint_level() { + #[allow(unused_variables)] + let this_should_not_fulfill_the_expectation = "maybe"; + //~^ WARNING unused variable: `this_should_not_fulfill_the_expectation` [unused_variables] + //~| NOTE requested on the command line with `--force-warn unused-variables` + //~| HELP if this is intentional, prefix it with an underscore +} + +fn main() { + check_multiple_lints_with_lint_group(); + check_overridden_expectation_lint_level(); +} diff --git a/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_unfulfilled.stderr b/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_unfulfilled.stderr new file mode 100644 index 0000000000000..c74fabe27dc87 --- /dev/null +++ b/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_unfulfilled.stderr @@ -0,0 +1,38 @@ +warning: unused variable: `this_should_not_fulfill_the_expectation` + --> $DIR/force_warn_expected_lints_unfulfilled.rs:40:9 + | +LL | let this_should_not_fulfill_the_expectation = "maybe"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_this_should_not_fulfill_the_expectation` + | + = note: requested on the command line with `--force-warn unused-variables` + +warning: this lint expectation is unfulfilled + --> $DIR/force_warn_expected_lints_unfulfilled.rs:9:14 + | +LL | #[expect(while_true)] + | ^^^^^^^^^^ + | + = note: `#[warn(unfulfilled_lint_expectations)]` on by default + +warning: this lint expectation is unfulfilled + --> $DIR/force_warn_expected_lints_unfulfilled.rs:17:10 + | +LL | #[expect(unused_variables, reason="")] + | ^^^^^^^^^^^^^^^^ + | + = note: + +warning: this lint expectation is unfulfilled + --> $DIR/force_warn_expected_lints_unfulfilled.rs:24:10 + | +LL | #[expect(unused)] + | ^^^^^^ + +warning: this lint expectation is unfulfilled + --> $DIR/force_warn_expected_lints_unfulfilled.rs:36:10 + | +LL | #[expect(unused)] + | ^^^^^^ + +warning: 5 warnings emitted + diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs index 4408e20747a6a..8b706b8bcb49a 100644 --- a/src/tools/rustfmt/src/parse/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -433,7 +433,7 @@ mod tests { Some(ignore_list), ); let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1))); - let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span)); + let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(span)); emitter.emit_diagnostic(&non_fatal_diagnostic); assert_eq!(num_emitted_errors.load(Ordering::Acquire), 0); assert_eq!(can_reset_errors.load(Ordering::Acquire), true); @@ -457,7 +457,7 @@ mod tests { None, ); let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1))); - let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span)); + let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(span)); emitter.emit_diagnostic(&non_fatal_diagnostic); assert_eq!(num_emitted_errors.load(Ordering::Acquire), 1); assert_eq!(can_reset_errors.load(Ordering::Acquire), false); @@ -494,8 +494,8 @@ mod tests { ); let bar_span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1))); let foo_span = MultiSpan::from_span(mk_sp(BytePos(21), BytePos(22))); - let bar_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(bar_span)); - let foo_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(foo_span)); + let bar_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(bar_span)); + let foo_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(foo_span)); let fatal_diagnostic = build_diagnostic(DiagnosticLevel::Fatal, None); emitter.emit_diagnostic(&bar_diagnostic); emitter.emit_diagnostic(&foo_diagnostic);