From 849c5254afdeb96a740cfac989a382fde69b6067 Mon Sep 17 00:00:00 2001 From: RustyYato Date: Tue, 13 Feb 2024 18:16:00 -0700 Subject: [PATCH 1/8] Change f32::midpoint to upcast to f64 This has been verified by kani as a correct optimization see: https://github.com/rust-lang/rust/issues/110840#issuecomment-1942587398 The new implementation is branchless, and only differs in which NaN values are produced (if any are produced at all). Which is fine to change. Aside from NaN handling, this implementation produces bitwise identical results to the original implementation. The new implementation is gated on targets that have a fast 64-bit floating point implementation in hardware, and on WASM. --- library/core/src/num/f32.rs | 55 +++++++++++++++++++++++------------ library/core/tests/num/mod.rs | 29 ++++++++++++++++-- 2 files changed, 62 insertions(+), 22 deletions(-) diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 047cb64ce5069..7551a50949201 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1016,25 +1016,42 @@ impl f32 { /// ``` #[unstable(feature = "num_midpoint", issue = "110840")] pub fn midpoint(self, other: f32) -> f32 { - const LO: f32 = f32::MIN_POSITIVE * 2.; - const HI: f32 = f32::MAX / 2.; - - let (a, b) = (self, other); - let abs_a = a.abs_private(); - let abs_b = b.abs_private(); - - if abs_a <= HI && abs_b <= HI { - // Overflow is impossible - (a + b) / 2. - } else if abs_a < LO { - // Not safe to halve a - a + (b / 2.) - } else if abs_b < LO { - // Not safe to halve b - (a / 2.) + b - } else { - // Not safe to halve a and b - (a / 2.) + (b / 2.) + cfg_if! { + if #[cfg(any( + target_arch = "x86_64", + target_arch = "aarch64", + all(any(target_arch="riscv32", target_arch= "riscv64"), target_feature="d"), + all(target_arch = "arm", target_feature="vfp2"), + target_arch = "wasm32", + target_arch = "wasm64", + ))] { + // whitelist the faster implementation to targets that have known good 64-bit float + // implementations. Falling back to the branchy code on targets that don't have + // 64-bit hardware floats or buggy implementations. + // see: https://github.com/rust-lang/rust/pull/121062#issuecomment-2123408114 + ((f64::from(self) + f64::from(other)) / 2.0) as f32 + } else { + const LO: f32 = f32::MIN_POSITIVE * 2.; + const HI: f32 = f32::MAX / 2.; + + let (a, b) = (self, other); + let abs_a = a.abs_private(); + let abs_b = b.abs_private(); + + if abs_a <= HI && abs_b <= HI { + // Overflow is impossible + (a + b) / 2. + } else if abs_a < LO { + // Not safe to halve a + a + (b / 2.) + } else if abs_b < LO { + // Not safe to halve b + (a / 2.) + b + } else { + // Not safe to halve a and b + (a / 2.) + (b / 2.) + } + } } } diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs index 863da9b18a289..4b41db72f9bd3 100644 --- a/library/core/tests/num/mod.rs +++ b/library/core/tests/num/mod.rs @@ -719,7 +719,7 @@ assume_usize_width! { } macro_rules! test_float { - ($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr, $min: expr, $max: expr, $min_pos: expr) => { + ($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr, $min: expr, $max: expr, $min_pos: expr, $max_exp:expr) => { mod $modname { #[test] fn min() { @@ -870,6 +870,27 @@ macro_rules! test_float { assert!(($nan as $fty).midpoint(1.0).is_nan()); assert!((1.0 as $fty).midpoint($nan).is_nan()); assert!(($nan as $fty).midpoint($nan).is_nan()); + + // test if large differences in magnitude are still correctly computed. + // NOTE: that because of how small x and y are, x + y can never overflow + // so (x + y) / 2.0 is always correct + // in particular, `2.pow(i)` will never be at the max exponent, so it could + // be safely doubled, while j is significantly smaller. + for i in $max_exp.saturating_sub(64)..$max_exp { + for j in 0..64u8 { + let large = <$fty>::from(2.0f32).powi(i); + // a much smaller number, such that there is no chance of overflow to test + // potential double rounding in midpoint's implementation. + let small = <$fty>::from(2.0f32).powi($max_exp - 1) + * <$fty>::EPSILON + * <$fty>::from(j); + + let naive = (large + small) / 2.0; + let midpoint = large.midpoint(small); + + assert_eq!(naive, midpoint); + } + } } #[test] fn rem_euclid() { @@ -902,7 +923,8 @@ test_float!( f32::NAN, f32::MIN, f32::MAX, - f32::MIN_POSITIVE + f32::MIN_POSITIVE, + f32::MAX_EXP ); test_float!( f64, @@ -912,5 +934,6 @@ test_float!( f64::NAN, f64::MIN, f64::MAX, - f64::MIN_POSITIVE + f64::MIN_POSITIVE, + f64::MAX_EXP ); From 2416f460f8ae0aa7ed0a47a1c2ed2c3d96645435 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 31 May 2024 10:47:30 +0200 Subject: [PATCH 2/8] Add `dynamic_lib_extension` and `read_dir` functions to `run-make-support` library --- src/tools/run-make-support/src/lib.rs | 38 ++++++++++++++++++--------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 0cf64db6ac9c0..323fc40e6481e 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -123,12 +123,23 @@ pub fn dynamic_lib_name(name: &str) -> String { // ``` assert!(!name.contains(char::is_whitespace), "dynamic library name cannot contain whitespace"); + let extension = dynamic_lib_extension(); if is_darwin() { - format!("lib{name}.dylib") + format!("lib{name}.{extension}") } else if is_windows() { - format!("{name}.dll") + format!("{name}.{extension}") } else { - format!("lib{name}.so") + format!("lib{name}.{extension}") + } +} + +pub fn dynamic_lib_extension() -> &'static str { + if is_darwin() { + "dylib" + } else if is_windows() { + "dll" + } else { + "so" } } @@ -249,16 +260,13 @@ pub fn recursive_diff(dir1: impl AsRef, dir2: impl AsRef) { } let dir2 = dir2.as_ref(); - for entry in fs::read_dir(dir1).unwrap() { - let entry = entry.unwrap(); - let entry_name = entry.file_name(); - let path = entry.path(); - - if path.is_dir() { - recursive_diff(&path, &dir2.join(entry_name)); + read_dir(dir1, |entry_path| { + let entry_name = entry_path.file_name().unwrap(); + if entry_path.is_dir() { + recursive_diff(&entry_path, &dir2.join(entry_name)); } else { let path2 = dir2.join(entry_name); - let file1 = read_file(&path); + let file1 = read_file(&entry_path); let file2 = read_file(&path2); // We don't use `assert_eq!` because they are `Vec`, so not great for display. @@ -267,10 +275,16 @@ pub fn recursive_diff(dir1: impl AsRef, dir2: impl AsRef) { assert!( file1 == file2, "`{}` and `{}` have different content", - path.display(), + entry_path.display(), path2.display(), ); } + }); +} + +pub fn read_dir(dir: impl AsRef, callback: F) { + for entry in fs::read_dir(dir).unwrap() { + callback(&entry.unwrap().path()); } } From d23d3408580ca9ba64cd1418698a643ab73c3f31 Mon Sep 17 00:00:00 2001 From: Rua Date: Sun, 2 Jun 2024 12:01:07 +0200 Subject: [PATCH 3/8] Implement feature `integer_sign_cast` --- library/core/src/num/int_macros.rs | 24 ++++++++++++++++++++++++ library/core/src/num/uint_macros.rs | 24 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index c9c6e34eaad8e..e674ce46a330f 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -183,6 +183,30 @@ macro_rules! int_impl { (self as $UnsignedT).trailing_ones() } + /// Returns the bit pattern of `self` reinterpreted as an unsigned integer of the same size. + /// + /// This is a bit safer than `as` because it wouldn't silently change the size if the code + /// is refactored. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(integer_sign_cast)] + /// + #[doc = concat!("let n = -1", stringify!($SelfT), ";")] + /// + #[doc = concat!("assert_eq!(n.cast_unsigned(), ", stringify!($UnsignedT), "::MAX);")] + /// ``` + #[unstable(feature = "integer_sign_cast", issue = "125882")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn cast_unsigned(self) -> $UnsignedT { + self as $UnsignedT + } + /// Shifts the bits to the left by a specified amount, `n`, /// wrapping the truncated bits to the end of the resulting integer. /// diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 50a8f4111195d..229f5ac587806 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -184,6 +184,30 @@ macro_rules! uint_impl { (!self).trailing_zeros() } + /// Returns the bit pattern of `self` reinterpreted as a signed integer of the same size. + /// + /// This is a bit safer than `as` because it wouldn't silently change the size if the code + /// is refactored. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(integer_sign_cast)] + /// + #[doc = concat!("let n = ", stringify!($SelfT), "::MAX;")] + /// + #[doc = concat!("assert_eq!(n.cast_signed(), -1", stringify!($SignedT), ");")] + /// ``` + #[unstable(feature = "integer_sign_cast", issue = "125882")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn cast_signed(self) -> $SignedT { + self as $SignedT + } + /// Shifts the bits to the left by a specified amount, `n`, /// wrapping the truncated bits to the end of the resulting integer. /// From 32933a6869281aaa7718be4c42f5a2b0c9c9c4cf Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 31 May 2024 10:47:57 +0200 Subject: [PATCH 4/8] Migrate `run-make/c-link-to-rust-dylib` to `rmake.rs` --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/c-link-to-rust-dylib/Makefile | 21 ---------- tests/run-make/c-link-to-rust-dylib/rmake.rs | 41 +++++++++++++++++++ 3 files changed, 41 insertions(+), 22 deletions(-) delete mode 100644 tests/run-make/c-link-to-rust-dylib/Makefile create mode 100644 tests/run-make/c-link-to-rust-dylib/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index ebe9d2b7bb0b9..57637f7ae642b 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -6,7 +6,6 @@ run-make/bare-outfile/Makefile run-make/branch-protection-check-IBT/Makefile run-make/c-dynamic-dylib/Makefile run-make/c-dynamic-rlib/Makefile -run-make/c-link-to-rust-dylib/Makefile run-make/c-static-dylib/Makefile run-make/c-static-rlib/Makefile run-make/c-unwind-abi-catch-lib-panic/Makefile diff --git a/tests/run-make/c-link-to-rust-dylib/Makefile b/tests/run-make/c-link-to-rust-dylib/Makefile deleted file mode 100644 index 201f717ece49c..0000000000000 --- a/tests/run-make/c-link-to-rust-dylib/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# This test checks that C linking with Rust does not encounter any errors, with dynamic libraries. -# See https://github.com/rust-lang/rust/issues/10434 - -# ignore-cross-compile -include ../tools.mk - -all: $(TMPDIR)/$(call BIN,bar) - $(call RUN,bar) - $(call REMOVE_DYLIBS,foo) - $(call FAIL,bar) - -ifdef IS_MSVC -$(TMPDIR)/$(call BIN,bar): $(call DYLIB,foo) - $(CC) bar.c $(TMPDIR)/foo.dll.lib $(call OUT_EXE,bar) -else -$(TMPDIR)/$(call BIN,bar): $(call DYLIB,foo) - $(CC) bar.c -lfoo -o $(call RUN_BINFILE,bar) -L $(TMPDIR) -endif - -$(call DYLIB,foo): foo.rs - $(RUSTC) foo.rs diff --git a/tests/run-make/c-link-to-rust-dylib/rmake.rs b/tests/run-make/c-link-to-rust-dylib/rmake.rs new file mode 100644 index 0000000000000..5c4b6d7864964 --- /dev/null +++ b/tests/run-make/c-link-to-rust-dylib/rmake.rs @@ -0,0 +1,41 @@ +// This test checks that C linking with Rust does not encounter any errors, with dynamic libraries. +// See . + +//@ ignore-cross-compile + +use std::fs::remove_file; + +use run_make_support::{ + cc, dynamic_lib_extension, is_msvc, read_dir, run, run_fail, rustc, tmp_dir, +}; + +fn main() { + rustc().input("foo.rs").run(); + + if is_msvc() { + let lib = tmp_dir().join("foo.dll.lib"); + + cc().input("bar.c").arg(lib).out_exe("bar").run(); + } else { + cc().input("bar.c") + .arg("-lfoo") + .output(tmp_dir().join("bar")) + .library_search_path(tmp_dir()) + .run(); + } + + run("bar"); + + let expected_extension = dynamic_lib_extension(); + read_dir(tmp_dir(), |path| { + if path.is_file() + && path.extension().is_some_and(|ext| ext == expected_extension) + && path.file_name().and_then(|name| name.to_str()).is_some_and(|name| { + name.ends_with(".so") || name.ends_with(".dll") || name.ends_with(".dylib") + }) + { + remove_file(path).unwrap(); + } + }); + run_fail("bar"); +} From 3aefc4aeb27f0322b0771b187c0c0438c9789e0c Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 2 Jun 2024 12:50:49 +0200 Subject: [PATCH 5/8] Improve compiletest expected/not found formatting compiletest, oh compiletest, you are truly one of the tools in this repository. You're the omnipresent gatekeeper, ensuring that every new change works, doesn't break the world, and is nice. We thank you for your work, for your tests, for your test runs, for your features that help writing tests, for all the stability and and good you have caused. Without you, Rust wouldn't exist as it does, without you, nothing would work, without you, we would all go insane from having changes break and having to test them all by hand. Thank you, compiletest. but holy shit i fucking hate your stupid debug output so much i simply cannot take this anymore aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa By changing a few magic lines in this file called "runtest.rs", we can cause compiletest to emit nicer messages. This is widely regarded as a good thing. We stop wasting vertical space, allowing more errors to be displayed at once. Additionally, we add colors, which make it so much more pretty *and* gay, both of which are very good and useful. There's a bit of fuckery needed to get the colors to work. `colored` checks whether stdout is a terminal. We also print to stdout, so that works well. But.... for some stupid reason that I absolutely refuse to even attempt to debug, stdout is *not* a terminal when executing tests *in a terminal*. But stderr is >:). So this just checks whether stderr is a terminal. If you have a use case where you dump compiletest stdout into a place where colors are not supported while having stderr be a terminal, then I'm sorry for you, but you are gonna get colors and you're gonna like it. Stop it with the usual environment variable, which `colored` also respects by default. --- src/tools/compiletest/src/errors.rs | 12 ++++++++++++ src/tools/compiletest/src/main.rs | 10 +++++++++- src/tools/compiletest/src/runtest.rs | 18 +++++++++++++----- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index c11d3da13a8b2..7a5abc51d043e 100644 --- a/src/tools/compiletest/src/errors.rs +++ b/src/tools/compiletest/src/errors.rs @@ -57,6 +57,18 @@ pub struct Error { pub msg: String, } +impl Error { + pub fn render_for_expected(&self) -> String { + use colored::Colorize; + format!( + "{: <10}line {: >3}: {}", + self.kind.map(|kind| kind.to_string()).unwrap_or_default().to_uppercase(), + self.line_num, + self.msg.cyan(), + ) + } +} + #[derive(PartialEq, Debug)] enum WhichLine { ThisLine, diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 42c751bb6bedd..1ec3f0a0552e5 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -1,10 +1,18 @@ -use std::{env, sync::Arc}; +use std::{env, io::IsTerminal, sync::Arc}; use compiletest::{common::Mode, log_config, parse_config, run_tests}; fn main() { tracing_subscriber::fmt::init(); + // colored checks stdout by default, but for some reason only stderr is a terminal. + // compiletest *does* print many things to stdout, but it doesn't really matter. + if std::io::stderr().is_terminal() + && matches!(std::env::var("NO_COLOR").as_deref(), Err(_) | Ok("0")) + { + colored::control::set_override(true); + } + let config = Arc::new(parse_config(env::args().collect())); if config.valgrind_path.is_none() && config.force_valgrind { diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 79e158992d477..4c233eed7fddc 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -17,10 +17,10 @@ use crate::json; use crate::read2::{read2_abbreviated, Truncated}; use crate::util::{add_dylib_path, dylib_env_var, logv, PathBufExt}; use crate::ColorConfig; +use colored::Colorize; use miropt_test_tools::{files_for_miropt_test, MiroptTest, MiroptTestFile}; use regex::{Captures, Regex}; use rustfix::{apply_suggestions, get_suggestions_from_json, Filter}; - use std::collections::{HashMap, HashSet}; use std::env; use std::ffi::{OsStr, OsString}; @@ -1493,14 +1493,22 @@ impl<'test> TestCx<'test> { unexpected.len(), not_found.len() )); - println!("status: {}\ncommand: {}", proc_res.status, proc_res.cmdline); + println!("status: {}\ncommand: {}\n", proc_res.status, proc_res.cmdline); if !unexpected.is_empty() { - println!("unexpected errors (from JSON output): {:#?}\n", unexpected); + println!("{}", "--- unexpected errors (from JSON output) ---".green()); + for error in &unexpected { + println!("{}", error.render_for_expected()); + } + println!("{}", "---".green()); } if !not_found.is_empty() { - println!("not found errors (from test file): {:#?}\n", not_found); + println!("{}", "--- not found errors (from test file) ---".red()); + for error in ¬_found { + println!("{}", error.render_for_expected()); + } + println!("{}", "---\n".red()); } - panic!(); + panic!("errors differ from expected"); } } From 590c373e43a701cf0218b30bf5fffada80594d9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Sun, 2 Jun 2024 14:33:31 +0000 Subject: [PATCH 6/8] compiletest: fix outdated rmake.rs comment --- src/tools/compiletest/src/runtest.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 1c2e3c4067138..15263ab182107 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -3435,13 +3435,13 @@ impl<'test> TestCx<'test> { // ``` // base_dir/ // rmake.exe - // scratch/ + // rmake_out/ // ``` - // having the executable separate from the scratch directory allows the recipes to - // `remove_dir_all(scratch)` without running into permission denied issues because - // the executable is not under the `scratch/` directory. + // having the executable separate from the output artifacts directory allows the recipes to + // `remove_dir_all($TMPDIR)` without running into permission denied issues because + // the executable is not under the `rmake_out/` directory. // - // This setup diverges from legacy Makefile run-make tests. + // This setup intentionally diverges from legacy Makefile run-make tests. let base_dir = cwd.join(self.output_base_name()); if base_dir.exists() { self.aggressive_rm_rf(&base_dir).unwrap(); From 361c6a5c3a613d3693e9d97da3d9530cc5b7626d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 2 Jun 2024 18:15:50 +0200 Subject: [PATCH 7/8] typo: depending from -> on --- library/core/src/str/pattern.rs | 2 +- library/std/src/sys/thread_local/fast_local/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs index cc66da25795dd..8988229be2e57 100644 --- a/library/core/src/str/pattern.rs +++ b/library/core/src/str/pattern.rs @@ -342,7 +342,7 @@ pub unsafe trait ReverseSearcher<'a>: Searcher<'a> { /// /// `(&str)::Searcher` is not a `DoubleEndedSearcher` because /// the pattern `"aa"` in the haystack `"aaa"` matches as either -/// `"[aa]a"` or `"a[aa]"`, depending from which side it is searched. +/// `"[aa]a"` or `"a[aa]"`, depending on which side it is searched. pub trait DoubleEndedSearcher<'a>: ReverseSearcher<'a> {} ///////////////////////////////////////////////////////////////////////////// diff --git a/library/std/src/sys/thread_local/fast_local/mod.rs b/library/std/src/sys/thread_local/fast_local/mod.rs index 25379071cb7a6..152137d92709b 100644 --- a/library/std/src/sys/thread_local/fast_local/mod.rs +++ b/library/std/src/sys/thread_local/fast_local/mod.rs @@ -1,7 +1,7 @@ //! Thread local support for platforms with native TLS. //! //! To achieve the best performance, we choose from four different types for -//! the TLS variable, depending from the method of initialization used (`const` +//! the TLS variable, depending on the method of initialization used (`const` //! or lazy) and the drop requirements of the stored type: //! //! | | `Drop` | `!Drop` | From b181e8106c96ed7305cb9d87598249d363035fa8 Mon Sep 17 00:00:00 2001 From: Rua Date: Sun, 2 Jun 2024 21:03:24 +0200 Subject: [PATCH 8/8] Wording of the documentation --- library/core/src/num/int_macros.rs | 4 ++-- library/core/src/num/uint_macros.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index e674ce46a330f..96510ee4dca60 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -185,8 +185,8 @@ macro_rules! int_impl { /// Returns the bit pattern of `self` reinterpreted as an unsigned integer of the same size. /// - /// This is a bit safer than `as` because it wouldn't silently change the size if the code - /// is refactored. + /// This produces the same result as an `as` cast, but ensures that the bit-width remains + /// the same. /// /// # Examples /// diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 229f5ac587806..1491c27372bfb 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -186,8 +186,8 @@ macro_rules! uint_impl { /// Returns the bit pattern of `self` reinterpreted as a signed integer of the same size. /// - /// This is a bit safer than `as` because it wouldn't silently change the size if the code - /// is refactored. + /// This produces the same result as an `as` cast, but ensures that the bit-width remains + /// the same. /// /// # Examples ///