about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-06-02 21:54:30 +0000
committerbors <bors@rust-lang.org>2024-06-02 21:54:30 +0000
commit032af18af578f4283a2927fb43b90df2bbb72b67 (patch)
tree8321cf7ce119ba648ac3c6d220e73db8bb93afa7
parenta6416d8907bc94ef1a032d54cb0443cde963e455 (diff)
parent72ea7e92206cf2857c6eaa65d7fb6d043e29258f (diff)
downloadrust-032af18af578f4283a2927fb43b90df2bbb72b67.tar.gz
rust-032af18af578f4283a2927fb43b90df2bbb72b67.zip
Auto merge of #125902 - workingjubilee:rollup-f8x6iif, r=workingjubilee
Rollup of 6 pull requests

Successful merges:

 - #121062 (Change f32::midpoint to upcast to f64)
 - #125808 (Migrate `run-make/c-link-to-rust-dylib` to `rmake.rs`)
 - #125884 (Implement feature `integer_sign_cast`)
 - #125890 (Improve compiletest expected/not found formatting)
 - #125896 (compiletest: fix outdated rmake.rs comment)
 - #125898 (typo: depending from -> on)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--library/core/src/num/f32.rs55
-rw-r--r--library/core/src/num/int_macros.rs24
-rw-r--r--library/core/src/num/uint_macros.rs24
-rw-r--r--library/core/src/str/pattern.rs2
-rw-r--r--library/core/tests/num/mod.rs29
-rw-r--r--library/std/src/sys/thread_local/fast_local/mod.rs2
-rw-r--r--src/tools/compiletest/src/errors.rs12
-rw-r--r--src/tools/compiletest/src/main.rs10
-rw-r--r--src/tools/compiletest/src/runtest.rs28
-rw-r--r--src/tools/run-make-support/src/lib.rs38
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt1
-rw-r--r--tests/run-make/c-link-to-rust-dylib/Makefile21
-rw-r--r--tests/run-make/c-link-to-rust-dylib/rmake.rs41
13 files changed, 218 insertions, 69 deletions
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index 19fc4489618..22b24937cbc 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -1030,25 +1030,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/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index c9c6e34eaad..96510ee4dca 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 produces the same result as an `as` cast, but ensures that the bit-width remains
+        /// the same.
+        ///
+        /// # 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 50a8f411119..1491c27372b 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 produces the same result as an `as` cast, but ensures that the bit-width remains
+        /// the same.
+        ///
+        /// # 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.
         ///
diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs
index cc66da25795..8988229be2e 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/core/tests/num/mod.rs b/library/core/tests/num/mod.rs
index 0fed854318d..9d2912c4b22 100644
--- a/library/core/tests/num/mod.rs
+++ b/library/core/tests/num/mod.rs
@@ -729,7 +729,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() {
@@ -880,6 +880,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() {
@@ -912,7 +933,8 @@ test_float!(
     f32::NAN,
     f32::MIN,
     f32::MAX,
-    f32::MIN_POSITIVE
+    f32::MIN_POSITIVE,
+    f32::MAX_EXP
 );
 test_float!(
     f64,
@@ -922,5 +944,6 @@ test_float!(
     f64::NAN,
     f64::MIN,
     f64::MAX,
-    f64::MIN_POSITIVE
+    f64::MIN_POSITIVE,
+    f64::MAX_EXP
 );
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 25379071cb7..152137d9270 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`             |
diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs
index c11d3da13a8..7a5abc51d04 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 42c751bb6be..1ec3f0a0552 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 1c2e3c40671..9bd0002a3d9 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 &not_found {
+                    println!("{}", error.render_for_expected());
+                }
+                println!("{}", "---\n".red());
             }
-            panic!();
+            panic!("errors differ from expected");
         }
     }
 
@@ -3435,13 +3443,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();
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 0cf64db6ac9..323fc40e648 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<Path>, dir2: impl AsRef<Path>) {
     }
 
     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<u8>`, so not great for display.
@@ -267,10 +275,16 @@ pub fn recursive_diff(dir1: impl AsRef<Path>, dir2: impl AsRef<Path>) {
             assert!(
                 file1 == file2,
                 "`{}` and `{}` have different content",
-                path.display(),
+                entry_path.display(),
                 path2.display(),
             );
         }
+    });
+}
+
+pub fn read_dir<F: Fn(&Path)>(dir: impl AsRef<Path>, callback: F) {
+    for entry in fs::read_dir(dir).unwrap() {
+        callback(&entry.unwrap().path());
     }
 }
 
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index b36cde72ff4..96a27610500 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 201f717ece4..00000000000
--- 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 00000000000..5c4b6d78649
--- /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 <https://github.com/rust-lang/rust/issues/10434>.
+
+//@ 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");
+}