about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_data_structures/src/flock.rs25
-rw-r--r--compiler/rustc_data_structures/src/profiling.rs63
-rw-r--r--compiler/rustc_lint/src/types/literal.rs31
-rw-r--r--compiler/rustc_span/src/analyze_source_file.rs160
-rw-r--r--library/alloc/src/sync.rs8
-rw-r--r--library/core/src/macros/mod.rs52
-rw-r--r--library/core/tests/lib.rs3
-rw-r--r--library/core/tests/macros.rs53
-rw-r--r--library/core/tests/macros_bootstrap.rs193
-rw-r--r--library/std/src/sync/lazy_lock.rs2
-rw-r--r--tests/ui/lint/type-overflow.rs26
-rw-r--r--tests/ui/lint/type-overflow.stderr53
12 files changed, 629 insertions, 40 deletions
diff --git a/compiler/rustc_data_structures/src/flock.rs b/compiler/rustc_data_structures/src/flock.rs
index e03962a54ec..292a33d5646 100644
--- a/compiler/rustc_data_structures/src/flock.rs
+++ b/compiler/rustc_data_structures/src/flock.rs
@@ -4,6 +4,7 @@
 //! green/native threading. This is just a bare-bones enough solution for
 //! librustdoc, it is not production quality at all.
 
