mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
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
This commit is contained in:
commit
032af18af5
@ -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.;
|
||||
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();
|
||||
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.)
|
||||
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.)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
///
|
||||
|
@ -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.
|
||||
///
|
||||
|
@ -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> {}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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
|
||||
);
|
||||
|
@ -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` |
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
41
tests/run-make/c-link-to-rust-dylib/rmake.rs
Normal file
41
tests/run-make/c-link-to-rust-dylib/rmake.rs
Normal file
@ -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");
|
||||
}
|
Loading…
Reference in New Issue
Block a user