summaryrefslogtreecommitdiff
path: root/library/core
diff options
context:
space:
mode:
Diffstat (limited to 'library/core')
-rw-r--r--library/core/benches/fmt.rs24
-rw-r--r--library/core/benches/num/dec2flt/mod.rs24
-rw-r--r--library/core/benches/num/flt2dec/mod.rs6
-rw-r--r--library/core/benches/num/mod.rs6
-rw-r--r--library/core/src/any.rs2
-rw-r--r--library/core/src/cell.rs23
-rw-r--r--library/core/src/cmp.rs3
-rw-r--r--library/core/src/convert/mod.rs1
-rw-r--r--library/core/src/ffi/c_str.rs5
-rw-r--r--library/core/src/ffi/mod.rs14
-rw-r--r--library/core/src/fmt/mod.rs2
-rw-r--r--library/core/src/fmt/rt.rs15
-rw-r--r--library/core/src/intrinsics.rs5
-rw-r--r--library/core/src/intrinsics/mir.rs4
-rw-r--r--library/core/src/lib.rs2
-rw-r--r--library/core/src/marker.rs25
-rw-r--r--library/core/src/mem/mod.rs7
-rw-r--r--library/core/src/num/error.rs1
-rw-r--r--library/core/src/num/f32.rs36
-rw-r--r--library/core/src/num/f64.rs36
-rw-r--r--library/core/src/num/int_macros.rs38
-rw-r--r--library/core/src/num/mod.rs59
-rw-r--r--library/core/src/num/nonzero.rs67
-rw-r--r--library/core/src/ops/drop.rs68
-rw-r--r--library/core/src/panic.rs16
-rw-r--r--library/core/src/panic/panic_info.rs2
-rw-r--r--library/core/src/ptr/const_ptr.rs4
-rw-r--r--library/core/src/ptr/mod.rs6
-rw-r--r--library/core/src/ptr/mut_ptr.rs4
-rw-r--r--library/core/src/ptr/non_null.rs13
-rw-r--r--library/core/src/slice/iter.rs20
-rw-r--r--library/core/src/slice/iter/macros.rs73
-rw-r--r--library/core/src/slice/mod.rs46
-rw-r--r--library/core/src/str/pattern.rs8
-rw-r--r--library/core/src/task/poll.rs2
-rw-r--r--library/core/src/task/ready.rs4
-rw-r--r--library/core/src/task/wake.rs2
-rw-r--r--library/core/tests/lib.rs2
-rw-r--r--library/core/tests/num/int_macros.rs26
-rw-r--r--library/core/tests/num/mod.rs56
-rw-r--r--library/core/tests/num/uint_macros.rs26
41 files changed, 594 insertions, 189 deletions
diff --git a/library/core/benches/fmt.rs b/library/core/benches/fmt.rs
index ff726ff7559..d1cdb12e50f 100644
--- a/library/core/benches/fmt.rs
+++ b/library/core/benches/fmt.rs
@@ -1,13 +1,13 @@
use std::fmt::{self, Write as FmtWrite};
use std::io::{self, Write as IoWrite};
-use test::Bencher;
+use test::{black_box, Bencher};
#[bench]
fn write_vec_value(bh: &mut Bencher) {
bh.iter(|| {
let mut mem = Vec::new();
for _ in 0..1000 {
- mem.write_all("abc".as_bytes()).unwrap();
+ mem.write_all(black_box("abc").as_bytes()).unwrap();
}
});
}
@@ -18,7 +18,7 @@ fn write_vec_ref(bh: &mut Bencher) {
let mut mem = Vec::new();
let wr = &mut mem as &mut dyn io::Write;
for _ in 0..1000 {
- wr.write_all("abc".as_bytes()).unwrap();
+ wr.write_all(black_box("abc").as_bytes()).unwrap();
}
});
}
@@ -29,7 +29,7 @@ fn write_vec_macro1(bh: &mut Bencher) {
let mut mem = Vec::new();
let wr = &mut mem as &mut dyn io::Write;
for _ in 0..1000 {
- write!(wr, "abc").unwrap();
+ write!(wr, "{}", black_box("abc")).unwrap();
}
});
}
@@ -40,7 +40,7 @@ fn write_vec_macro2(bh: &mut Bencher) {
let mut mem = Vec::new();
let wr = &mut mem as &mut dyn io::Write;
for _ in 0..1000 {
- write!(wr, "{}", "abc").unwrap();
+ write!(wr, "{}", black_box("abc")).unwrap();
}
});
}
@@ -51,7 +51,7 @@ fn write_vec_macro_debug(bh: &mut Bencher) {
let mut mem = Vec::new();
let wr = &mut mem as &mut dyn io::Write;
for _ in 0..1000 {
- write!(wr, "{:?}", "☃").unwrap();
+ write!(wr, "{:?}", black_box("☃")).unwrap();
}
});
}
@@ -61,7 +61,7 @@ fn write_str_value(bh: &mut Bencher) {
bh.iter(|| {
let mut mem = String::new();
for _ in 0..1000 {
- mem.write_str("abc").unwrap();
+ mem.write_str(black_box("abc")).unwrap();
}
});
}
@@ -72,7 +72,7 @@ fn write_str_ref(bh: &mut Bencher) {
let mut mem = String::new();
let wr = &mut mem as &mut dyn fmt::Write;
for _ in 0..1000 {
- wr.write_str("abc").unwrap();
+ wr.write_str(black_box("abc")).unwrap();
}
});
}
@@ -82,7 +82,7 @@ fn write_str_macro1(bh: &mut Bencher) {
bh.iter(|| {
let mut mem = String::new();
for _ in 0..1000 {
- write!(mem, "abc").unwrap();
+ write!(mem, "{}", black_box("abc")).unwrap();
}
});
}
@@ -93,7 +93,7 @@ fn write_str_macro2(bh: &mut Bencher) {
let mut mem = String::new();
let wr = &mut mem as &mut dyn fmt::Write;
for _ in 0..1000 {
- write!(wr, "{}", "abc").unwrap();
+ write!(wr, "{}", black_box("abc")).unwrap();
}
});
}
@@ -104,7 +104,7 @@ fn write_str_macro_debug(bh: &mut Bencher) {
let mut mem = String::new();
let wr = &mut mem as &mut dyn fmt::Write;
for _ in 0..1000 {
- write!(wr, "{:?}", "☃").unwrap();
+ write!(wr, "{:?}", black_box("☃")).unwrap();
}
});
}
@@ -115,7 +115,7 @@ fn write_str_macro_debug_ascii(bh: &mut Bencher) {
let mut mem = String::new();
let wr = &mut mem as &mut dyn fmt::Write;
for _ in 0..1000 {
- write!(wr, "{:?}", "Hello, World!").unwrap();
+ write!(wr, "{:?}", black_box("Hello, World!")).unwrap();
}
});
}
diff --git a/library/core/benches/num/dec2flt/mod.rs b/library/core/benches/num/dec2flt/mod.rs
index 305baa68729..fb4a786b27e 100644
--- a/library/core/benches/num/dec2flt/mod.rs
+++ b/library/core/benches/num/dec2flt/mod.rs
@@ -1,57 +1,57 @@
-use test::Bencher;
+use test::{black_box, Bencher};
#[bench]
fn bench_0(b: &mut Bencher) {
- b.iter(|| "0.0".parse::<f64>());
+ b.iter(|| black_box("0.0").parse::<f64>());
}
#[bench]
fn bench_42(b: &mut Bencher) {
- b.iter(|| "42".parse::<f64>());
+ b.iter(|| black_box("42").parse::<f64>());
}
#[bench]
fn bench_huge_int(b: &mut Bencher) {
// 2^128 - 1
- b.iter(|| "170141183460469231731687303715884105727".parse::<f64>());
+ b.iter(|| black_box("170141183460469231731687303715884105727").parse::<f64>());
}
#[bench]
fn bench_short_decimal(b: &mut Bencher) {
- b.iter(|| "1234.5678".parse::<f64>());
+ b.iter(|| black_box("1234.5678").parse::<f64>());
}
#[bench]
fn bench_pi_long(b: &mut Bencher) {
- b.iter(|| "3.14159265358979323846264338327950288".parse::<f64>());
+ b.iter(|| black_box("3.14159265358979323846264338327950288").parse::<f64>());
}
#[bench]
fn bench_pi_short(b: &mut Bencher) {
- b.iter(|| "3.141592653589793".parse::<f64>())
+ b.iter(|| black_box("3.141592653589793").parse::<f64>())
}
#[bench]
fn bench_1e150(b: &mut Bencher) {
- b.iter(|| "1e150".parse::<f64>());
+ b.iter(|| black_box("1e150").parse::<f64>());
}
#[bench]
fn bench_long_decimal_and_exp(b: &mut Bencher) {
- b.iter(|| "727501488517303786137132964064381141071e-123".parse::<f64>());
+ b.iter(|| black_box("727501488517303786137132964064381141071e-123").parse::<f64>());
}
#[bench]
fn bench_min_subnormal(b: &mut Bencher) {
- b.iter(|| "5e-324".parse::<f64>());
+ b.iter(|| black_box("5e-324").parse::<f64>());
}
#[bench]
fn bench_min_normal(b: &mut Bencher) {
- b.iter(|| "2.2250738585072014e-308".parse::<f64>());
+ b.iter(|| black_box("2.2250738585072014e-308").parse::<f64>());
}
#[bench]
fn bench_max(b: &mut Bencher) {
- b.iter(|| "1.7976931348623157e308".parse::<f64>());
+ b.iter(|| black_box("1.7976931348623157e308").parse::<f64>());
}
diff --git a/library/core/benches/num/flt2dec/mod.rs b/library/core/benches/num/flt2dec/mod.rs
index 32fd5e626bc..1a330ef5fe5 100644
--- a/library/core/benches/num/flt2dec/mod.rs
+++ b/library/core/benches/num/flt2dec/mod.rs
@@ -7,7 +7,7 @@ use core::num::flt2dec::MAX_SIG_DIGITS;
use core::num::flt2dec::{decode, DecodableFloat, Decoded, FullDecoded};
use std::io::Write;
use std::vec::Vec;
-use test::Bencher;
+use test::{black_box, Bencher};
pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
match decode(v).1 {
@@ -22,7 +22,7 @@ fn bench_small_shortest(b: &mut Bencher) {
b.iter(|| {
buf.clear();
- write!(&mut buf, "{}", 3.1415926f64).unwrap()
+ write!(black_box(&mut buf), "{}", black_box(3.1415926f64)).unwrap()
});
}
@@ -32,6 +32,6 @@ fn bench_big_shortest(b: &mut Bencher) {
b.iter(|| {
buf.clear();
- write!(&mut buf, "{}", f64::MAX).unwrap()
+ write!(black_box(&mut buf), "{}", black_box(f64::MAX)).unwrap()
});
}
diff --git a/library/core/benches/num/mod.rs b/library/core/benches/num/mod.rs
index 2f9cad2725d..b97014d9bf9 100644
--- a/library/core/benches/num/mod.rs
+++ b/library/core/benches/num/mod.rs
@@ -3,7 +3,7 @@ mod flt2dec;
mod int_log;
use std::str::FromStr;
-use test::Bencher;
+use test::{black_box, Bencher};
const ASCII_NUMBERS: [&str; 19] = [
"0",
@@ -36,7 +36,7 @@ macro_rules! from_str_bench {
.iter()
.cycle()
.take(5_000)
- .filter_map(|s| <$t>::from_str(s).ok())
+ .filter_map(|s| <$t>::from_str(black_box(s)).ok())
.max()
})
}
@@ -52,7 +52,7 @@ macro_rules! from_str_radix_bench {
.iter()
.cycle()
.take(5_000)
- .filter_map(|s| <$t>::from_str_radix(s, $radix).ok())
+ .filter_map(|s| <$t>::from_str_radix(black_box(s), $radix).ok())
.max()
})
}
diff --git a/library/core/src/any.rs b/library/core/src/any.rs
index bb93ea509d8..d1c1ae6526b 100644
--- a/library/core/src/any.rs
+++ b/library/core/src/any.rs
@@ -866,7 +866,7 @@ where
///
/// A data provider provides values by calling this type's provide methods.
#[unstable(feature = "provide_any", issue = "96024")]
-#[repr(transparent)]
+#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435
pub struct Demand<'a>(dyn Erased<'a> + 'a);
impl<'a> Demand<'a> {
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index a96dfafd9c4..744767aae44 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -2030,6 +2030,27 @@ impl<T> UnsafeCell<T> {
}
impl<T: ?Sized> UnsafeCell<T> {
+ /// Converts from `&mut T` to `&mut UnsafeCell<T>`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # #![feature(unsafe_cell_from_mut)]
+ /// use std::cell::UnsafeCell;
+ ///
+ /// let mut val = 42;
+ /// let uc = UnsafeCell::from_mut(&mut val);
+ ///
+ /// *uc.get_mut() -= 1;
+ /// assert_eq!(*uc.get_mut(), 41);
+ /// ```
+ #[inline(always)]
+ #[unstable(feature = "unsafe_cell_from_mut", issue = "111645")]
+ pub const fn from_mut(value: &mut T) -> &mut UnsafeCell<T> {
+ // SAFETY: `UnsafeCell<T>` has the same memory layout as `T` due to #[repr(transparent)].
+ unsafe { &mut *(value as *mut T as *mut UnsafeCell<T>) }
+ }
+
/// Gets a mutable pointer to the wrapped value.
///
/// This can be cast to a pointer of any kind.
@@ -2100,6 +2121,8 @@ impl<T: ?Sized> UnsafeCell<T> {
///
/// let m = MaybeUninit::<UnsafeCell<i32>>::uninit();
/// unsafe { UnsafeCell::raw_get(m.as_ptr()).write(5); }
+ /// // avoid below which references to uninitialized data
+ /// // unsafe { UnsafeCell::get(&*m.as_ptr()).write(5); }
/// let uc = unsafe { m.assume_init() };
///
/// assert_eq!(uc.into_inner(), 5);
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index 48b127716f5..faf48ae570f 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -1412,6 +1412,7 @@ mod impls {
#[unstable(feature = "never_type", issue = "35121")]
impl PartialEq for ! {
+ #[inline]
fn eq(&self, _: &!) -> bool {
*self
}
@@ -1422,6 +1423,7 @@ mod impls {
#[unstable(feature = "never_type", issue = "35121")]
impl PartialOrd for ! {
+ #[inline]
fn partial_cmp(&self, _: &!) -> Option<Ordering> {
*self
}
@@ -1429,6 +1431,7 @@ mod impls {
#[unstable(feature = "never_type", issue = "35121")]
impl Ord for ! {
+ #[inline]
fn cmp(&self, _: &!) -> Ordering {
*self
}
diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs
index 3ae787cac71..38a6d1ccdb5 100644
--- a/library/core/src/convert/mod.rs
+++ b/library/core/src/convert/mod.rs
@@ -915,6 +915,7 @@ impl Ord for Infallible {
#[stable(feature = "convert_infallible", since = "1.34.0")]
impl From<!> for Infallible {
+ #[inline]
fn from(x: !) -> Self {
x
}
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 07b11814f96..201bacb28c7 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -517,8 +517,6 @@ impl CStr {
/// # Examples
///
/// ```
- /// #![feature(cstr_is_empty)]
- ///
/// use std::ffi::CStr;
/// # use std::ffi::FromBytesWithNulError;
///
@@ -533,7 +531,8 @@ impl CStr {
/// # }
/// ```
#[inline]
- #[unstable(feature = "cstr_is_empty", issue = "102444")]
+ #[stable(feature = "cstr_is_empty", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "cstr_is_empty", since = "CURRENT_RUSTC_VERSION")]
pub const fn is_empty(&self) -> bool {
// SAFETY: We know there is at least one byte; for empty strings it
// is the NUL terminator.
diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs
index b85894259f1..b73abbbaca7 100644
--- a/library/core/src/ffi/mod.rs
+++ b/library/core/src/ffi/mod.rs
@@ -203,7 +203,7 @@ mod c_long_definition {
// be UB.
#[doc = include_str!("c_void.md")]
#[cfg_attr(not(bootstrap), lang = "c_void")]
-#[repr(u8)]
+#[cfg_attr(not(doc), repr(u8))] // work around https://github.com/rust-lang/rust/issues/90435
#[stable(feature = "core_c_void", since = "1.30.0")]
pub enum c_void {
#[unstable(
@@ -244,7 +244,7 @@ impl fmt::Debug for c_void {
target_os = "uefi",
windows,
))]
-#[repr(transparent)]
+#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435
#[unstable(
feature = "c_variadic",
reason = "the `c_variadic` feature has not been properly tested on \
@@ -296,7 +296,7 @@ impl<'f> fmt::Debug for VaListImpl<'f> {
not(target_os = "uefi"),
not(windows),
))]
-#[repr(C)]
+#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401
#[derive(Debug)]
#[unstable(
feature = "c_variadic",
@@ -316,7 +316,7 @@ pub struct VaListImpl<'f> {
/// PowerPC ABI implementation of a `va_list`.
#[cfg(all(target_arch = "powerpc", not(target_os = "uefi"), not(windows)))]
-#[repr(C)]
+#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401
#[derive(Debug)]
#[unstable(
feature = "c_variadic",
@@ -336,7 +336,7 @@ pub struct VaListImpl<'f> {
/// s390x ABI implementation of a `va_list`.
#[cfg(target_arch = "s390x")]
-#[repr(C)]
+#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401
#[derive(Debug)]
#[unstable(
feature = "c_variadic",
@@ -355,7 +355,7 @@ pub struct VaListImpl<'f> {
/// x86_64 ABI implementation of a `va_list`.
#[cfg(all(target_arch = "x86_64", not(target_os = "uefi"), not(windows)))]
-#[repr(C)]
+#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401
#[derive(Debug)]
#[unstable(
feature = "c_variadic",
@@ -373,7 +373,7 @@ pub struct VaListImpl<'f> {
}
/// A wrapper for a `va_list`
-#[repr(transparent)]
+#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435
#[derive(Debug)]
#[unstable(
feature = "c_variadic",
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index aa829edd5b0..bac2f31878b 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -2267,6 +2267,7 @@ fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperEx
#[unstable(feature = "never_type", issue = "35121")]
impl Debug for ! {
+ #[inline]
fn fmt(&self, _: &mut Formatter<'_>) -> Result {
*self
}
@@ -2274,6 +2275,7 @@ impl Debug for ! {
#[unstable(feature = "never_type", issue = "35121")]
impl Display for ! {
+ #[inline]
fn fmt(&self, _: &mut Formatter<'_>) -> Result {
*self
}
diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs
index 0596f6c30ce..d37888c27bd 100644
--- a/library/core/src/fmt/rt.rs
+++ b/library/core/src/fmt/rt.rs
@@ -152,6 +152,21 @@ impl<'a> Argument<'a> {
None
}
}
+
+ /// Used by `format_args` when all arguments are gone after inlining,
+ /// when using `&[]` would incorrectly allow for a bigger lifetime.
+ ///
+ /// This fails without format argument inlining, and that shouldn't be different
+ /// when the argument is inlined:
+ ///
+ /// ```compile_fail,E0716
+ /// let f = format_args!("{}", "a");
+ /// println!("{f}");
+ /// ```
+ #[inline(always)]
+ pub fn none() -> [Self; 0] {
+ []
+ }
}
/// This struct represents the unsafety of constructing an `Arguments`.
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 077c0fdc380..23ded42fa66 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -1187,7 +1187,7 @@ extern "rust-intrinsic" {
/// Below are common applications of `transmute` which can be replaced with safer
/// constructs.
///
- /// Turning raw bytes (`&[u8]`) into `u32`, `f64`, etc.:
+ /// Turning raw bytes (`[u8; SZ]`) into `u32`, `f64`, etc.:
///
/// ```
/// let raw_bytes = [0x78, 0x56, 0x34, 0x12];
@@ -2260,7 +2260,7 @@ extern "rust-intrinsic" {
/// This intrinsic can *only* be called where the pointer is a local without
/// projections (`read_via_copy(ptr)`, not `read_via_copy(*ptr)`) so that it
/// trivially obeys runtime-MIR rules about derefs in operands.
- #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
+ #[rustc_const_stable(feature = "const_ptr_read", since = "CURRENT_RUSTC_VERSION")]
#[rustc_nounwind]
pub fn read_via_copy<T>(ptr: *const T) -> T;
@@ -2523,6 +2523,7 @@ macro_rules! assert_unsafe_precondition {
}
}
#[allow(non_snake_case)]
+ #[inline]
const fn comptime$(<$($tt)*>)?($(_:$ty),*) {}
::core::intrinsics::const_eval_select(($($i,)*), comptime, runtime);
diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs
index b4639c07c35..5944a0de1a4 100644
--- a/library/core/src/intrinsics/mir.rs
+++ b/library/core/src/intrinsics/mir.rs
@@ -228,7 +228,7 @@
//!
//! - Operands implicitly convert to `Use` rvalues.
//! - `&`, `&mut`, `addr_of!`, and `addr_of_mut!` all work to create their associated rvalue.
-//! - [`Discriminant`] and [`Len`] have associated functions.
+//! - [`Discriminant`], [`Len`], and [`CopyForDeref`] have associated functions.
//! - Unary and binary operations use their normal Rust syntax - `a * b`, `!c`, etc.
//! - The binary operation `Offset` can be created via [`Offset`].
//! - Checked binary operations are represented by wrapping the associated binop in [`Checked`].
@@ -263,6 +263,7 @@ pub struct BasicBlock;
macro_rules! define {
($name:literal, $( #[ $meta:meta ] )* fn $($sig:tt)*) => {
#[rustc_diagnostic_item = $name]
+ #[inline]
$( #[ $meta ] )*
pub fn $($sig)* { panic!() }
}
@@ -278,6 +279,7 @@ define!("mir_storage_dead", fn StorageDead<T>(local: T));
define!("mir_deinit", fn Deinit<T>(place: T));
define!("mir_checked", fn Checked<T>(binop: T) -> (T, bool));
define!("mir_len", fn Len<T>(place: T) -> usize);
+define!("mir_copy_for_deref", fn CopyForDeref<T>(place: T) -> T);
define!("mir_retag", fn Retag<T>(place: T));
define!("mir_move", fn Move<T>(place: T) -> T);
define!("mir_static", fn Static<T>(s: T) -> &'static T);
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 3abf66dbe29..0af04fac909 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -133,6 +133,7 @@
#![feature(const_maybe_uninit_assume_init)]
#![feature(const_maybe_uninit_uninit_array)]
#![feature(const_nonnull_new)]
+#![feature(const_num_midpoint)]
#![feature(const_option)]
#![feature(const_option_ext)]
#![feature(const_pin)]
@@ -140,7 +141,6 @@
#![feature(const_pointer_is_aligned)]
#![feature(const_ptr_as_ref)]
#![feature(const_ptr_is_null)]
-#![feature(const_ptr_read)]
#![feature(const_ptr_sub_ptr)]
#![feature(const_ptr_write)]
#![feature(const_raw_ptr_comparison)]
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 97f9d01e016..ca45683d3d6 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -695,7 +695,7 @@ impl<T: ?Sized> !Sync for *mut T {}
/// }
/// ```
///
-/// This also in turn requires the annotation `T: 'a`, indicating
+/// This also in turn infers the lifetime bound `T: 'a`, indicating
/// that any references in `T` are valid over the lifetime `'a`.
///
/// When initializing a `Slice` you simply provide the value
@@ -766,16 +766,11 @@ impl<T: ?Sized> !Sync for *mut T {}
///
/// ## Ownership and the drop check
///
-/// Adding a field of type `PhantomData<T>` indicates that your
-/// type owns data of type `T`. This in turn implies that when your
-/// type is dropped, it may drop one or more instances of the type
-/// `T`. This has bearing on the Rust compiler's [drop check]
-/// analysis.
+/// The exact interaction of `PhantomData` with drop check **may change in the future**.
///
-/// If your struct does not in fact *own* the data of type `T`, it is
-/// better to use a reference type, like `PhantomData<&'a T>`
-/// (ideally) or `PhantomData<*const T>` (if no lifetime applies), so
-/// as not to indicate ownership.
+/// Currently, adding a field of type `PhantomData<T>` indicates that your type *owns* data of type
+/// `T` in very rare circumstances. This in turn has effects on the Rust compiler's [drop check]
+/// analysis. For the exact rules, see the [drop check] documentation.
///
/// ## Layout
///
@@ -783,7 +778,7 @@ impl<T: ?Sized> !Sync for *mut T {}
/// * `size_of::<PhantomData<T>>() == 0`
/// * `align_of::<PhantomData<T>>() == 1`
///
-/// [drop check]: ../../nomicon/dropck.html
+/// [drop check]: Drop#drop-check
#[lang = "phantom_data"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct PhantomData<T: ?Sized>;
@@ -991,6 +986,14 @@ pub trait PointerLike {}
#[rustc_on_unimplemented(message = "`{Self}` can't be used as a const parameter type")]
pub trait ConstParamTy: StructuralEq {}
+/// Derive macro generating an impl of the trait `Copy`.
+#[rustc_builtin_macro]
+#[unstable(feature = "adt_const_params", issue = "95174")]
+#[cfg(not(bootstrap))]
+pub macro ConstParamTy($item:item) {
+ /* compiler built-in */
+}
+
// FIXME(generic_const_parameter_types): handle `ty::FnDef`/`ty::Closure`
// FIXME(generic_const_parameter_types): handle `ty::Tuple`
marker_impls! {
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index 7d2f2971523..289305253ec 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -968,6 +968,7 @@ pub const fn replace<T>(dest: &mut T, src: T) -> T {
/// Integers and other types implementing [`Copy`] are unaffected by `drop`.
///
/// ```
+/// # #![cfg_attr(not(bootstrap), allow(drop_copy))]
/// #[derive(Copy, Clone)]
/// struct Foo(u8);
///
@@ -1315,9 +1316,9 @@ impl<T> SizedTypeProperties for T {}
///
/// assert_eq!(mem::offset_of!(NestedA, b.0), 0);
/// ```
-#[unstable(feature = "offset_of", issue = "106655")]
-#[rustc_builtin_macro]
#[cfg(not(bootstrap))]
+#[unstable(feature = "offset_of", issue = "106655")]
+#[allow_internal_unstable(builtin_syntax)]
pub macro offset_of($Container:ty, $($fields:tt).+ $(,)?) {
- /* compiler built-in */
+ builtin # offset_of($Container, $($fields).+)
}
diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs
index 2ad0f1dc506..14e99578a7c 100644
--- a/library/core/src/num/error.rs
+++ b/library/core/src/num/error.rs
@@ -34,6 +34,7 @@ impl From<Infallible> for TryFromIntError {
#[unstable(feature = "never_type", issue = "35121")]
impl From<!> for TryFromIntError {
+ #[inline]
fn from(never: !) -> TryFromIntError {
// Match rather than coerce to make sure that code like
// `From<Infallible> for TryFromIntError` above will keep working
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index 1c6819b547d..4a035ad61e1 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -940,6 +940,42 @@ impl f32 {
}
}
+ /// Calculates the middle point of `self` and `rhs`.
+ ///
+ /// This returns NaN when *either* argument is NaN or if a combination of
+ /// +inf and -inf is provided as arguments.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(num_midpoint)]
+ /// assert_eq!(1f32.midpoint(4.0), 2.5);
+ /// assert_eq!((-5.5f32).midpoint(8.0), 1.25);
+ /// ```
+ #[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.)
+ }
+ }
+
/// Rounds toward zero and converts to any primitive integer type,
/// assuming that the value is finite and fits in that type.
///
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index 1e7387217cb..3aafc435f1e 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -951,6 +951,42 @@ impl f64 {
}
}
+ /// Calculates the middle point of `self` and `rhs`.
+ ///
+ /// This returns NaN when *either* argument is NaN or if a combination of
+ /// +inf and -inf is provided as arguments.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(num_midpoint)]
+ /// assert_eq!(1f64.midpoint(4.0), 2.5);
+ /// assert_eq!((-5.5f64).midpoint(8.0), 1.25);
+ /// ```
+ #[unstable(feature = "num_midpoint", issue = "110840")]
+ pub fn midpoint(self, other: f64) -> f64 {
+ const LO: f64 = f64::MIN_POSITIVE * 2.;
+ const HI: f64 = f64::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.)
+ }
+ }
+
/// Rounds toward zero and converts to any primitive integer type,
/// assuming that the value is finite and fits in that type.
///
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 17715c9291f..1199d09b563 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -2332,6 +2332,44 @@ macro_rules! int_impl {
}
}
+ /// Calculates the middle point of `self` and `rhs`.
+ ///
+ /// `midpoint(a, b)` is `(a + b) >> 1` as if it were performed in a
+ /// sufficiently-large signed integral type. This implies that the result is
+ /// always rounded towards negative infinity and that no overflow will ever occur.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(num_midpoint)]
+ #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")]
+ #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(-1), -1);")]
+ #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").midpoint(0), -1);")]
+ /// ```
+ #[unstable(feature = "num_midpoint", issue = "110840")]
+ #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")]
+ #[rustc_allow_const_fn_unstable(const_num_midpoint)]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn midpoint(self, rhs: Self) -> Self {
+ const U: $UnsignedT = <$SelfT>::MIN.unsigned_abs();
+
+ // Map an $SelfT to an $UnsignedT
+ // ex: i8 [-128; 127] to [0; 255]
+ const fn map(a: $SelfT) -> $UnsignedT {
+ (a as $UnsignedT) ^ U
+ }
+
+ // Map an $UnsignedT to an $SelfT
+ // ex: u8 [0; 255] to [-128; 127]
+ const fn demap(a: $UnsignedT) -> $SelfT {
+ (a ^ U) as $SelfT
+ }
+
+ demap(<$UnsignedT>::midpoint(map(self), map(rhs)))
+ }
+
/// Returns the logarithm of the number with respect to an arbitrary base,
/// rounded down.
///
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 08444421dca..c9baa09f407 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -95,6 +95,57 @@ depending on the target pointer size.
};
}
+macro_rules! midpoint_impl {
+ ($SelfT:ty, unsigned) => {
+ /// Calculates the middle point of `self` and `rhs`.
+ ///
+ /// `midpoint(a, b)` is `(a + b) >> 1` as if it were performed in a
+ /// sufficiently-large signed integral type. This implies that the result is
+ /// always rounded towards negative infinity and that no overflow will ever occur.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(num_midpoint)]
+ #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")]
+ #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".midpoint(4), 2);")]
+ /// ```
+ #[unstable(feature = "num_midpoint", issue = "110840")]
+ #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn midpoint(self, rhs: $SelfT) -> $SelfT {
+ // Use the well known branchless algorthim from Hacker's Delight to compute
+ // `(a + b) / 2` without overflowing: `((a ^ b) >> 1) + (a & b)`.
+ ((self ^ rhs) >> 1) + (self & rhs)
+ }
+ };
+ ($SelfT:ty, $WideT:ty, unsigned) => {
+ /// Calculates the middle point of `self` and `rhs`.
+ ///
+ /// `midpoint(a, b)` is `(a + b) >> 1` as if it were performed in a
+ /// sufficiently-large signed integral type. This implies that the result is
+ /// always rounded towards negative infinity and that no overflow will ever occur.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(num_midpoint)]
+ #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")]
+ #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".midpoint(4), 2);")]
+ /// ```
+ #[unstable(feature = "num_midpoint", issue = "110840")]
+ #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn midpoint(self, rhs: $SelfT) -> $SelfT {
+ ((self as $WideT + rhs as $WideT) / 2) as $SelfT
+ }
+ };
+}
+
macro_rules! widening_impl {
($SelfT:ty, $WideT:ty, $BITS:literal, unsigned) => {
/// Calculates the complete product `self * rhs` without the possibility to overflow.
@@ -455,6 +506,7 @@ impl u8 {
bound_condition = "",
}
widening_impl! { u8, u16, 8, unsigned }
+ midpoint_impl! { u8, u16, unsigned }
/// Checks if the value is within the ASCII range.
///
@@ -1066,6 +1118,7 @@ impl u16 {
bound_condition = "",
}
widening_impl! { u16, u32, 16, unsigned }
+ midpoint_impl! { u16, u32, unsigned }
/// Checks if the value is a Unicode surrogate code point, which are disallowed values for [`char`].
///
@@ -1114,6 +1167,7 @@ impl u32 {
bound_condition = "",
}
widening_impl! { u32, u64, 32, unsigned }
+ midpoint_impl! { u32, u64, unsigned }
}
impl u64 {
@@ -1137,6 +1191,7 @@ impl u64 {
bound_condition = "",
}
widening_impl! { u64, u128, 64, unsigned }
+ midpoint_impl! { u64, u128, unsigned }
}
impl u128 {
@@ -1161,6 +1216,7 @@ impl u128 {
from_xe_bytes_doc = "",
bound_condition = "",
}
+ midpoint_impl! { u128, unsigned }
}
#[cfg(target_pointer_width = "16")]
@@ -1185,6 +1241,7 @@ impl usize {
bound_condition = " on 16-bit targets",
}
widening_impl! { usize, u32, 16, unsigned }
+ midpoint_impl! { usize, u32, unsigned }
}
#[cfg(target_pointer_width = "32")]
@@ -1209,6 +1266,7 @@ impl usize {
bound_condition = " on 32-bit targets",
}
widening_impl! { usize, u64, 32, unsigned }
+ midpoint_impl! { usize, u64, unsigned }
}
#[cfg(target_pointer_width = "64")]
@@ -1233,6 +1291,7 @@ impl usize {
bound_condition = " on 64-bit targets",
}
widening_impl! { usize, u128, 64, unsigned }
+ midpoint_impl! { usize, u128, unsigned }
}
impl usize {
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 74a325b89d4..38a1c42d9e8 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -493,6 +493,43 @@ macro_rules! nonzero_unsigned_operations {
pub const fn ilog10(self) -> u32 {
super::int_log10::$Int(self.0)
}
+
+ /// Calculates the middle point of `self` and `rhs`.
+ ///
+ /// `midpoint(a, b)` is `(a + b) >> 1` as if it were performed in a
+ /// sufficiently-large signed integral type. This implies that the result is
+ /// always rounded towards negative infinity and that no overflow will ever occur.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(num_midpoint)]
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ ///
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")]
+ #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
+ #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")]
+ ///
+ /// assert_eq!(one.midpoint(four), two);
+ /// assert_eq!(four.midpoint(one), two);
+ /// # Some(())
+ /// # }
+ /// ```
+ #[unstable(feature = "num_midpoint", issue = "110840")]
+ #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")]
+ #[rustc_allow_const_fn_unstable(const_num_midpoint)]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn midpoint(self, rhs: Self) -> Self {
+ // SAFETY: The only way to get `0` with midpoint is to have two opposite or
+ // near opposite numbers: (-5, 5), (0, 1), (0, 0) which is impossible because
+ // of the unsignedness of this number and also because $Ty is guaranteed to
+ // never being 0.
+ unsafe { $Ty::new_unchecked(self.get().midpoint(rhs.get())) }
+ }
}
)+
}
@@ -719,8 +756,6 @@ macro_rules! nonzero_signed_operations {
/// # Example
///
/// ```
- /// #![feature(nonzero_negation_ops)]
- ///
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
@@ -734,7 +769,8 @@ macro_rules! nonzero_signed_operations {
/// ```
#[must_use]
#[inline]
- #[unstable(feature = "nonzero_negation_ops", issue = "102443")]
+ #[stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")]
pub const fn is_positive(self) -> bool {
self.get().is_positive()
}
@@ -745,8 +781,6 @@ macro_rules! nonzero_signed_operations {
/// # Example
///
/// ```
- /// #![feature(nonzero_negation_ops)]
- ///
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
@@ -760,7 +794,8 @@ macro_rules! nonzero_signed_operations {
/// ```
#[must_use]
#[inline]
- #[unstable(feature = "nonzero_negation_ops", issue = "102443")]
+ #[stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")]
pub const fn is_negative(self) -> bool {
self.get().is_negative()
}
@@ -770,8 +805,6 @@ macro_rules! nonzero_signed_operations {
/// # Example
///
/// ```
- /// #![feature(nonzero_negation_ops)]
- ///
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
@@ -786,7 +819,8 @@ macro_rules! nonzero_signed_operations {
/// # }
/// ```
#[inline]
- #[unstable(feature = "nonzero_negation_ops", issue = "102443")]
+ #[stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")]
pub const fn checked_neg(self) -> Option<$Ty> {
if let Some(result) = self.get().checked_neg() {
// SAFETY: negation of nonzero cannot yield zero values.
@@ -803,8 +837,6 @@ macro_rules! nonzero_signed_operations {
/// # Example
///
/// ```
- /// #![feature(nonzero_negation_ops)]
- ///
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
@@ -819,7 +851,8 @@ macro_rules! nonzero_signed_operations {
/// # }
/// ```
#[inline]
- #[unstable(feature = "nonzero_negation_ops", issue = "102443")]
+ #[stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")]
pub const fn overflowing_neg(self) -> ($Ty, bool) {
let (result, overflow) = self.get().overflowing_neg();
// SAFETY: negation of nonzero cannot yield zero values.
@@ -832,8 +865,6 @@ macro_rules! nonzero_signed_operations {
/// # Example
///
/// ```
- /// #![feature(nonzero_negation_ops)]
- ///
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
@@ -853,7 +884,8 @@ macro_rules! nonzero_signed_operations {
/// # }
/// ```
#[inline]
- #[unstable(feature = "nonzero_negation_ops", issue = "102443")]
+ #[stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")]
pub const fn saturating_neg(self) -> $Ty {
if let Some(result) = self.checked_neg() {
return result;
@@ -870,8 +902,6 @@ macro_rules! nonzero_signed_operations {
/// # Example
///
/// ```
- /// #![feature(nonzero_negation_ops)]
- ///
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
@@ -886,7 +916,8 @@ macro_rules! nonzero_signed_operations {
/// # }
/// ```
#[inline]
- #[unstable(feature = "nonzero_negation_ops", issue = "102443")]
+ #[stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")]
pub const fn wrapping_neg(self) -> $Ty {
let result = self.get().wrapping_neg();
// SAFETY: negation of nonzero cannot yield zero values.
diff --git a/library/core/src/ops/drop.rs b/library/core/src/ops/drop.rs
index a2c3d978cc4..9ebf426be95 100644
--- a/library/core/src/ops/drop.rs
+++ b/library/core/src/ops/drop.rs
@@ -132,6 +132,74 @@
/// are `Copy` get implicitly duplicated by the compiler, making it very
/// hard to predict when, and how often destructors will be executed. As such,
/// these types cannot have destructors.
+///
+/// ## Drop check
+///
+/// Dropping interacts with the borrow checker in subtle ways: when a type `T` is being implicitly
+/// dropped as some variable of this type goes out of scope, the borrow checker needs to ensure that
+/// calling `T`'s destructor at this moment is safe. In particular, it also needs to be safe to
+/// recursively drop all the fields of `T`. For example, it is crucial that code like the following
+/// is being rejected:
+///
+/// ```compile_fail,E0597
+/// use std::cell::Cell;
+///
+/// struct S<'a>(Cell<Option<&'a S<'a>>>, Box<i32>);
+/// impl Drop for S<'_> {
+/// fn drop(&mut self) {
+/// if let Some(r) = self.0.get() {
+/// // Print the contents of the `Box` in `r`.
+/// println!("{}", r.1);
+/// }
+/// }
+/// }
+///
+/// fn main() {
+/// // Set up two `S` that point to each other.
+/// let s1 = S(Cell::new(None), Box::new(42));
+/// let s2 = S(Cell::new(Some(&s1)), Box::new(42));
+/// s1.0.set(Some(&s2));
+/// // Now they both get dropped. But whichever is the 2nd one
+/// // to be dropped will access the `Box` in the first one,
+/// // which is a use-after-free!
+/// }
+/// ```
+///
+/// The Nomicon discusses the need for [drop check in more detail][drop check].
+///
+/// To reject such code, the "drop check" analysis determines which types and lifetimes need to
+/// still be live when `T` gets dropped. The exact details of this analysis are not yet
+/// stably guaranteed and **subject to change**. Currently, the analysis works as follows:
+/// - If `T` has no drop glue, then trivially nothing is required to be live. This is the case if
+/// neither `T` nor any of its (recursive) fields have a destructor (`impl Drop`). [`PhantomData`]
+/// and [`ManuallyDrop`] are considered to never have a destructor, no matter their field type.
+/// - If `T` has drop glue, then, for all types `U` that are *owned* by any field of `T`,
+/// recursively add the types and lifetimes that need to be live when `U` gets dropped. The set of
+/// owned types is determined by recursively traversing `T`:
+/// - Recursively descend through `PhantomData`, `Box`, tuples, and arrays (including arrays of
+/// length 0).
+/// - Stop at reference and raw pointer types as well as function pointers and function items;
+/// they do not own anything.
+/// - Stop at non-composite types (type parameters that remain generic in the current context and
+/// base types such as integers and `bool`); these types are owned.
+/// - When hitting an ADT with `impl Drop`, stop there; this type is owned.
+/// - When hitting an ADT without `impl Drop`, recursively descend to its fields. (For an `enum`,
+/// consider all fields of all variants.)
+/// - Furthermore, if `T` implements `Drop`, then all generic (lifetime and type) parameters of `T`
+/// must be live.
+///
+/// In the above example, the last clause implies that `'a` must be live when `S<'a>` is dropped,
+/// and hence the example is rejected. If we remove the `impl Drop`, the liveness requirement
+/// disappears and the example is accepted.
+///
+/// There exists an unstable way for a type to opt-out of the last clause; this is called "drop
+/// check eyepatch" or `may_dangle`. For more details on this nightly-only feature, see the
+/// [discussion in the Nomicon][nomicon].
+///
+/// [`ManuallyDrop`]: crate::mem::ManuallyDrop
+/// [`PhantomData`]: crate::marker::PhantomData
+/// [drop check]: ../../nomicon/dropck.html
+/// [nomicon]: ../../nomicon/phantom-data.html#an-exception-the-special-case-of-the-standard-library-and-its-unstable-may_dangle
#[lang = "drop"]
#[stable(feature = "rust1", since = "1.0.0")]
#[const_trait]
diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs
index 8338a5d7e5a..ebcce79b0f8 100644
--- a/library/core/src/panic.rs
+++ b/library/core/src/panic.rs
@@ -35,9 +35,11 @@ pub macro panic_2015 {
("{}", $arg:expr $(,)?) => (
$crate::panicking::panic_display(&$arg)
),
- ($fmt:expr, $($arg:tt)+) => (
- $crate::panicking::panic_fmt($crate::const_format_args!($fmt, $($arg)+))
- ),
+ ($fmt:expr, $($arg:tt)+) => ({
+ // Semicolon to prevent temporaries inside the formatting machinery from
+ // being considered alive in the caller after the panic_fmt call.
+ $crate::panicking::panic_fmt($crate::const_format_args!($fmt, $($arg)+));
+ }),
}
#[doc(hidden)]
@@ -53,9 +55,11 @@ pub macro panic_2021 {
("{}", $arg:expr $(,)?) => (
$crate::panicking::panic_display(&$arg)
),
- ($($t:tt)+) => (
- $crate::panicking::panic_fmt($crate::const_format_args!($($t)+))
- ),
+ ($($t:tt)+) => ({
+ // Semicolon to prevent temporaries inside the formatting machinery from
+ // being considered alive in the caller after the panic_fmt call.
+ $crate::panicking::panic_fmt($crate::const_format_args!($($t)+));
+ }),
}
#[doc(hidden)]
diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs
index 06fbe083ca1..5576adde84b 100644
--- a/library/core/src/panic/panic_info.rs
+++ b/library/core/src/panic/panic_info.rs
@@ -134,7 +134,7 @@ impl<'a> PanicInfo<'a> {
/// whose ABI does not support unwinding.
///
/// It is safe for a panic handler to unwind even when this function returns
- /// true, however this will simply cause the panic handler to be called
+ /// false, however this will simply cause the panic handler to be called
/// again.
#[must_use]
#[unstable(feature = "panic_can_unwind", issue = "92988")]
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 585b648873a..5ee1b5e4afc 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -1195,7 +1195,7 @@ impl<T: ?Sized> *const T {
///
/// [`ptr::read`]: crate::ptr::read()
#[stable(feature = "pointer_methods", since = "1.26.0")]
- #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
+ #[rustc_const_stable(feature = "const_ptr_read", since = "CURRENT_RUSTC_VERSION")]
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn read(self) -> T
@@ -1236,7 +1236,7 @@ impl<T: ?Sized> *const T {
///
/// [`ptr::read_unaligned`]: crate::ptr::read_unaligned()
#[stable(feature = "pointer_methods", since = "1.26.0")]
- #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
+ #[rustc_const_stable(feature = "const_ptr_read", since = "CURRENT_RUSTC_VERSION")]
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn read_unaligned(self) -> T
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 4737ff5d756..ecbf4e66fa4 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -1133,7 +1133,8 @@ pub const unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
/// [valid]: self#safety
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
+#[rustc_const_stable(feature = "const_ptr_read", since = "CURRENT_RUSTC_VERSION")]
+#[rustc_allow_const_fn_unstable(const_mut_refs, const_maybe_uninit_as_mut_ptr)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn read<T>(src: *const T) -> T {
// It would be semantically correct to implement this via `copy_nonoverlapping`
@@ -1249,7 +1250,8 @@ pub const unsafe fn read<T>(src: *const T) -> T {
/// ```
#[inline]
#[stable(feature = "ptr_unaligned", since = "1.17.0")]
-#[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
+#[rustc_const_stable(feature = "const_ptr_read", since = "CURRENT_RUSTC_VERSION")]
+#[rustc_allow_const_fn_unstable(const_mut_refs, const_maybe_uninit_as_mut_ptr)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn read_unaligned<T>(src: *const T) -> T {
let mut tmp = MaybeUninit::<T>::uninit();
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index c339ccb1b4d..5edd291fb76 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -1305,7 +1305,7 @@ impl<T: ?Sized> *mut T {
///
/// [`ptr::read`]: crate::ptr::read()
#[stable(feature = "pointer_methods", since = "1.26.0")]
- #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
+ #[rustc_const_stable(feature = "const_ptr_read", since = "CURRENT_RUSTC_VERSION")]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn read(self) -> T
@@ -1346,7 +1346,7 @@ impl<T: ?Sized> *mut T {
///
/// [`ptr::read_unaligned`]: crate::ptr::read_unaligned()
#[stable(feature = "pointer_methods", since = "1.26.0")]
- #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
+ #[rustc_const_stable(feature = "const_ptr_read", since = "CURRENT_RUSTC_VERSION")]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn read_unaligned(self) -> T
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 61fcdf58b4f..b492d2f07bc 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -449,6 +449,19 @@ impl<T: ?Sized> NonNull<T> {
// SAFETY: `self` is a `NonNull` pointer which is necessarily non-null
unsafe { NonNull::new_unchecked(self.as_ptr() as *mut U) }
}
+
+ /// See [`pointer::add`] for semantics and safety requirements.
+ #[inline]
+ pub(crate) const unsafe fn add(self, delta: usize) -> Self
+ where
+ T: Sized,
+ {
+ // SAFETY: We require that the delta stays in-bounds of the object, and
+ // thus it cannot become null, as that would require wrapping the
+ // address space, which no legal objects are allowed to do.
+ // And the caller promised the `delta` is sound to add.
+ unsafe { NonNull { pointer: self.pointer.add(delta) } }
+ }
}
impl<T> NonNull<[T]> {
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
index 8629aab0070..5369fe0a9a9 100644
--- a/library/core/src/slice/iter.rs
+++ b/library/core/src/slice/iter.rs
@@ -13,7 +13,7 @@ use crate::iter::{
use crate::marker::{PhantomData, Send, Sized, Sync};
use crate::mem::{self, SizedTypeProperties};
use crate::num::NonZeroUsize;
-use crate::ptr::NonNull;
+use crate::ptr::{invalid, invalid_mut, NonNull};
use super::{from_raw_parts, from_raw_parts_mut};
@@ -67,9 +67,7 @@ pub struct Iter<'a, T: 'a> {
ptr: NonNull<T>,
/// For non-ZSTs, the non-null pointer to the past-the-end element.
///
- /// For ZSTs, this is `ptr.wrapping_byte_add(len)`.
- ///
- /// For all types, `ptr == end` tests whether the iterator is empty.
+ /// For ZSTs, this is `ptr::invalid(len)`.
end: *const T,
_marker: PhantomData<&'a T>,
}
@@ -92,10 +90,7 @@ impl<'a, T> Iter<'a, T> {
let ptr = slice.as_ptr();
// SAFETY: Similar to `IterMut::new`.
unsafe {
- assume(!ptr.is_null());
-
- let end =
- if T::IS_ZST { ptr.wrapping_byte_add(slice.len()) } else { ptr.add(slice.len()) };
+ let end = if T::IS_ZST { invalid(slice.len()) } else { ptr.add(slice.len()) };
Self { ptr: NonNull::new_unchecked(ptr as *mut T), end, _marker: PhantomData }
}
@@ -193,9 +188,7 @@ pub struct IterMut<'a, T: 'a> {
ptr: NonNull<T>,
/// For non-ZSTs, the non-null pointer to the past-the-end element.
///
- /// For ZSTs, this is `ptr.wrapping_byte_add(len)`.
- ///
- /// For all types, `ptr == end` tests whether the iterator is empty.
+ /// For ZSTs, this is `ptr::invalid_mut(len)`.
end: *mut T,
_marker: PhantomData<&'a mut T>,
}
@@ -233,10 +226,7 @@ impl<'a, T> IterMut<'a, T> {
// See the `next_unchecked!` and `is_empty!` macros as well as the
// `post_inc_start` method for more information.
unsafe {
- assume(!ptr.is_null());
-
- let end =
- if T::IS_ZST { ptr.wrapping_byte_add(slice.len()) } else { ptr.add(slice.len()) };
+ let end = if T::IS_ZST { invalid_mut(slice.len()) } else { ptr.add(slice.len()) };
Self { ptr: NonNull::new_unchecked(ptr), end, _marker: PhantomData }
}
diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs
index 0a30033778b..3462c0e020a 100644
--- a/library/core/src/slice/iter/macros.rs
+++ b/library/core/src/slice/iter/macros.rs
@@ -1,11 +1,30 @@
//! Macros used by iterators of slice.
+// Shrinks the iterator when T is a ZST, setting the length to `new_len`.
+// `new_len` must not exceed `self.len()`.
+macro_rules! zst_set_len {
+ ($self: ident, $new_len: expr) => {{
+ #![allow(unused_unsafe)] // we're sometimes used within an unsafe block
+
+ // SAFETY: same as `invalid(_mut)`, but the macro doesn't know
+ // which versions of that function to call, so open-code it.
+ $self.end = unsafe { mem::transmute::<usize, _>($new_len) };
+ }};
+}
+
+// Shrinks the iterator when T is a ZST, reducing the length by `n`.
+// `n` must not exceed `self.len()`.
+macro_rules! zst_shrink {
+ ($self: ident, $n: ident) => {
+ let new_len = $self.end.addr() - $n;
+ zst_set_len!($self, new_len);
+ };
+}
+
// Inlining is_empty and len makes a huge performance difference
macro_rules! is_empty {
- // The way we encode the length of a ZST iterator, this works both for ZST
- // and non-ZST.
($self: ident) => {
- $self.ptr.as_ptr() as *const T == $self.end
+ if T::IS_ZST { $self.end.addr() == 0 } else { $self.ptr.as_ptr() as *const _ == $self.end }
};
}
@@ -13,16 +32,13 @@ macro_rules! len {
($self: ident) => {{
#![allow(unused_unsafe)] // we're sometimes used within an unsafe block
- let start = $self.ptr;
if T::IS_ZST {
- // This _cannot_ use `ptr_sub` because we depend on wrapping
- // to represent the length of long ZST slice iterators.
- $self.end.addr().wrapping_sub(start.as_ptr().addr())
+ $self.end.addr()
} else {
// To get rid of some bounds checks (see `position`), we use ptr_sub instead of
// offset_from (Tested by `codegen/slice-position-bounds-check`.)
// SAFETY: by the type invariant pointers are aligned and `start <= end`
- unsafe { $self.end.sub_ptr(start.as_ptr()) }
+ unsafe { $self.end.sub_ptr($self.ptr.as_ptr()) }
}
}};
}
@@ -50,14 +66,6 @@ macro_rules! iterator {
($self: ident) => {& $( $mut_ )? *$self.pre_dec_end(1)}
}
- // Shrinks the iterator when T is a ZST, by moving the end of the iterator
- // backwards by `n`. `n` must not exceed `self.len()`.
- macro_rules! zst_shrink {
- ($self: ident, $n: ident) => {
- $self.end = $self.end.wrapping_byte_sub($n);
- }
- }
-
impl<'a, T> $name<'a, T> {
// Helper function for creating a slice from the iterator.
#[inline(always)]
@@ -73,16 +81,15 @@ macro_rules! iterator {
// Unsafe because the offset must not exceed `self.len()`.
#[inline(always)]
unsafe fn post_inc_start(&mut self, offset: usize) -> * $raw_mut T {
+ let old = self.ptr;
if T::IS_ZST {
zst_shrink!(self, offset);
- self.ptr.as_ptr()
} else {
- let old = self.ptr.as_ptr();
// SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`,
// so this new pointer is inside `self` and thus guaranteed to be non-null.
- self.ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().add(offset)) };
- old
+ self.ptr = unsafe { self.ptr.add(offset) };
}
+ old.as_ptr()
}
// Helper function for moving the end of the iterator backwards by `offset` elements,
@@ -124,12 +131,10 @@ macro_rules! iterator {
fn next(&mut self) -> Option<$elem> {
// could be implemented with slices, but this avoids bounds checks
- // SAFETY: `assume` calls are safe since a slice's start pointer
- // must be non-null, and slices over non-ZSTs must also have a
- // non-null end pointer. The call to `next_unchecked!` is safe
- // since we check if the iterator is empty first.
+ // SAFETY: `assume` call is safe because slices over non-ZSTs must
+ // have a non-null end pointer. The call to `next_unchecked!` is
+ // safe since we check if the iterator is empty first.
unsafe {
- assume(!self.ptr.as_ptr().is_null());
if !<T>::IS_ZST {
assume(!self.end.is_null());
}
@@ -157,9 +162,7 @@ macro_rules! iterator {
if n >= len!(self) {
// This iterator is now empty.
if T::IS_ZST {
- // We have to do it this way as `ptr` may never be 0, but `end`
- // could be (due to wrapping).
- self.end = self.ptr.as_ptr();
+ zst_set_len!(self, 0);
} else {
// SAFETY: end can't be 0 if T isn't ZST because ptr isn't 0 and end >= ptr
unsafe {
@@ -339,12 +342,10 @@ macro_rules! iterator {
fn next_back(&mut self) -> Option<$elem> {
// could be implemented with slices, but this avoids bounds checks
- // SAFETY: `assume` calls are safe since a slice's start pointer must be non-null,
- // and slices over non-ZSTs must also have a non-null end pointer.
- // The call to `next_back_unchecked!` is safe since we check if the iterator is
- // empty first.
+ // SAFETY: `assume` call is safe because slices over non-ZSTs must
+ // have a non-null end pointer. The call to `next_back_unchecked!`
+ // is safe since we check if the iterator is empty first.
unsafe {
- assume(!self.ptr.as_ptr().is_null());
if !<T>::IS_ZST {
assume(!self.end.is_null());
}
@@ -360,7 +361,11 @@ macro_rules! iterator {
fn nth_back(&mut self, n: usize) -> Option<$elem> {
if n >= len!(self) {
// This iterator is now empty.
- self.end = self.ptr.as_ptr();
+ if T::IS_ZST {
+ zst_set_len!(self, 0);
+ } else {
+ self.end = self.ptr.as_ptr();
+ }
return None;
}
// SAFETY: We are in bounds. `pre_dec_end` does the right thing even for ZSTs.
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 4c891ba550f..6fd2b87d0e3 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -1595,7 +1595,8 @@ impl<T> [T] {
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_slice_split_at_not_mut", issue = "101158")]
+ #[rustc_const_stable(feature = "const_slice_split_at_not_mut", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_allow_const_fn_unstable(slice_split_at_unchecked)]
#[inline]
#[track_caller]
#[must_use]
@@ -3478,44 +3479,13 @@ impl<T> [T] {
// Ts = size_of::<U> / gcd(size_of::<T>, size_of::<U>)
//
// Luckily since all this is constant-evaluated... performance here matters not!
- #[inline]
- fn gcd(a: usize, b: usize) -> usize {
- use crate::intrinsics;
- // iterative stein’s algorithm
- // We should still make this `const fn` (and revert to recursive algorithm if we do)
- // because relying on llvm to consteval all this is… well, it makes me uncomfortable.
-
- // SAFETY: `a` and `b` are checked to be non-zero values.
- let (ctz_a, mut ctz_b) = unsafe {
- if a == 0 {
- return b;
- }
- if b == 0 {
- return a;
- }
- (intrinsics::cttz_nonzero(a), intrinsics::cttz_nonzero(b))
- };
- let k = ctz_a.min(ctz_b);
- let mut a = a >> ctz_a;
- let mut b = b;
- loop {
- // remove all factors of 2 from b
- b >>= ctz_b;
- if a > b {
- mem::swap(&mut a, &mut b);
- }
- b = b - a;
- // SAFETY: `b` is checked to be non-zero.
- unsafe {
- if b == 0 {
- break;
- }
- ctz_b = intrinsics::cttz_nonzero(b);
- }
- }
- a << k
+ const fn gcd(a: usize, b: usize) -> usize {
+ if b == 0 { a } else { gcd(b, a % b) }
}
- let gcd: usize = gcd(mem::size_of::<T>(), mem::size_of::<U>());
+
+ // Explicitly wrap the function call in a const block so it gets
+ // constant-evaluated even in debug mode.
+ let gcd: usize = const { gcd(mem::size_of::<T>(), mem::size_of::<U>()) };
let ts: usize = mem::size_of::<U>() / gcd;
let us: usize = mem::size_of::<T>() / gcd;
diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs
index e3a464a1c51..91ee2903aab 100644
--- a/library/core/src/str/pattern.rs
+++ b/library/core/src/str/pattern.rs
@@ -791,8 +791,8 @@ pub struct CharArrayRefSearcher<'a, 'b, const N: usize>(
/// # Examples
///
/// ```
-/// assert_eq!("Hello world".find(['l', 'l']), Some(2));
-/// assert_eq!("Hello world".find(['l', 'l']), Some(2));
+/// assert_eq!("Hello world".find(['o', 'l']), Some(2));
+/// assert_eq!("Hello world".find(['h', 'w']), Some(6));
/// ```
impl<'a, const N: usize> Pattern<'a> for [char; N] {
pattern_methods!(CharArraySearcher<'a, N>, MultiCharEqPattern, CharArraySearcher);
@@ -811,8 +811,8 @@ unsafe impl<'a, const N: usize> ReverseSearcher<'a> for CharArraySearcher<'a, N>
/// # Examples
///
/// ```
-/// assert_eq!("Hello world".find(&['l', 'l']), Some(2));
-/// assert_eq!("Hello world".find(&['l', 'l']), Some(2));
+/// assert_eq!("Hello world".find(&['o', 'l']), Some(2));
+/// assert_eq!("Hello world".find(&['h', 'w']), Some(6));
/// ```
impl<'a, 'b, const N: usize> Pattern<'a> for &'b [char; N] {
pattern_methods!(CharArrayRefSearcher<'a, 'b, N>, MultiCharEqPattern, CharArrayRefSearcher);
diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs
index 168516263f1..5283a576d1b 100644
--- a/library/core/src/task/poll.rs
+++ b/library/core/src/task/poll.rs
@@ -116,7 +116,7 @@ impl<T> Poll<T> {
/// let fut = Pin::new(&mut fut);
///
/// let num = fut.poll(cx).ready()?;
- /// # drop(num);
+ /// # let _ = num; // to silence unused warning
/// // ... use num
///
/// Poll::Ready(())
diff --git a/library/core/src/task/ready.rs b/library/core/src/task/ready.rs
index b1daf545fbe..8d12625e88d 100644
--- a/library/core/src/task/ready.rs
+++ b/library/core/src/task/ready.rs
@@ -22,7 +22,7 @@ use core::task::Poll;
/// let fut = Pin::new(&mut fut);
///
/// let num = ready!(fut.poll(cx));
-/// # drop(num);
+/// # let _ = num;
/// // ... use num
///
/// Poll::Ready(())
@@ -44,7 +44,7 @@ use core::task::Poll;
/// Poll::Ready(t) => t,
/// Poll::Pending => return Poll::Pending,
/// };
-/// # drop(num);
+/// # let _ = num; // to silence unused warning
/// # // ... use num
/// #
/// # Poll::Ready(())
diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs
index 808825326ae..7043ab5ff2b 100644
--- a/library/core/src/task/wake.rs
+++ b/library/core/src/task/wake.rs
@@ -232,7 +232,7 @@ impl fmt::Debug for Context<'_> {
///
/// [`Future::poll()`]: core::future::Future::poll
/// [`Poll::Pending`]: core::task::Poll::Pending
-#[repr(transparent)]
+#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/66401
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct Waker {
waker: RawWaker,
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 84859a54c26..3933e328951 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -18,7 +18,6 @@
#![feature(const_pointer_byte_offsets)]
#![feature(const_pointer_is_aligned)]
#![feature(const_ptr_as_ref)]
-#![feature(const_ptr_read)]
#![feature(const_ptr_write)]
#![feature(const_trait_impl)]
#![feature(const_likely)]
@@ -54,6 +53,7 @@
#![feature(maybe_uninit_uninit_array_transpose)]
#![feature(min_specialization)]
#![feature(numfmt)]
+#![feature(num_midpoint)]
#![feature(step_trait)]
#![feature(str_internals)]
#![feature(std_internals)]
diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs
index 18c55e43aac..439bbe66997 100644
--- a/library/core/tests/num/int_macros.rs
+++ b/library/core/tests/num/int_macros.rs
@@ -364,6 +364,32 @@ macro_rules! int_module {
assert_eq!((0 as $T).borrowing_sub($T::MIN, false), ($T::MIN, true));
assert_eq!((0 as $T).borrowing_sub($T::MIN, true), ($T::MAX, false));
}
+
+ #[test]
+ fn test_midpoint() {
+ assert_eq!(<$T>::midpoint(1, 3), 2);
+ assert_eq!(<$T>::midpoint(3, 1), 2);
+
+ assert_eq!(<$T>::midpoint(0, 0), 0);
+ assert_eq!(<$T>::midpoint(0, 2), 1);
+ assert_eq!(<$T>::midpoint(2, 0), 1);
+ assert_eq!(<$T>::midpoint(2, 2), 2);
+
+ assert_eq!(<$T>::midpoint(1, 4), 2);
+ assert_eq!(<$T>::midpoint(4, 1), 2);
+ assert_eq!(<$T>::midpoint(3, 4), 3);
+ assert_eq!(<$T>::midpoint(4, 3), 3);
+
+ assert_eq!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), -1);
+ assert_eq!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), -1);
+ assert_eq!(<$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN);
+ assert_eq!(<$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX);
+
+ assert_eq!(<$T>::midpoint(<$T>::MIN, 6), <$T>::MIN / 2 + 3);
+ assert_eq!(<$T>::midpoint(6, <$T>::MIN), <$T>::MIN / 2 + 3);
+ assert_eq!(<$T>::midpoint(<$T>::MAX, 6), <$T>::MAX / 2 + 3);
+ assert_eq!(<$T>::midpoint(6, <$T>::MAX), <$T>::MAX / 2 + 3);
+ }
}
};
}
diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs
index 3e1f848ccfe..3f3659ba837 100644
--- a/library/core/tests/num/mod.rs
+++ b/library/core/tests/num/mod.rs
@@ -724,7 +724,7 @@ assume_usize_width! {
}
macro_rules! test_float {
- ($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr) => {
+ ($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr, $min: expr, $max: expr, $min_pos: expr) => {
mod $modname {
#[test]
fn min() {
@@ -845,6 +845,38 @@ macro_rules! test_float {
assert!(($nan as $fty).maximum($nan).is_nan());
}
#[test]
+ fn midpoint() {
+ assert_eq!((0.5 as $fty).midpoint(0.5), 0.5);
+ assert_eq!((0.5 as $fty).midpoint(2.5), 1.5);
+ assert_eq!((3.0 as $fty).midpoint(4.0), 3.5);
+ assert_eq!((-3.0 as $fty).midpoint(4.0), 0.5);
+ assert_eq!((3.0 as $fty).midpoint(-4.0), -0.5);
+ assert_eq!((-3.0 as $fty).midpoint(-4.0), -3.5);
+ assert_eq!((0.0 as $fty).midpoint(0.0), 0.0);
+ assert_eq!((-0.0 as $fty).midpoint(-0.0), -0.0);
+ assert_eq!((-5.0 as $fty).midpoint(5.0), 0.0);
+ assert_eq!(($max as $fty).midpoint($min), 0.0);
+ assert_eq!(($min as $fty).midpoint($max), -0.0);
+ assert_eq!(($max as $fty).midpoint($min_pos), $max / 2.);
+ assert_eq!((-$max as $fty).midpoint($min_pos), -$max / 2.);
+ assert_eq!(($max as $fty).midpoint(-$min_pos), $max / 2.);
+ assert_eq!((-$max as $fty).midpoint(-$min_pos), -$max / 2.);
+ assert_eq!(($min_pos as $fty).midpoint($max), $max / 2.);
+ assert_eq!(($min_pos as $fty).midpoint(-$max), -$max / 2.);
+ assert_eq!((-$min_pos as $fty).midpoint($max), $max / 2.);
+ assert_eq!((-$min_pos as $fty).midpoint(-$max), -$max / 2.);
+ assert_eq!(($max as $fty).midpoint($max), $max);
+ assert_eq!(($min_pos as $fty).midpoint($min_pos), $min_pos);
+ assert_eq!((-$min_pos as $fty).midpoint(-$min_pos), -$min_pos);
+ assert_eq!(($max as $fty).midpoint(5.0), $max / 2.0 + 2.5);
+ assert_eq!(($max as $fty).midpoint(-5.0), $max / 2.0 - 2.5);
+ assert_eq!(($inf as $fty).midpoint($inf), $inf);
+ assert_eq!(($neginf as $fty).midpoint($neginf), $neginf);
+ 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]
fn rem_euclid() {
let a: $fty = 42.0;
assert!($inf.rem_euclid(a).is_nan());
@@ -867,5 +899,23 @@ macro_rules! test_float {
};
}
-test_float!(f32, f32, f32::INFINITY, f32::NEG_INFINITY, f32::NAN);
-test_float!(f64, f64, f64::INFINITY, f64::NEG_INFINITY, f64::NAN);
+test_float!(
+ f32,
+ f32,
+ f32::INFINITY,
+ f32::NEG_INFINITY,
+ f32::NAN,
+ f32::MIN,
+ f32::MAX,
+ f32::MIN_POSITIVE
+);
+test_float!(
+ f64,
+ f64,
+ f64::INFINITY,
+ f64::NEG_INFINITY,
+ f64::NAN,
+ f64::MIN,
+ f64::MAX,
+ f64::MIN_POSITIVE
+);
diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs
index 15ae9f2324f..7d6203db0b9 100644
--- a/library/core/tests/num/uint_macros.rs
+++ b/library/core/tests/num/uint_macros.rs
@@ -252,6 +252,32 @@ macro_rules! uint_module {
assert_eq!($T::MAX.borrowing_sub(0, true), ($T::MAX - 1, false));
assert_eq!($T::MAX.borrowing_sub($T::MAX, true), ($T::MAX, true));
}
+
+ #[test]
+ fn test_midpoint() {
+ assert_eq!(<$T>::midpoint(1, 3), 2);
+ assert_eq!(<$T>::midpoint(3, 1), 2);
+
+ assert_eq!(<$T>::midpoint(0, 0), 0);
+ assert_eq!(<$T>::midpoint(0, 2), 1);
+ assert_eq!(<$T>::midpoint(2, 0), 1);
+ assert_eq!(<$T>::midpoint(2, 2), 2);
+
+ assert_eq!(<$T>::midpoint(1, 4), 2);
+ assert_eq!(<$T>::midpoint(4, 1), 2);
+ assert_eq!(<$T>::midpoint(3, 4), 3);
+ assert_eq!(<$T>::midpoint(4, 3), 3);
+
+ assert_eq!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2);
+ assert_eq!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), (<$T>::MAX - <$T>::MIN) / 2);
+ assert_eq!(<$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN);
+ assert_eq!(<$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX);
+
+ assert_eq!(<$T>::midpoint(<$T>::MIN, 6), <$T>::MIN / 2 + 3);
+ assert_eq!(<$T>::midpoint(6, <$T>::MIN), <$T>::MIN / 2 + 3);
+ assert_eq!(<$T>::midpoint(<$T>::MAX, 6), (<$T>::MAX - <$T>::MIN) / 2 + 3);
+ assert_eq!(<$T>::midpoint(6, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2 + 3);
+ }
}
};
}