+#[cfg(bootstrap)]
 cfg_match! {
     cfg(target_os = "linux") => {
         mod linux;
@@ -27,4 +28,28 @@ cfg_match! {
     }
 }
 
+#[cfg(not(bootstrap))]
+cfg_match! {
+    target_os = "linux" => {
+        mod linux;
+        use linux as imp;
+    }
+    target_os = "redox" => {
+        mod linux;
+        use linux as imp;
+    }
+    unix => {
+        mod unix;
+        use unix as imp;
+    }
+    windows => {
+        mod windows;
+        use self::windows as imp;
+    }
+    _ => {
+        mod unsupported;
+        use unsupported as imp;
+    }
+}
+
 pub use imp::Lock;
diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index 19050746c2f..18e98e6c39f 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -860,6 +860,7 @@ fn get_thread_id() -> u32 {
 }
 
 // Memory reporting
+#[cfg(bootstrap)]
 cfg_match! {
     cfg(windows) => {
         pub fn get_resident_set_size() -> Option<usize> {
@@ -921,5 +922,67 @@ cfg_match! {
     }
 }
 
+#[cfg(not(bootstrap))]
+cfg_match! {
+    windows => {
+        pub fn get_resident_set_size() -> Option<usize> {
+            use std::mem;
+
+            use windows::{
+                Win32::System::ProcessStatus::{K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS},
+                Win32::System::Threading::GetCurrentProcess,
+            };
+
+            let mut pmc = PROCESS_MEMORY_COUNTERS::default();
+            let pmc_size = mem::size_of_val(&pmc);
+            unsafe {
+                K32GetProcessMemoryInfo(
+                    GetCurrentProcess(),
+                    &mut pmc,
+                    pmc_size as u32,
+                )
+            }
+            .ok()
+            .ok()?;
+
+            Some(pmc.WorkingSetSize)
+        }
+    }
+    target_os = "macos" => {
+        pub fn get_resident_set_size() -> Option<usize> {
+            use libc::{c_int, c_void, getpid, proc_pidinfo, proc_taskinfo, PROC_PIDTASKINFO};
+            use std::mem;
+            const PROC_TASKINFO_SIZE: c_int = mem::size_of::<proc_taskinfo>() as c_int;
+
+            unsafe {
+                let mut info: proc_taskinfo = mem::zeroed();
+                let info_ptr = &mut info as *mut proc_taskinfo as *mut c_void;
+                let pid = getpid() as c_int;
+                let ret = proc_pidinfo(pid, PROC_PIDTASKINFO, 0, info_ptr, PROC_TASKINFO_SIZE);
+                if ret == PROC_TASKINFO_SIZE {
+                    Some(info.pti_resident_size as usize)
+                } else {
+                    None
+                }
+            }
+        }
+    }
+    unix => {
+        pub fn get_resident_set_size() -> Option<usize> {
+            let field = 1;
+            let contents = fs::read("/proc/self/statm").ok()?;
+            let contents = String::from_utf8(contents).ok()?;
+            let s = contents.split_whitespace().nth(field)?;
+            let npages = s.parse::<usize>().ok()?;
+            Some(npages * 4096)
+        }
+    }
+    _ => {
+        pub fn get_resident_set_size() -> Option<usize> {
+            None
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_lint/src/types/literal.rs b/compiler/rustc_lint/src/types/literal.rs
index 83942918e3b..4b5163522f8 100644
--- a/compiler/rustc_lint/src/types/literal.rs
+++ b/compiler/rustc_lint/src/types/literal.rs
@@ -204,20 +204,35 @@ fn get_type_suggestion(t: Ty<'_>, val: u128, negative: bool) -> Option<&'static
     match t.kind() {
         ty::Uint(ty::UintTy::Usize) | ty::Int(ty::IntTy::Isize) => None,
         ty::Uint(_) => Some(Integer::fit_unsigned(val).uint_ty_str()),
-        ty::Int(_) if negative => Some(Integer::fit_signed(-(val as i128)).int_ty_str()),
-        ty::Int(int) => {
-            let signed = Integer::fit_signed(val as i128);
-            let unsigned = Integer::fit_unsigned(val);
-            Some(if Some(unsigned.size().bits()) == int.bit_width() {
-                unsigned.uint_ty_str()
+        ty::Int(_) => {
+            let signed = literal_to_i128(val, negative).map(Integer::fit_signed);
+            if negative {
+                signed.map(Integer::int_ty_str)
             } else {
-                signed.int_ty_str()
-            })
+                let unsigned = Integer::fit_unsigned(val);
+                Some(if let Some(signed) = signed {
+                    if unsigned.size() < signed.size() {
+                        unsigned.uint_ty_str()
+                    } else {
+                        signed.int_ty_str()
+                    }
+                } else {
+                    unsigned.uint_ty_str()
+                })
+            }
         }
         _ => None,
     }
 }
 
+fn literal_to_i128(val: u128, negative: bool) -> Option<i128> {
+    if negative {
+        (val <= i128::MAX as u128 + 1).then(|| val.wrapping_neg() as i128)
+    } else {
+        val.try_into().ok()
+    }
+}
+
 fn lint_int_literal<'tcx>(
     cx: &LateContext<'tcx>,
     type_limits: &TypeLimits,
diff --git a/compiler/rustc_span/src/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs
index 28ce883daee..fba20566580 100644
--- a/compiler/rustc_span/src/analyze_source_file.rs
+++ b/compiler/rustc_span/src/analyze_source_file.rs
@@ -29,6 +29,7 @@ pub(crate) fn analyze_source_file(src: &str) -> (Vec<RelativeBytePos>, Vec<Multi
     (lines, multi_byte_chars)
 }
 
+#[cfg(bootstrap)]
 cfg_match! {
     cfg(any(target_arch = "x86", target_arch = "x86_64")) => {
         fn analyze_source_file_dispatch(
@@ -185,6 +186,165 @@ cfg_match! {
         }
     }
 }
+
+#[cfg(not(bootstrap))]
+cfg_match! {
+    any(target_arch = "x86", target_arch = "x86_64") => {
+        fn analyze_source_file_dispatch(
+            src: &str,
+            lines: &mut Vec<RelativeBytePos>,
+            multi_byte_chars: &mut Vec<MultiByteChar>,
+        ) {
+            if is_x86_feature_detected!("sse2") {
+                unsafe {
+                    analyze_source_file_sse2(src, lines, multi_byte_chars);
+                }
+            } else {
+                analyze_source_file_generic(
+                    src,
+                    src.len(),
+                    RelativeBytePos::from_u32(0),
+                    lines,
+                    multi_byte_chars,
+                );
+            }
+        }
+
+        /// Checks 16 byte chunks of text at a time. If the chunk contains
+        /// something other than printable ASCII characters and newlines, the
+        /// function falls back to the generic implementation. Otherwise it uses
+        /// SSE2 intrinsics to quickly find all newlines.
+        #[target_feature(enable = "sse2")]
+        unsafe fn analyze_source_file_sse2(
+            src: &str,
+            lines: &mut Vec<RelativeBytePos>,
+            multi_byte_chars: &mut Vec<MultiByteChar>,
+        ) {
+            #[cfg(target_arch = "x86")]
+            use std::arch::x86::*;
+            #[cfg(target_arch = "x86_64")]
+            use std::arch::x86_64::*;
+
+            const CHUNK_SIZE: usize = 16;
+
+            let src_bytes = src.as_bytes();
+
+            let chunk_count = src.len() / CHUNK_SIZE;
+
+            // This variable keeps track of where we should start decoding a
+            // chunk. If a multi-byte character spans across chunk boundaries,
+            // we need to skip that part in the next chunk because we already
+            // handled it.
+            let mut intra_chunk_offset = 0;
+
+            for chunk_index in 0..chunk_count {
+                let ptr = src_bytes.as_ptr() as *const __m128i;
+                // We don't know if the pointer is aligned to 16 bytes, so we
+                // use `loadu`, which supports unaligned loading.
+                let chunk = unsafe { _mm_loadu_si128(ptr.add(chunk_index)) };
+
+                // For character in the chunk, see if its byte value is < 0, which
+                // indicates that it's part of a UTF-8 char.
+                let multibyte_test = unsafe { _mm_cmplt_epi8(chunk, _mm_set1_epi8(0)) };
+                // Create a bit mask from the comparison results.
+                let multibyte_mask = unsafe { _mm_movemask_epi8(multibyte_test) };
+
+                // If the bit mask is all zero, we only have ASCII chars here:
+                if multibyte_mask == 0 {
+                    assert!(intra_chunk_offset == 0);
+
+                    // Check if there are any control characters in the chunk. All
+                    // control characters that we can encounter at this point have a
+                    // byte value less than 32 or ...
+                    let control_char_test0 = unsafe { _mm_cmplt_epi8(chunk, _mm_set1_epi8(32)) };
+                    let control_char_mask0 = unsafe { _mm_movemask_epi8(control_char_test0) };
+
+                    // ... it's the ASCII 'DEL' character with a value of 127.
+                    let control_char_test1 = unsafe { _mm_cmpeq_epi8(chunk, _mm_set1_epi8(127)) };
+                    let control_char_mask1 = unsafe { _mm_movemask_epi8(control_char_test1) };
+
+                    let control_char_mask = control_char_mask0 | control_char_mask1;
+
+                    if control_char_mask != 0 {
+                        // Check for newlines in the chunk
+                        let newlines_test = unsafe { _mm_cmpeq_epi8(chunk, _mm_set1_epi8(b'\n' as i8)) };
+                        let newlines_mask = unsafe { _mm_movemask_epi8(newlines_test) };
+
+                        if control_char_mask == newlines_mask {
+                            // All control characters are newlines, record them
+                            let mut newlines_mask = 0xFFFF0000 | newlines_mask as u32;
+                            let output_offset = RelativeBytePos::from_usize(chunk_index * CHUNK_SIZE + 1);
+
+                            loop {
+                                let index = newlines_mask.trailing_zeros();
+
+                                if index >= CHUNK_SIZE as u32 {
+                                    // We have arrived at the end of the chunk.
+                                    break;
+                                }
+
+                                lines.push(RelativeBytePos(index) + output_offset);
+
+                                // Clear the bit, so we can find the next one.
+                                newlines_mask &= (!1) << index;
+                            }
+
+                            // We are done for this chunk. All control characters were
+                            // newlines and we took care of those.
+                            continue;
+                        } else {
+                            // Some of the control characters are not newlines,
+                            // fall through to the slow path below.
+                        }
+                    } else {
+                        // No control characters, nothing to record for this chunk
+                        continue;
+                    }
+                }
+
+                // The slow path.
+                // There are control chars in here, fallback to generic decoding.
+                let scan_start = chunk_index * CHUNK_SIZE + intra_chunk_offset;
+                intra_chunk_offset = analyze_source_file_generic(
+                    &src[scan_start..],
+                    CHUNK_SIZE - intra_chunk_offset,
+                    RelativeBytePos::from_usize(scan_start),
+                    lines,
+                    multi_byte_chars,
+                );
+            }
+
+            // There might still be a tail left to analyze
+            let tail_start = chunk_count * CHUNK_SIZE + intra_chunk_offset;
+            if tail_start < src.len() {
+                analyze_source_file_generic(
+                    &src[tail_start..],
+                    src.len() - tail_start,
+                    RelativeBytePos::from_usize(tail_start),
+                    lines,
+                    multi_byte_chars,
+                );
+            }
+        }
+    }
+    _ => {
+        // The target (or compiler version) does not support SSE2 ...
+        fn analyze_source_file_dispatch(
+            src: &str,
+            lines: &mut Vec<RelativeBytePos>,
+            multi_byte_chars: &mut Vec<MultiByteChar>,
+        ) {
+            analyze_source_file_generic(
+                src,
+                src.len(),
+                RelativeBytePos::from_u32(0),
+                lines,
+                multi_byte_chars,
+            );
+        }
+    }
+}
+
 // `scan_len` determines the number of bytes in `src` to scan. Note that the
 // function can read past `scan_len` if a multi-byte character start within the
 // range but extends past it. The overflow is returned by the function.
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 11e7128e677..8eee7cff208 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -1397,6 +1397,8 @@ impl<T: ?Sized> Arc<T> {
     /// different types. See [`mem::transmute`][transmute] for more information
     /// on what restrictions apply in this case.
     ///
+    /// The raw pointer must point to a block of memory allocated by the global allocator.
+    ///
     /// The user of `from_raw` has to make sure a specific value of `T` is only
     /// dropped once.
     ///
@@ -1452,7 +1454,8 @@ impl<T: ?Sized> Arc<T> {
     ///
     /// The pointer must have been obtained through `Arc::into_raw`, and the
     /// associated `Arc` instance must be valid (i.e. the strong count must be at
-    /// least 1) for the duration of this method.
+    /// least 1) for the duration of this method, and `ptr` must point to a block of memory
+    /// allocated by the global allocator.
     ///
     /// # Examples
     ///
@@ -1486,7 +1489,8 @@ impl<T: ?Sized> Arc<T> {
     ///
     /// The pointer must have been obtained through `Arc::into_raw`, and the
     /// associated `Arc` instance must be valid (i.e. the strong count must be at
-    /// least 1) when invoking this method. This method can be used to release the final
+    /// least 1) when invoking this method, and `ptr` must point to a block of memory
+    /// allocated by the global allocator. This method can be used to release the final
     /// `Arc` and backing storage, but **should not** be called after the final `Arc` has been
     /// released.
     ///
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 402b436d28e..5c04e5a40df 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -224,6 +224,7 @@ pub macro assert_matches {
 ///     }
 /// }
 /// ```
+#[cfg(bootstrap)]
 #[unstable(feature = "cfg_match", issue = "115585")]
 #[rustc_diagnostic_item = "cfg_match"]
 pub macro cfg_match {
@@ -284,6 +285,57 @@ pub macro cfg_match {
     }
 }
 
+/// A macro for defining `#[cfg]` match-like statements.
+///
+/// It is similar to the `if/elif` C preprocessor macro by allowing definition of a cascade of
+/// `#[cfg]` cases, emitting the implementation which matches first.
+///
+/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code
+/// without having to rewrite each clause multiple times.
+///
+/// Trailing `_` wildcard match arms are **optional** and they indicate a fallback branch when
+/// all previous declarations do not evaluate to true.
+///
+/// # Example
+///
+/// ```
+/// #![feature(cfg_match)]
+///
+/// cfg_match! {
+///     unix => {
+///         fn foo() { /* unix specific functionality */ }
+///     }
+///     target_pointer_width = "32" => {
+///         fn foo() { /* non-unix, 32-bit functionality */ }
+///     }
+///     _ => {
+///         fn foo() { /* fallback implementation */ }
+///     }
+/// }
+/// ```
+#[cfg(not(bootstrap))]
+#[unstable(feature = "cfg_match", issue = "115585")]
+#[rustc_diagnostic_item = "cfg_match"]
+pub macro cfg_match {
+    ({ $($tt:tt)* }) => {{
+        cfg_match! { $($tt)* }
+    }},
+    (_ => { $($output:tt)* }) => {
+        $($output)*
+    },
+    (
+        $cfg:meta => $output:tt
+        $($( $rest:tt )+)?
+    ) => {
+        #[cfg($cfg)]
+        cfg_match! { _ => $output }
+        $(
+            #[cfg(not($cfg))]
+            cfg_match! { $($rest)+ }
+        )?
+    },
+}
+
 /// Asserts that a boolean expression is `true` at runtime.
 ///
 /// This will invoke the [`panic!`] macro if the provided expression cannot be
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 18feee9fb25..a8980c5f30a 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -153,7 +153,10 @@ mod intrinsics;
 mod io;
 mod iter;
 mod lazy;
+#[cfg(not(bootstrap))]
 mod macros;
+#[cfg(bootstrap)]
+mod macros_bootstrap;
 mod manually_drop;
 mod mem;
 mod net;
diff --git a/library/core/tests/macros.rs b/library/core/tests/macros.rs
index fdb4ea29412..b30a40b7df2 100644
--- a/library/core/tests/macros.rs
+++ b/library/core/tests/macros.rs
@@ -10,7 +10,7 @@ struct Struct;
 
 impl Trait for Struct {
     cfg_match! {
-        cfg(feature = "blah") => {
+        feature = "blah" => {
             fn blah(&self) {
                 unimplemented!();
             }
@@ -47,21 +47,21 @@ fn matches_leading_pipe() {
 #[test]
 fn cfg_match_basic() {
     cfg_match! {
-        cfg(target_pointer_width = "64") => { fn f0_() -> bool { true }}
+        target_pointer_width = "64" => { fn f0_() -> bool { true }}
     }
 
     cfg_match! {
-        cfg(unix) => { fn f1_() -> bool { true }}
-        cfg(any(target_os = "macos", target_os = "linux")) => { fn f1_() -> bool { false }}
+        unix => { fn f1_() -> bool { true } }
+        any(target_os = "macos", target_os = "linux") => { fn f1_() -> bool { false }}
     }
 
     cfg_match! {
-        cfg(target_pointer_width = "32") => { fn f2_() -> bool { false }}
-        cfg(target_pointer_width = "64") => { fn f2_() -> bool { true }}
+        target_pointer_width = "32" => { fn f2_() -> bool { false } }
+        target_pointer_width = "64" => { fn f2_() -> bool { true } }
     }
 
     cfg_match! {
-        cfg(target_pointer_width = "16") => { fn f3_() -> i32 { 1 }}
+        target_pointer_width = "16" => { fn f3_() -> i32 { 1 } }
         _ => { fn f3_() -> i32 { 2 }}
     }
 
@@ -83,7 +83,7 @@ fn cfg_match_basic() {
 #[test]
 fn cfg_match_debug_assertions() {
     cfg_match! {
-        cfg(debug_assertions) => {
+        debug_assertions => {
             assert!(cfg!(debug_assertions));
             assert_eq!(4, 2+2);
         }
@@ -98,13 +98,13 @@ fn cfg_match_debug_assertions() {
 #[test]
 fn cfg_match_no_duplication_on_64() {
     cfg_match! {
-        cfg(windows) => {
+        windows => {
             fn foo() {}
         }
-        cfg(unix) => {
+        unix => {
             fn foo() {}
         }
-        cfg(target_pointer_width = "64") => {
+        target_pointer_width = "64" => {
             fn foo() {}
         }
     }
@@ -114,7 +114,7 @@ fn cfg_match_no_duplication_on_64() {
 #[test]
 fn cfg_match_options() {
     cfg_match! {
-        cfg(test) => {
+        test => {
             use core::option::Option as Option2;
             fn works1() -> Option2<u32> { Some(1) }
         }
@@ -122,26 +122,26 @@ fn cfg_match_options() {
     }
 
     cfg_match! {
-        cfg(feature = "foo") => { fn works2() -> bool { false } }
-        cfg(test) => { fn works2() -> bool { true } }
+        feature = "foo" => { fn works2() -> bool { false } }
+        test => { fn works2() -> bool { true } }
         _ => { fn works2() -> bool { false } }
     }
 
     cfg_match! {
-        cfg(feature = "foo") => { fn works3() -> bool { false } }
+        feature = "foo" => { fn works3() -> bool { false } }
         _ => { fn works3() -> bool { true } }
     }
 
     cfg_match! {
-        cfg(test) => {
+        test => {
             use core::option::Option as Option3;
             fn works4() -> Option3<u32> { Some(1) }
         }
     }
 
     cfg_match! {
-        cfg(feature = "foo") => { fn works5() -> bool { false } }
-        cfg(test) => { fn works5() -> bool { true } }
+        feature = "foo" => { fn works5() -> bool { false } }
+        test => { fn works5() -> bool { true } }
     }
 
     assert!(works1().is_some());
@@ -154,7 +154,7 @@ fn cfg_match_options() {
 #[test]
 fn cfg_match_two_functions() {
     cfg_match! {
-        cfg(target_pointer_width = "64") => {
+        target_pointer_width = "64" => {
             fn foo1() {}
             fn bar1() {}
         }
@@ -178,7 +178,7 @@ fn cfg_match_two_functions() {
 
 fn _accepts_expressions() -> i32 {
     cfg_match! {
-        cfg(unix) => { 1 }
+        unix => { 1 }
         _ => { 2 }
     }
 }
@@ -189,7 +189,18 @@ fn _allows_stmt_expr_attributes() {
     let one = 1;
     let two = 2;
     cfg_match! {
-        cfg(unix) => { one * two; }
+        unix => { one * two; }
         _ => { one + two; }
     }
 }
+
+fn _expression() {
+    let _ = cfg_match!({
+        windows => {
+            " XP"
+        }
+        _ => {
+            ""
+        }
+    });
+}
diff --git a/library/core/tests/macros_bootstrap.rs b/library/core/tests/macros_bootstrap.rs
new file mode 100644
index 00000000000..f10ef862c5d
--- /dev/null
+++ b/library/core/tests/macros_bootstrap.rs
@@ -0,0 +1,193 @@
+#![allow(unused_must_use)]
+
+#[allow(dead_code)]
+trait Trait {
+    fn blah(&self);
+}
+
+#[allow(dead_code)]
+struct Struct;
+
+impl Trait for Struct {
+    cfg_match! {
+        cfg(feature = "blah") => {
+            fn blah(&self) {
+                unimplemented!();
+            }
+        }
+        _ => {
+            fn blah(&self) {
+                unimplemented!();
+            }
+        }
+    }
+}
+
+#[test]
+fn assert_eq_trailing_comma() {
+    assert_eq!(1, 1,);
+}
+
+#[test]
+fn assert_escape() {
+    assert!(r#"☃\backslash"#.contains("\\"));
+}
+
+#[test]
+fn assert_ne_trailing_comma() {
+    assert_ne!(1, 2,);
+}
+
+#[rustfmt::skip]
+#[test]
+fn matches_leading_pipe() {
+    matches!(1, | 1 | 2 | 3);
+}
+
+#[test]
+fn cfg_match_basic() {
+    cfg_match! {
+        cfg(target_pointer_width = "64") => { fn f0_() -> bool { true }}
+    }
+
+    cfg_match! {
+        cfg(unix) => { fn f1_() -> bool { true }}
+        cfg(any(target_os = "macos", target_os = "linux")) => { fn f1_() -> bool { false }}
+    }
+
+    cfg_match! {
+        cfg(target_pointer_width = "32") => { fn f2_() -> bool { false }}
+        cfg(target_pointer_width = "64") => { fn f2_() -> bool { true }}
+    }
+
+    cfg_match! {
+        cfg(target_pointer_width = "16") => { fn f3_() -> i32 { 1 }}
+        _ => { fn f3_() -> i32 { 2 }}
+    }
+
+    #[cfg(target_pointer_width = "64")]
+    assert!(f0_());
+
+    #[cfg(unix)]
+    assert!(f1_());
+
+    #[cfg(target_pointer_width = "32")]
+    assert!(!f2_());
+    #[cfg(target_pointer_width = "64")]
+    assert!(f2_());
+
+    #[cfg(not(target_pointer_width = "16"))]
+    assert_eq!(f3_(), 2);
+}
+
+#[test]
+fn cfg_match_debug_assertions() {
+    cfg_match! {
+        cfg(debug_assertions) => {
+            assert!(cfg!(debug_assertions));
+            assert_eq!(4, 2+2);
+        }
+        _ => {
+            assert!(cfg!(not(debug_assertions)));
+            assert_eq!(10, 5+5);
+        }
+    }
+}
+
+#[cfg(target_pointer_width = "64")]
+#[test]
+fn cfg_match_no_duplication_on_64() {
+    cfg_match! {
+        cfg(windows) => {
+            fn foo() {}
+        }
+        cfg(unix) => {
+            fn foo() {}
+        }
+        cfg(target_pointer_width = "64") => {
+            fn foo() {}
+        }
+    }
+    foo();
+}
+
+#[test]
+fn cfg_match_options() {
+    cfg_match! {
+        cfg(test) => {
+            use core::option::Option as Option2;
+            fn works1() -> Option2<u32> { Some(1) }
+        }
+        _ => { fn works1() -> Option<u32> { None } }
+    }
+
+    cfg_match! {
+        cfg(feature = "foo") => { fn works2() -> bool { false } }
+        cfg(test) => { fn works2() -> bool { true } }
+        _ => { fn works2() -> bool { false } }
+    }
+
+    cfg_match! {
+        cfg(feature = "foo") => { fn works3() -> bool { false } }
+        _ => { fn works3() -> bool { true } }
+    }
+
+    cfg_match! {
+        cfg(test) => {
+            use core::option::Option as Option3;
+            fn works4() -> Option3<u32> { Some(1) }
+        }
+    }
+
+    cfg_match! {
+        cfg(feature = "foo") => { fn works5() -> bool { false } }
+        cfg(test) => { fn works5() -> bool { true } }
+    }
+
+    assert!(works1().is_some());
+    assert!(works2());
+    assert!(works3());
+    assert!(works4().is_some());
+    assert!(works5());
+}
+
+#[test]
+fn cfg_match_two_functions() {
+    cfg_match! {
+        cfg(target_pointer_width = "64") => {
+            fn foo1() {}
+            fn bar1() {}
+        }
+        _ => {
+            fn foo2() {}
+            fn bar2() {}
+        }
+    }
+
+    #[cfg(target_pointer_width = "64")]
+    {
+        foo1();
+        bar1();
+    }
+    #[cfg(not(target_pointer_width = "64"))]
+    {
+        foo2();
+        bar2();
+    }
+}
+
+fn _accepts_expressions() -> i32 {
+    cfg_match! {
+        cfg(unix) => { 1 }
+        _ => { 2 }
+    }
+}
+
+fn _allows_stmt_expr_attributes() {
+    let one = 1;
+    let two = 2;
+    cfg_match! {
+        cfg(unix) => { one * two; }
+        _ => { one + two; }
+    }
+}
diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs
index 1e4f9b79e0f..98c83d8d326 100644
--- a/library/std/src/sync/lazy_lock.rs
+++ b/library/std/src/sync/lazy_lock.rs
@@ -31,7 +31,7 @@ union Data<T, F> {
 /// ```
 /// use std::sync::LazyLock;
 ///
-/// // n.b. static items do not call [`Drop`] on program termination, so this won't be deallocated.
+/// // Note: static items do not call [`Drop`] on program termination, so this won't be deallocated.
 /// // this is fine, as the OS can deallocate the terminated program faster than we can free memory
 /// // but tools like valgrind might report "memory leaks" as it isn't obvious this is intentional.
 /// static DEEP_THOUGHT: LazyLock<String> = LazyLock::new(|| {
diff --git a/tests/ui/lint/type-overflow.rs b/tests/ui/lint/type-overflow.rs
index 7239e1c9837..1e74a8925f6 100644
--- a/tests/ui/lint/type-overflow.rs
+++ b/tests/ui/lint/type-overflow.rs
@@ -3,20 +3,46 @@
 
 fn main() {
     let error = 255i8; //~WARNING literal out of range for `i8`
+    //~^ HELP consider using the type `u8` instead
 
     let ok = 0b1000_0001; // should be ok -> i32
     let ok = 0b0111_1111i8; // should be ok -> 127i8
 
     let fail = 0b1000_0001i8; //~WARNING literal out of range for `i8`
+    //~^ HELP consider using the type `u8` instead
+    //~| HELP consider using the type `u8` for the literal and cast it to `i8`
 
     let fail = 0x8000_0000_0000_0000i64; //~WARNING literal out of range for `i64`
+    //~^ HELP consider using the type `u64` instead
+    //~| HELP consider using the type `u64` for the literal and cast it to `i64`
 
     let fail = 0x1_FFFF_FFFFu32; //~WARNING literal out of range for `u32`
+    //~^ HELP consider using the type `u64` instead
 
     let fail: i128 = 0x8000_0000_0000_0000_0000_0000_0000_0000;
     //~^ WARNING literal out of range for `i128`
+    //~| HELP consider using the type `u128` instead
+    //~| HELP consider using the type `u128` for the literal and cast it to `i128`
+
+    let fail = 0x8000_0000_0000_0000_0000_0000_0000_0000;
+    //~^ WARNING literal out of range for `i32`
+    //~| HELP consider using the type `u128` instead
+
+    let fail = -0x8000_0000_0000_0000_0000_0000_0000_0000; // issue #131849
+    //~^ WARNING literal out of range for `i32`
+    //~| HELP consider using the type `i128` instead
+
+    let fail = -0x8000_0000_0000_0000_0000_0000_0000_0001i128;
+    //~^ WARNING literal out of range for `i128`
+
+    let fail = 340282366920938463463374607431768211455i8;
+    //~^ WARNING literal out of range for `i8`
+    //~| HELP consider using the type `u128` instead
 
     let fail = 0x8FFF_FFFF_FFFF_FFFE; //~WARNING literal out of range for `i32`
+    //~| HELP consider using the type `u64` instead
+    //~| HELP
 
     let fail = -0b1111_1111i8; //~WARNING literal out of range for `i8`
+    //~| HELP consider using the type `i16` instead
 }
diff --git a/tests/ui/lint/type-overflow.stderr b/tests/ui/lint/type-overflow.stderr
index e7c90dcc81b..9fdb05ed1c0 100644
--- a/tests/ui/lint/type-overflow.stderr
+++ b/tests/ui/lint/type-overflow.stderr
@@ -13,7 +13,7 @@ LL | #![warn(overflowing_literals)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 warning: literal out of range for `i8`
-  --> $DIR/type-overflow.rs:10:16
+  --> $DIR/type-overflow.rs:11:16
    |
 LL |     let fail = 0b1000_0001i8;
    |                ^^^^^^^^^^^^^
@@ -29,7 +29,7 @@ LL |     let fail = 0b1000_0001u8 as i8;
    |                ~~~~~~~~~~~~~~~~~~~
 
 warning: literal out of range for `i64`
-  --> $DIR/type-overflow.rs:12:16
+  --> $DIR/type-overflow.rs:15:16
    |
 LL |     let fail = 0x8000_0000_0000_0000i64;
    |                ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -45,7 +45,7 @@ LL |     let fail = 0x8000_0000_0000_0000u64 as i64;
    |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 warning: literal out of range for `u32`
-  --> $DIR/type-overflow.rs:14:16
+  --> $DIR/type-overflow.rs:19:16
    |
 LL |     let fail = 0x1_FFFF_FFFFu32;
    |                ^^^^^^^^^^^^^^^^ help: consider using the type `u64` instead: `0x1_FFFF_FFFFu64`
@@ -53,7 +53,7 @@ LL |     let fail = 0x1_FFFF_FFFFu32;
    = note: the literal `0x1_FFFF_FFFFu32` (decimal `8589934591`) does not fit into the type `u32` and will become `4294967295u32`
 
 warning: literal out of range for `i128`
-  --> $DIR/type-overflow.rs:16:22
+  --> $DIR/type-overflow.rs:22:22
    |
 LL |     let fail: i128 = 0x8000_0000_0000_0000_0000_0000_0000_0000;
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -66,20 +66,57 @@ LL |     let fail: i128 = 0x8000_0000_0000_0000_0000_0000_0000_0000u128 as i128;
    |                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 warning: literal out of range for `i32`
-  --> $DIR/type-overflow.rs:19:16
+  --> $DIR/type-overflow.rs:27:16
+   |
+LL |     let fail = 0x8000_0000_0000_0000_0000_0000_0000_0000;
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the literal `0x8000_0000_0000_0000_0000_0000_0000_0000` (decimal `170141183460469231731687303715884105728`) does not fit into the type `i32` and will become `0i32`
+   = help: consider using the type `u128` instead
+
+warning: literal out of range for `i32`
+  --> $DIR/type-overflow.rs:31:17
+   |
+LL |     let fail = -0x8000_0000_0000_0000_0000_0000_0000_0000; // issue #131849
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the literal `0x8000_0000_0000_0000_0000_0000_0000_0000` (decimal `170141183460469231731687303715884105728`) does not fit into the type `i32`
+   = note: and the value `-0x8000_0000_0000_0000_0000_0000_0000_0000` will become `0i32`
+   = help: consider using the type `i128` instead
+
+warning: literal out of range for `i128`
+  --> $DIR/type-overflow.rs:35:17
+   |
+LL |     let fail = -0x8000_0000_0000_0000_0000_0000_0000_0001i128;
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the literal `0x8000_0000_0000_0000_0000_0000_0000_0001i128` (decimal `170141183460469231731687303715884105729`) does not fit into the type `i128`
+   = note: and the value `-0x8000_0000_0000_0000_0000_0000_0000_0001i128` will become `170141183460469231731687303715884105727i128`
+
+warning: literal out of range for `i8`
+  --> $DIR/type-overflow.rs:38:16
+   |
+LL |     let fail = 340282366920938463463374607431768211455i8;
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the literal `340282366920938463463374607431768211455i8` does not fit into the type `i8` whose range is `-128..=127`
+   = help: consider using the type `u128` instead
+
+warning: literal out of range for `i32`
+  --> $DIR/type-overflow.rs:42:16
    |
 LL |     let fail = 0x8FFF_FFFF_FFFF_FFFE;
    |                ^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the literal `0x8FFF_FFFF_FFFF_FFFE` (decimal `10376293541461622782`) does not fit into the type `i32` and will become `-2i32`
-   = help: consider using the type `i128` instead
+   = help: consider using the type `u64` instead
 help: to use as a negative number (decimal `-2`), consider using the type `u32` for the literal and cast it to `i32`
    |
 LL |     let fail = 0x8FFF_FFFF_FFFF_FFFEu32 as i32;
    |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 warning: literal out of range for `i8`
-  --> $DIR/type-overflow.rs:21:17
+  --> $DIR/type-overflow.rs:46:17
    |
 LL |     let fail = -0b1111_1111i8;
    |                 ^^^^^^^^^^^^^ help: consider using the type `i16` instead: `0b1111_1111i16`
@@ -87,5 +124,5 @@ LL |     let fail = -0b1111_1111i8;
    = note: the literal `0b1111_1111i8` (decimal `255`) does not fit into the type `i8`
    = note: and the value `-0b1111_1111i8` will become `1i8`
 
-warning: 7 warnings emitted
+warning: 11 warnings emitted