summaryrefslogtreecommitdiffstats
path: root/library/core
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
commit9835e2ae736235810b4ea1c162ca5e65c547e770 (patch)
tree3fcebf40ed70e581d776a8a4c65923e8ec20e026 /library/core
parentReleasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff)
downloadrustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz
rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/core')
-rw-r--r--library/core/benches/fmt.rs24
-rw-r--r--library/core/benches/iter.rs46
-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/flt2dec/strategy/grisu.rs27
-rw-r--r--library/core/benches/num/mod.rs6
-rw-r--r--library/core/src/alloc/global.rs3
-rw-r--r--library/core/src/alloc/layout.rs15
-rw-r--r--library/core/src/alloc/mod.rs1
-rw-r--r--library/core/src/any.rs13
-rw-r--r--library/core/src/array/ascii.rs47
-rw-r--r--library/core/src/array/iter.rs18
-rw-r--r--library/core/src/array/mod.rs35
-rw-r--r--library/core/src/ascii.rs75
-rw-r--r--library/core/src/ascii/ascii_char.rs565
-rw-r--r--library/core/src/bool.rs15
-rw-r--r--library/core/src/borrow.rs17
-rw-r--r--library/core/src/cell.rs53
-rw-r--r--library/core/src/cell/lazy.rs28
-rw-r--r--library/core/src/cell/once.rs3
-rw-r--r--library/core/src/char/convert.rs12
-rw-r--r--library/core/src/char/methods.rs76
-rw-r--r--library/core/src/char/mod.rs252
-rw-r--r--library/core/src/clone.rs23
-rw-r--r--library/core/src/cmp.rs212
-rw-r--r--library/core/src/convert/mod.rs49
-rw-r--r--library/core/src/convert/num.rs24
-rw-r--r--library/core/src/default.rs4
-rw-r--r--library/core/src/escape.rs112
-rw-r--r--library/core/src/ffi/c_str.rs21
-rw-r--r--library/core/src/ffi/mod.rs20
-rw-r--r--library/core/src/fmt/builders.rs14
-rw-r--r--library/core/src/fmt/float.rs12
-rw-r--r--library/core/src/fmt/mod.rs416
-rw-r--r--library/core/src/fmt/num.rs15
-rw-r--r--library/core/src/fmt/rt.rs212
-rw-r--r--library/core/src/fmt/rt/v1.rs63
-rw-r--r--library/core/src/future/into_future.rs1
-rw-r--r--library/core/src/future/join.rs6
-rw-r--r--library/core/src/future/mod.rs8
-rw-r--r--library/core/src/hash/mod.rs95
-rw-r--r--library/core/src/hash/sip.rs17
-rw-r--r--library/core/src/hint.rs13
-rw-r--r--library/core/src/internal_macros.rs71
-rw-r--r--library/core/src/intrinsics.rs79
-rw-r--r--library/core/src/intrinsics/mir.rs7
-rw-r--r--library/core/src/iter/adapters/chain.rs2
-rw-r--r--library/core/src/iter/adapters/filter.rs55
-rw-r--r--library/core/src/iter/adapters/filter_map.rs62
-rw-r--r--library/core/src/iter/adapters/flatten.rs68
-rw-r--r--library/core/src/iter/range.rs20
-rw-r--r--library/core/src/iter/sources/empty.rs3
-rw-r--r--library/core/src/iter/traits/collect.rs13
-rw-r--r--library/core/src/iter/traits/iterator.rs1
-rw-r--r--library/core/src/lib.rs18
-rw-r--r--library/core/src/macros/mod.rs3
-rw-r--r--library/core/src/macros/panic.md2
-rw-r--r--library/core/src/marker.rs211
-rw-r--r--library/core/src/mem/manually_drop.rs6
-rw-r--r--library/core/src/mem/maybe_uninit.rs14
-rw-r--r--library/core/src/mem/mod.rs62
-rw-r--r--library/core/src/mem/transmutability.rs6
-rw-r--r--library/core/src/net/socket_addr.rs27
-rw-r--r--library/core/src/num/error.rs6
-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/flt2dec/strategy/grisu.rs16
-rw-r--r--library/core/src/num/int_macros.rs49
-rw-r--r--library/core/src/num/mod.rs87
-rw-r--r--library/core/src/num/nonzero.rs130
-rw-r--r--library/core/src/num/uint_macros.rs4
-rw-r--r--library/core/src/num/wrapping.rs168
-rw-r--r--library/core/src/ops/arith.rs78
-rw-r--r--library/core/src/ops/bit.rs69
-rw-r--r--library/core/src/ops/control_flow.rs9
-rw-r--r--library/core/src/ops/deref.rs8
-rw-r--r--library/core/src/ops/drop.rs68
-rw-r--r--library/core/src/ops/function.rs25
-rw-r--r--library/core/src/ops/index.rs5
-rw-r--r--library/core/src/ops/range.rs95
-rw-r--r--library/core/src/ops/try_trait.rs19
-rw-r--r--library/core/src/option.rs217
-rw-r--r--library/core/src/panic.rs40
-rw-r--r--library/core/src/panic/panic_info.rs2
-rw-r--r--library/core/src/panicking.rs2
-rw-r--r--library/core/src/pin.rs2
-rw-r--r--library/core/src/primitive_docs.rs96
-rw-r--r--library/core/src/ptr/alignment.rs16
-rw-r--r--library/core/src/ptr/const_ptr.rs27
-rw-r--r--library/core/src/ptr/mod.rs305
-rw-r--r--library/core/src/ptr/mut_ptr.rs39
-rw-r--r--library/core/src/ptr/non_null.rs30
-rw-r--r--library/core/src/ptr/unique.rs14
-rw-r--r--library/core/src/result.rs74
-rw-r--r--library/core/src/slice/ascii.rs79
-rw-r--r--library/core/src/slice/index.rs27
-rw-r--r--library/core/src/slice/iter.rs42
-rw-r--r--library/core/src/slice/iter/macros.rs75
-rw-r--r--library/core/src/slice/memchr.rs14
-rw-r--r--library/core/src/slice/mod.rs372
-rw-r--r--library/core/src/slice/select.rs302
-rw-r--r--library/core/src/slice/sort.rs181
-rw-r--r--library/core/src/str/mod.rs35
-rw-r--r--library/core/src/str/pattern.rs8
-rw-r--r--library/core/src/str/traits.rs22
-rw-r--r--library/core/src/sync/atomic.rs18
-rw-r--r--library/core/src/task/mod.rs2
-rw-r--r--library/core/src/task/poll.rs36
-rw-r--r--library/core/src/task/ready.rs61
-rw-r--r--library/core/src/task/wake.rs2
-rw-r--r--library/core/src/time.rs26
-rw-r--r--library/core/src/tuple.rs50
-rw-r--r--library/core/tests/asserting.rs6
-rw-r--r--library/core/tests/atomic.rs2
-rw-r--r--library/core/tests/bool.rs2
-rw-r--r--library/core/tests/cell.rs2
-rw-r--r--library/core/tests/char.rs2
-rw-r--r--library/core/tests/clone.rs1
-rw-r--r--library/core/tests/cmp.rs6
-rw-r--r--library/core/tests/convert.rs2
-rw-r--r--library/core/tests/hash/mod.rs24
-rw-r--r--library/core/tests/hash/sip.rs4
-rw-r--r--library/core/tests/lazy.rs4
-rw-r--r--library/core/tests/lib.rs6
-rw-r--r--library/core/tests/mem.rs210
-rw-r--r--library/core/tests/nonzero.rs20
-rw-r--r--library/core/tests/num/const_from.rs2
-rw-r--r--library/core/tests/num/ieee754.rs1
-rw-r--r--library/core/tests/num/int_macros.rs26
-rw-r--r--library/core/tests/num/mod.rs58
-rw-r--r--library/core/tests/num/uint_macros.rs26
-rw-r--r--library/core/tests/option.rs24
-rw-r--r--library/core/tests/time.rs12
133 files changed, 4317 insertions, 2675 deletions
diff --git a/library/core/benches/fmt.rs b/library/core/benches/fmt.rs
index ff726ff75..d1cdb12e5 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/iter.rs b/library/core/benches/iter.rs
index 9193c79be..60ef83223 100644
--- a/library/core/benches/iter.rs
+++ b/library/core/benches/iter.rs
@@ -404,7 +404,7 @@ fn bench_trusted_random_access_adapters(b: &mut Bencher) {
/// Exercises the iter::Copied specialization for slice::Iter
#[bench]
-fn bench_copied_chunks(b: &mut Bencher) {
+fn bench_next_chunk_copied(b: &mut Bencher) {
let v = vec![1u8; 1024];
b.iter(|| {
@@ -421,7 +421,7 @@ fn bench_copied_chunks(b: &mut Bencher) {
/// Exercises the TrustedRandomAccess specialization in ArrayChunks
#[bench]
-fn bench_trusted_random_access_chunks(b: &mut Bencher) {
+fn bench_next_chunk_trusted_random_access(b: &mut Bencher) {
let v = vec![1u8; 1024];
b.iter(|| {
@@ -437,3 +437,45 @@ fn bench_trusted_random_access_chunks(b: &mut Bencher) {
.sum::<Wrapping<u64>>()
})
}
+
+#[bench]
+fn bench_next_chunk_filter_even(b: &mut Bencher) {
+ let a = (0..1024).next_chunk::<1024>().unwrap();
+
+ b.iter(|| black_box(&a).iter().filter(|&&i| i % 2 == 0).next_chunk::<32>())
+}
+
+#[bench]
+fn bench_next_chunk_filter_predictably_true(b: &mut Bencher) {
+ let a = (0..1024).next_chunk::<1024>().unwrap();
+
+ b.iter(|| black_box(&a).iter().filter(|&&i| i < 100).next_chunk::<32>())
+}
+
+#[bench]
+fn bench_next_chunk_filter_mostly_false(b: &mut Bencher) {
+ let a = (0..1024).next_chunk::<1024>().unwrap();
+
+ b.iter(|| black_box(&a).iter().filter(|&&i| i > 900).next_chunk::<32>())
+}
+
+#[bench]
+fn bench_next_chunk_filter_map_even(b: &mut Bencher) {
+ let a = (0..1024).next_chunk::<1024>().unwrap();
+
+ b.iter(|| black_box(&a).iter().filter_map(|&i| (i % 2 == 0).then(|| i)).next_chunk::<32>())
+}
+
+#[bench]
+fn bench_next_chunk_filter_map_predictably_true(b: &mut Bencher) {
+ let a = (0..1024).next_chunk::<1024>().unwrap();
+
+ b.iter(|| black_box(&a).iter().filter_map(|&i| (i < 100).then(|| i)).next_chunk::<32>())
+}
+
+#[bench]
+fn bench_next_chunk_filter_map_mostly_false(b: &mut Bencher) {
+ let a = (0..1024).next_chunk::<1024>().unwrap();
+
+ b.iter(|| black_box(&a).iter().filter_map(|&i| (i > 900).then(|| i)).next_chunk::<32>())
+}
diff --git a/library/core/benches/num/dec2flt/mod.rs b/library/core/benches/num/dec2flt/mod.rs
index 305baa687..fb4a786b2 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 32fd5e626..1a330ef5f 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/flt2dec/strategy/grisu.rs b/library/core/benches/num/flt2dec/strategy/grisu.rs
index 6bea5e55d..17d6b474a 100644
--- a/library/core/benches/num/flt2dec/strategy/grisu.rs
+++ b/library/core/benches/num/flt2dec/strategy/grisu.rs
@@ -81,3 +81,30 @@ fn bench_big_exact_inf(b: &mut Bencher) {
format_exact(black_box(&decoded), &mut buf, i16::MIN);
});
}
+
+#[bench]
+fn bench_one_exact_inf(b: &mut Bencher) {
+ let decoded = decode_finite(1.0);
+ let mut buf = [MaybeUninit::new(0); 1024];
+ b.iter(|| {
+ format_exact(black_box(&decoded), &mut buf, i16::MIN);
+ });
+}
+
+#[bench]
+fn bench_trailing_zero_exact_inf(b: &mut Bencher) {
+ let decoded = decode_finite(250.000000000000000000000000);
+ let mut buf = [MaybeUninit::new(0); 1024];
+ b.iter(|| {
+ format_exact(black_box(&decoded), &mut buf, i16::MIN);
+ });
+}
+
+#[bench]
+fn bench_halfway_point_exact_inf(b: &mut Bencher) {
+ let decoded = decode_finite(1.00000000000000011102230246251565404236316680908203125);
+ let mut buf = [MaybeUninit::new(0); 1024];
+ b.iter(|| {
+ format_exact(black_box(&decoded), &mut buf, i16::MIN);
+ });
+}
diff --git a/library/core/benches/num/mod.rs b/library/core/benches/num/mod.rs
index 2f9cad272..b97014d9b 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/alloc/global.rs b/library/core/src/alloc/global.rs
index 18da70451..c58211170 100644
--- a/library/core/src/alloc/global.rs
+++ b/library/core/src/alloc/global.rs
@@ -235,7 +235,8 @@ pub unsafe trait GlobalAlloc {
/// * `new_size` must be greater than zero.
///
/// * `new_size`, when rounded up to the nearest multiple of `layout.align()`,
- /// must not overflow (i.e., the rounded value must be less than `usize::MAX`).
+ /// must not overflow isize (i.e., the rounded value must be less than or
+ /// equal to `isize::MAX`).
///
/// (Extension subtraits might provide more specific bounds on
/// behavior, e.g., guarantee a sentinel address or a null pointer
diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs
index ac3d84718..597303037 100644
--- a/library/core/src/alloc/layout.rs
+++ b/library/core/src/alloc/layout.rs
@@ -231,9 +231,8 @@ impl Layout {
/// Returns an error if the combination of `self.size()` and the given
/// `align` violates the conditions listed in [`Layout::from_size_align`].
#[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
- #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
#[inline]
- pub const fn align_to(&self, align: usize) -> Result<Self, LayoutError> {
+ pub fn align_to(&self, align: usize) -> Result<Self, LayoutError> {
Layout::from_size_align(self.size(), cmp::max(self.align(), align))
}
@@ -315,9 +314,8 @@ impl Layout {
///
/// On arithmetic overflow, returns `LayoutError`.
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
- #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
#[inline]
- pub const fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutError> {
+ pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutError> {
// This cannot overflow. Quoting from the invariant of Layout:
// > `size`, when rounded up to the nearest multiple of `align`,
// > must not overflow isize (i.e., the rounded value must be
@@ -376,9 +374,8 @@ impl Layout {
/// # assert_eq!(repr_c(&[u64, u32, u16, u32]), Ok((s, vec![0, 8, 12, 16])));
/// ```
#[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
- #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
#[inline]
- pub const fn extend(&self, next: Self) -> Result<(Self, usize), LayoutError> {
+ pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutError> {
let new_align = cmp::max(self.align, next.align);
let pad = self.padding_needed_for(next.align());
@@ -403,9 +400,8 @@ impl Layout {
///
/// On arithmetic overflow, returns `LayoutError`.
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
- #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
#[inline]
- pub const fn repeat_packed(&self, n: usize) -> Result<Self, LayoutError> {
+ pub fn repeat_packed(&self, n: usize) -> Result<Self, LayoutError> {
let size = self.size().checked_mul(n).ok_or(LayoutError)?;
// The safe constructor is called here to enforce the isize size limit.
Layout::from_size_alignment(size, self.align)
@@ -418,9 +414,8 @@ impl Layout {
///
/// On arithmetic overflow, returns `LayoutError`.
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
- #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
#[inline]
- pub const fn extend_packed(&self, next: Self) -> Result<Self, LayoutError> {
+ pub fn extend_packed(&self, next: Self) -> Result<Self, LayoutError> {
let new_size = self.size().checked_add(next.size()).ok_or(LayoutError)?;
// The safe constructor is called here to enforce the isize size limit.
Layout::from_size_alignment(new_size, self.align)
diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs
index ff390322d..d6ae2b821 100644
--- a/library/core/src/alloc/mod.rs
+++ b/library/core/src/alloc/mod.rs
@@ -105,7 +105,6 @@ impl fmt::Display for AllocError {
///
/// [*currently allocated*]: #currently-allocated-memory
#[unstable(feature = "allocator_api", issue = "32838")]
-#[const_trait]
pub unsafe trait Allocator {
/// Attempts to allocate a block of memory.
///
diff --git a/library/core/src/any.rs b/library/core/src/any.rs
index c27646b8f..7969f4055 100644
--- a/library/core/src/any.rs
+++ b/library/core/src/any.rs
@@ -662,13 +662,20 @@ impl dyn Any + Send + Sync {
/// While `TypeId` implements `Hash`, `PartialOrd`, and `Ord`, it is worth
/// noting that the hashes and ordering will vary between Rust releases. Beware
/// of relying on them inside of your code!
-#[derive(Clone, Copy, Debug, Hash, Eq)]
-#[derive_const(PartialEq, PartialOrd, Ord)]
+#[derive(Clone, Copy, Debug, Hash, Eq, PartialOrd, Ord)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct TypeId {
t: u64,
}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialEq for TypeId {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ self.t == other.t
+ }
+}
+
impl TypeId {
/// Returns the `TypeId` of the type this generic function has been
/// instantiated with.
@@ -867,7 +874,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/array/ascii.rs b/library/core/src/array/ascii.rs
new file mode 100644
index 000000000..3fea9a440
--- /dev/null
+++ b/library/core/src/array/ascii.rs
@@ -0,0 +1,47 @@
+use crate::ascii;
+
+#[cfg(not(test))]
+impl<const N: usize> [u8; N] {
+ /// Converts this array of bytes into a array of ASCII characters,
+ /// or returns `None` if any of the characters is non-ASCII.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ascii_char)]
+ /// #![feature(const_option)]
+ ///
+ /// const HEX_DIGITS: [std::ascii::Char; 16] =
+ /// *b"0123456789abcdef".as_ascii().unwrap();
+ ///
+ /// assert_eq!(HEX_DIGITS[1].as_str(), "1");
+ /// assert_eq!(HEX_DIGITS[10].as_str(), "a");
+ /// ```
+ #[unstable(feature = "ascii_char", issue = "110998")]
+ #[must_use]
+ #[inline]
+ pub const fn as_ascii(&self) -> Option<&[ascii::Char; N]> {
+ if self.is_ascii() {
+ // SAFETY: Just checked that it's ASCII
+ Some(unsafe { self.as_ascii_unchecked() })
+ } else {
+ None
+ }
+ }
+
+ /// Converts this array of bytes into a array of ASCII characters,
+ /// without checking whether they're valid.
+ ///
+ /// # Safety
+ ///
+ /// Every byte in the array must be in `0..=127`, or else this is UB.
+ #[unstable(feature = "ascii_char", issue = "110998")]
+ #[must_use]
+ #[inline]
+ pub const unsafe fn as_ascii_unchecked(&self) -> &[ascii::Char; N] {
+ let byte_ptr: *const [u8; N] = self;
+ let ascii_ptr = byte_ptr as *const [ascii::Char; N];
+ // SAFETY: The caller promised all the bytes are ASCII
+ unsafe { &*ascii_ptr }
+ }
+}
diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs
index 73e2c2cfb..587877dff 100644
--- a/library/core/src/array/iter.rs
+++ b/library/core/src/array/iter.rs
@@ -3,8 +3,9 @@
use crate::num::NonZeroUsize;
use crate::{
fmt,
+ intrinsics::transmute_unchecked,
iter::{self, ExactSizeIterator, FusedIterator, TrustedLen},
- mem::{self, MaybeUninit},
+ mem::MaybeUninit,
ops::{IndexRange, Range},
ptr,
};
@@ -63,18 +64,11 @@ impl<T, const N: usize> IntoIterator for [T; N] {
// an array of `T`.
//
// With that, this initialization satisfies the invariants.
-
- // FIXME(LukasKalbertodt): actually use `mem::transmute` here, once it
- // works with const generics:
- // `mem::transmute::<[T; N], [MaybeUninit<T>; N]>(array)`
//
- // Until then, we can use `mem::transmute_copy` to create a bitwise copy
- // as a different type, then forget `array` so that it is not dropped.
- unsafe {
- let iter = IntoIter { data: mem::transmute_copy(&self), alive: IndexRange::zero_to(N) };
- mem::forget(self);
- iter
- }
+ // FIXME: If normal `transmute` ever gets smart enough to allow this
+ // directly, use it instead of `transmute_unchecked`.
+ let data: [MaybeUninit<T>; N] = unsafe { transmute_unchecked(self) };
+ IntoIter { data, alive: IndexRange::zero_to(N) }
}
}
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index 1643842d6..fec92320a 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -17,6 +17,7 @@ use crate::ops::{
};
use crate::slice::{Iter, IterMut};
+mod ascii;
mod drain;
mod equality;
mod iter;
@@ -148,8 +149,7 @@ impl Error for TryFromSliceError {
}
#[stable(feature = "try_from_slice_error", since = "1.36.0")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl const From<Infallible> for TryFromSliceError {
+impl From<Infallible> for TryFromSliceError {
fn from(x: Infallible) -> TryFromSliceError {
match x {}
}
@@ -172,16 +172,14 @@ impl<T, const N: usize> AsMut<[T]> for [T; N] {
}
#[stable(feature = "array_borrow", since = "1.4.0")]
-#[rustc_const_unstable(feature = "const_borrow", issue = "91522")]
-impl<T, const N: usize> const Borrow<[T]> for [T; N] {
+impl<T, const N: usize> Borrow<[T]> for [T; N] {
fn borrow(&self) -> &[T] {
self
}
}
#[stable(feature = "array_borrow", since = "1.4.0")]
-#[rustc_const_unstable(feature = "const_borrow", issue = "91522")]
-impl<T, const N: usize> const BorrowMut<[T]> for [T; N] {
+impl<T, const N: usize> BorrowMut<[T]> for [T; N] {
fn borrow_mut(&mut self) -> &mut [T] {
self
}
@@ -206,6 +204,7 @@ where
{
type Error = TryFromSliceError;
+ #[inline]
fn try_from(slice: &[T]) -> Result<[T; N], TryFromSliceError> {
<&Self>::try_from(slice).map(|r| *r)
}
@@ -230,6 +229,7 @@ where
{
type Error = TryFromSliceError;
+ #[inline]
fn try_from(slice: &mut [T]) -> Result<[T; N], TryFromSliceError> {
<Self>::try_from(&*slice)
}
@@ -251,7 +251,8 @@ where
impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N] {
type Error = TryFromSliceError;
- fn try_from(slice: &[T]) -> Result<&[T; N], TryFromSliceError> {
+ #[inline]
+ fn try_from(slice: &'a [T]) -> Result<&'a [T; N], TryFromSliceError> {
if slice.len() == N {
let ptr = slice.as_ptr() as *const [T; N];
// SAFETY: ok because we just checked that the length fits
@@ -278,7 +279,8 @@ impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N] {
impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N] {
type Error = TryFromSliceError;
- fn try_from(slice: &mut [T]) -> Result<&mut [T; N], TryFromSliceError> {
+ #[inline]
+ fn try_from(slice: &'a mut [T]) -> Result<&'a mut [T; N], TryFromSliceError> {
if slice.len() == N {
let ptr = slice.as_mut_ptr() as *mut [T; N];
// SAFETY: ok because we just checked that the length fits
@@ -293,7 +295,6 @@ impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N] {
/// as required by the `Borrow` implementation.
///
/// ```
-/// #![feature(build_hasher_simple_hash_one)]
/// use std::hash::BuildHasher;
///
/// let b = std::collections::hash_map::RandomState::new();
@@ -336,10 +337,9 @@ impl<'a, T, const N: usize> IntoIterator for &'a mut [T; N] {
}
#[stable(feature = "index_trait_on_arrays", since = "1.50.0")]
-#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
-impl<T, I, const N: usize> const Index<I> for [T; N]
+impl<T, I, const N: usize> Index<I> for [T; N]
where
- [T]: ~const Index<I>,
+ [T]: Index<I>,
{
type Output = <[T] as Index<I>>::Output;
@@ -350,10 +350,9 @@ where
}
#[stable(feature = "index_trait_on_arrays", since = "1.50.0")]
-#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
-impl<T, I, const N: usize> const IndexMut<I> for [T; N]
+impl<T, I, const N: usize> IndexMut<I> for [T; N]
where
- [T]: ~const IndexMut<I>,
+ [T]: IndexMut<I>,
{
#[inline]
fn index_mut(&mut self, index: I) -> &mut Self::Output {
@@ -435,8 +434,7 @@ impl<T: Copy> SpecArrayClone for T {
macro_rules! array_impl_default {
{$n:expr, $t:ident $($ts:ident)*} => {
#[stable(since = "1.4.0", feature = "array_default")]
- #[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
- impl<T> const Default for [T; $n] where T: ~const Default {
+ impl<T> Default for [T; $n] where T: Default {
fn default() -> [T; $n] {
[$t::default(), $($ts::default()),*]
}
@@ -445,8 +443,7 @@ macro_rules! array_impl_default {
};
{$n:expr,} => {
#[stable(since = "1.4.0", feature = "array_default")]
- #[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
- impl<T> const Default for [T; $n] {
+ impl<T> Default for [T; $n] {
fn default() -> [T; $n] { [] }
}
};
diff --git a/library/core/src/ascii.rs b/library/core/src/ascii.rs
index 8a4cb78cc..ef8e4d098 100644
--- a/library/core/src/ascii.rs
+++ b/library/core/src/ascii.rs
@@ -9,10 +9,14 @@
#![stable(feature = "core_ascii", since = "1.26.0")]
+use crate::escape;
use crate::fmt;
use crate::iter::FusedIterator;
-use crate::ops::Range;
-use crate::str::from_utf8_unchecked;
+use crate::num::NonZeroUsize;
+
+mod ascii_char;
+#[unstable(feature = "ascii_char", issue = "110998")]
+pub use ascii_char::AsciiChar as Char;
/// An iterator over the escaped version of a byte.
///
@@ -21,10 +25,7 @@ use crate::str::from_utf8_unchecked;
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
-pub struct EscapeDefault {
- range: Range<u8>,
- data: [u8; 4],
-}
+pub struct EscapeDefault(escape::EscapeIterInner<4>);
/// Returns an iterator that produces an escaped version of a `u8`.
///
@@ -90,21 +91,9 @@ pub struct EscapeDefault {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn escape_default(c: u8) -> EscapeDefault {
- let (data, len) = match c {
- b'\t' => ([b'\\', b't', 0, 0], 2),
- b'\r' => ([b'\\', b'r', 0, 0], 2),
- b'\n' => ([b'\\', b'n', 0, 0], 2),
- b'\\' => ([b'\\', b'\\', 0, 0], 2),
- b'\'' => ([b'\\', b'\'', 0, 0], 2),
- b'"' => ([b'\\', b'"', 0, 0], 2),
- b'\x20'..=b'\x7e' => ([c, 0, 0, 0], 1),
- _ => {
- let hex_digits: &[u8; 16] = b"0123456789abcdef";
- ([b'\\', b'x', hex_digits[(c >> 4) as usize], hex_digits[(c & 0xf) as usize]], 4)
- }
- };
-
- return EscapeDefault { range: 0..len, data };
+ let mut data = [Char::Null; 4];
+ let range = escape::escape_ascii_into(&mut data, c);
+ EscapeDefault(escape::EscapeIterInner::new(data, range))
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -113,33 +102,59 @@ impl Iterator for EscapeDefault {
#[inline]
fn next(&mut self) -> Option<u8> {
- self.range.next().map(|i| self.data[i as usize])
+ self.0.next()
}
+
+ #[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
- self.range.size_hint()
+ let n = self.0.len();
+ (n, Some(n))
}
+
+ #[inline]
+ fn count(self) -> usize {
+ self.0.len()
+ }
+
+ #[inline]
fn last(mut self) -> Option<u8> {
- self.next_back()
+ self.0.next_back()
+ }
+
+ #[inline]
+ fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+ self.0.advance_by(n)
}
}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl DoubleEndedIterator for EscapeDefault {
+ #[inline]
fn next_back(&mut self) -> Option<u8> {
- self.range.next_back().map(|i| self.data[i as usize])
+ self.0.next_back()
+ }
+
+ #[inline]
+ fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+ self.0.advance_back_by(n)
}
}
+
#[stable(feature = "rust1", since = "1.0.0")]
-impl ExactSizeIterator for EscapeDefault {}
+impl ExactSizeIterator for EscapeDefault {
+ #[inline]
+ fn len(&self) -> usize {
+ self.0.len()
+ }
+}
+
#[stable(feature = "fused", since = "1.26.0")]
impl FusedIterator for EscapeDefault {}
#[stable(feature = "ascii_escape_display", since = "1.39.0")]
impl fmt::Display for EscapeDefault {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- // SAFETY: ok because `escape_default` created only valid utf-8 data
- f.write_str(unsafe {
- from_utf8_unchecked(&self.data[(self.range.start as usize)..(self.range.end as usize)])
- })
+ f.write_str(self.0.as_str())
}
}
diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs
new file mode 100644
index 000000000..f093a0990
--- /dev/null
+++ b/library/core/src/ascii/ascii_char.rs
@@ -0,0 +1,565 @@
+//! This uses the name `AsciiChar`, even though it's not exposed that way right now,
+//! because it avoids a whole bunch of "are you sure you didn't mean `char`?"
+//! suggestions from rustc if you get anything slightly wrong in here, and overall
+//! helps with clarity as we're also referring to `char` intentionally in here.
+
+use crate::fmt;
+use crate::mem::transmute;
+
+/// One of the 128 Unicode characters from U+0000 through U+007F,
+/// often known as the [ASCII] subset.
+///
+/// Officially, this is the first [block] in Unicode, _Basic Latin_.
+/// For details, see the [*C0 Controls and Basic Latin*][chart] code chart.
+///
+/// This block was based on older 7-bit character code standards such as
+/// ANSI X3.4-1977, ISO 646-1973, and [NIST FIPS 1-2].
+///
+/// # When to use this
+///
+/// The main advantage of this subset is that it's always valid UTF-8. As such,
+/// the `&[ascii::Char]` -> `&str` conversion function (as well as other related
+/// ones) are O(1): *no* runtime checks are needed.
+///
+/// If you're consuming strings, you should usually handle Unicode and thus
+/// accept `str`s, not limit yourself to `ascii::Char`s.
+///
+/// However, certain formats are intentionally designed to produce ASCII-only
+/// output in order to be 8-bit-clean. In those cases, it can be simpler and
+/// faster to generate `ascii::Char`s instead of dealing with the variable width
+/// properties of general UTF-8 encoded strings, while still allowing the result
+/// to be used freely with other Rust things that deal in general `str`s.
+///
+/// For example, a UUID library might offer a way to produce the string
+/// representation of a UUID as an `[ascii::Char; 36]` to avoid memory
+/// allocation yet still allow it to be used as UTF-8 via `as_str` without
+/// paying for validation (or needing `unsafe` code) the way it would if it
+/// were provided as a `[u8; 36]`.
+///
+/// # Layout
+///
+/// This type is guaranteed to have a size and alignment of 1 byte.
+///
+/// # Names
+///
+/// The variants on this type are [Unicode names][NamesList] of the characters
+/// in upper camel case, with a few tweaks:
+/// - For `<control>` characters, the primary alias name is used.
+/// - `LATIN` is dropped, as this block has no non-latin letters.
+/// - `LETTER` is dropped, as `CAPITAL`/`SMALL` suffices in this block.
+/// - `DIGIT`s use a single digit rather than writing out `ZERO`, `ONE`, etc.
+///
+/// [ASCII]: https://www.unicode.org/glossary/index.html#ASCII
+/// [block]: https://www.unicode.org/glossary/index.html#block
+/// [chart]: https://www.unicode.org/charts/PDF/U0000.pdf
+/// [NIST FIPS 1-2]: https://nvlpubs.nist.gov/nistpubs/Legacy/FIPS/fipspub1-2-1977.pdf
+/// [NamesList]: https://www.unicode.org/Public/15.0.0/ucd/NamesList.txt
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+#[unstable(feature = "ascii_char", issue = "110998")]
+#[repr(u8)]
+pub enum AsciiChar {
+ /// U+0000
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Null = 0,
+ /// U+0001
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ StartOfHeading = 1,
+ /// U+0002
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ StartOfText = 2,
+ /// U+0003
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ EndOfText = 3,
+ /// U+0004
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ EndOfTransmission = 4,
+ /// U+0005
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Enquiry = 5,
+ /// U+0006
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Acknowledge = 6,
+ /// U+0007
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Bell = 7,
+ /// U+0008
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Backspace = 8,
+ /// U+0009
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CharacterTabulation = 9,
+ /// U+000A
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ LineFeed = 10,
+ /// U+000B
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ LineTabulation = 11,
+ /// U+000C
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ FormFeed = 12,
+ /// U+000D
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CarriageReturn = 13,
+ /// U+000E
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ ShiftOut = 14,
+ /// U+000F
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ ShiftIn = 15,
+ /// U+0010
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ DataLinkEscape = 16,
+ /// U+0011
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ DeviceControlOne = 17,
+ /// U+0012
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ DeviceControlTwo = 18,
+ /// U+0013
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ DeviceControlThree = 19,
+ /// U+0014
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ DeviceControlFour = 20,
+ /// U+0015
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ NegativeAcknowledge = 21,
+ /// U+0016
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SynchronousIdle = 22,
+ /// U+0017
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ EndOfTransmissionBlock = 23,
+ /// U+0018
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Cancel = 24,
+ /// U+0019
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ EndOfMedium = 25,
+ /// U+001A
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Substitute = 26,
+ /// U+001B
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Escape = 27,
+ /// U+001C
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ InformationSeparatorFour = 28,
+ /// U+001D
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ InformationSeparatorThree = 29,
+ /// U+001E
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ InformationSeparatorTwo = 30,
+ /// U+001F
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ InformationSeparatorOne = 31,
+ /// U+0020
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Space = 32,
+ /// U+0021
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ ExclamationMark = 33,
+ /// U+0022
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ QuotationMark = 34,
+ /// U+0023
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ NumberSign = 35,
+ /// U+0024
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ DollarSign = 36,
+ /// U+0025
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ PercentSign = 37,
+ /// U+0026
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Ampersand = 38,
+ /// U+0027
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Apostrophe = 39,
+ /// U+0028
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ LeftParenthesis = 40,
+ /// U+0029
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ RightParenthesis = 41,
+ /// U+002A
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Asterisk = 42,
+ /// U+002B
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ PlusSign = 43,
+ /// U+002C
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Comma = 44,
+ /// U+002D
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ HyphenMinus = 45,
+ /// U+002E
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ FullStop = 46,
+ /// U+002F
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Solidus = 47,
+ /// U+0030
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Digit0 = 48,
+ /// U+0031
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Digit1 = 49,
+ /// U+0032
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Digit2 = 50,
+ /// U+0033
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Digit3 = 51,
+ /// U+0034
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Digit4 = 52,
+ /// U+0035
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Digit5 = 53,
+ /// U+0036
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Digit6 = 54,
+ /// U+0037
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Digit7 = 55,
+ /// U+0038
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Digit8 = 56,
+ /// U+0039
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Digit9 = 57,
+ /// U+003A
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Colon = 58,
+ /// U+003B
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Semicolon = 59,
+ /// U+003C
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ LessThanSign = 60,
+ /// U+003D
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ EqualsSign = 61,
+ /// U+003E
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ GreaterThanSign = 62,
+ /// U+003F
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ QuestionMark = 63,
+ /// U+0040
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CommercialAt = 64,
+ /// U+0041
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalA = 65,
+ /// U+0042
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalB = 66,
+ /// U+0043
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalC = 67,
+ /// U+0044
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalD = 68,
+ /// U+0045
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalE = 69,
+ /// U+0046
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalF = 70,
+ /// U+0047
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalG = 71,
+ /// U+0048
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalH = 72,
+ /// U+0049
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalI = 73,
+ /// U+004A
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalJ = 74,
+ /// U+004B
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalK = 75,
+ /// U+004C
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalL = 76,
+ /// U+004D
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalM = 77,
+ /// U+004E
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalN = 78,
+ /// U+004F
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalO = 79,
+ /// U+0050
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalP = 80,
+ /// U+0051
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalQ = 81,
+ /// U+0052
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalR = 82,
+ /// U+0053
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalS = 83,
+ /// U+0054
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalT = 84,
+ /// U+0055
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalU = 85,
+ /// U+0056
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalV = 86,
+ /// U+0057
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalW = 87,
+ /// U+0058
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalX = 88,
+ /// U+0059
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalY = 89,
+ /// U+005A
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CapitalZ = 90,
+ /// U+005B
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ LeftSquareBracket = 91,
+ /// U+005C
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ ReverseSolidus = 92,
+ /// U+005D
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ RightSquareBracket = 93,
+ /// U+005E
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ CircumflexAccent = 94,
+ /// U+005F
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ LowLine = 95,
+ /// U+0060
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ GraveAccent = 96,
+ /// U+0061
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallA = 97,
+ /// U+0062
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallB = 98,
+ /// U+0063
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallC = 99,
+ /// U+0064
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallD = 100,
+ /// U+0065
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallE = 101,
+ /// U+0066
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallF = 102,
+ /// U+0067
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallG = 103,
+ /// U+0068
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallH = 104,
+ /// U+0069
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallI = 105,
+ /// U+006A
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallJ = 106,
+ /// U+006B
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallK = 107,
+ /// U+006C
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallL = 108,
+ /// U+006D
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallM = 109,
+ /// U+006E
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallN = 110,
+ /// U+006F
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallO = 111,
+ /// U+0070
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallP = 112,
+ /// U+0071
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallQ = 113,
+ /// U+0072
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallR = 114,
+ /// U+0073
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallS = 115,
+ /// U+0074
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallT = 116,
+ /// U+0075
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallU = 117,
+ /// U+0076
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallV = 118,
+ /// U+0077
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallW = 119,
+ /// U+0078
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallX = 120,
+ /// U+0079
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallY = 121,
+ /// U+007A
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ SmallZ = 122,
+ /// U+007B
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ LeftCurlyBracket = 123,
+ /// U+007C
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ VerticalLine = 124,
+ /// U+007D
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ RightCurlyBracket = 125,
+ /// U+007E
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Tilde = 126,
+ /// U+007F
+ #[unstable(feature = "ascii_char_variants", issue = "110998")]
+ Delete = 127,
+}
+
+impl AsciiChar {
+ /// Creates an ascii character from the byte `b`,
+ /// or returns `None` if it's too large.
+ #[unstable(feature = "ascii_char", issue = "110998")]
+ #[inline]
+ pub const fn from_u8(b: u8) -> Option<Self> {
+ if b <= 127 {
+ // SAFETY: Just checked that `b` is in-range
+ Some(unsafe { Self::from_u8_unchecked(b) })
+ } else {
+ None
+ }
+ }
+
+ /// Creates an ASCII character from the byte `b`,
+ /// without checking whether it's valid.
+ ///
+ /// # Safety
+ ///
+ /// `b` must be in `0..=127`, or else this is UB.
+ #[unstable(feature = "ascii_char", issue = "110998")]
+ #[inline]
+ pub const unsafe fn from_u8_unchecked(b: u8) -> Self {
+ // SAFETY: Our safety precondition is that `b` is in-range.
+ unsafe { transmute(b) }
+ }
+
+ /// When passed the *number* `0`, `1`, …, `9`, returns the *character*
+ /// `'0'`, `'1'`, …, `'9'` respectively.
+ ///
+ /// If `d >= 10`, returns `None`.
+ #[unstable(feature = "ascii_char", issue = "110998")]
+ #[inline]
+ pub const fn digit(d: u8) -> Option<Self> {
+ if d < 10 {
+ // SAFETY: Just checked it's in-range.
+ Some(unsafe { Self::digit_unchecked(d) })
+ } else {
+ None
+ }
+ }
+
+ /// When passed the *number* `0`, `1`, …, `9`, returns the *character*
+ /// `'0'`, `'1'`, …, `'9'` respectively, without checking that it's in-range.
+ ///
+ /// # Safety
+ ///
+ /// This is immediate UB if called with `d > 64`.
+ ///
+ /// If `d >= 10` and `d <= 64`, this is allowed to return any value or panic.
+ /// Notably, it should not be expected to return hex digits, or any other
+ /// reasonable extension of the decimal digits.
+ ///
+ /// (This lose safety condition is intended to simplify soundness proofs
+ /// when writing code using this method, since the implementation doesn't
+ /// need something really specific, not to make those other arguments do
+ /// something useful. It might be tightened before stabilization.)
+ #[unstable(feature = "ascii_char", issue = "110998")]
+ #[inline]
+ pub const unsafe fn digit_unchecked(d: u8) -> Self {
+ debug_assert!(d < 10);
+
+ // SAFETY: `'0'` through `'9'` are U+00030 through U+0039,
+ // so because `d` must be 64 or less the addition can return at most
+ // 112 (0x70), which doesn't overflow and is within the ASCII range.
+ unsafe {
+ let byte = b'0'.unchecked_add(d);
+ Self::from_u8_unchecked(byte)
+ }
+ }
+
+ /// Gets this ASCII character as a byte.
+ #[unstable(feature = "ascii_char", issue = "110998")]
+ #[inline]
+ pub const fn as_u8(self) -> u8 {
+ self as u8
+ }
+
+ /// Gets this ASCII character as a `char` Unicode Scalar Value.
+ #[unstable(feature = "ascii_char", issue = "110998")]
+ #[inline]
+ pub const fn as_char(self) -> char {
+ self as u8 as char
+ }
+
+ /// Views this ASCII character as a one-code-unit UTF-8 `str`.
+ #[unstable(feature = "ascii_char", issue = "110998")]
+ #[inline]
+ pub const fn as_str(&self) -> &str {
+ crate::slice::from_ref(self).as_str()
+ }
+}
+
+impl [AsciiChar] {
+ /// Views this slice of ASCII characters as a UTF-8 `str`.
+ #[unstable(feature = "ascii_char", issue = "110998")]
+ #[inline]
+ pub const fn as_str(&self) -> &str {
+ let ascii_ptr: *const Self = self;
+ let str_ptr = ascii_ptr as *const str;
+ // SAFETY: Each ASCII codepoint in UTF-8 is encoded as one single-byte
+ // code unit having the same value as the ASCII byte.
+ unsafe { &*str_ptr }
+ }
+
+ /// Views this slice of ASCII characters as a slice of `u8` bytes.
+ #[unstable(feature = "ascii_char", issue = "110998")]
+ #[inline]
+ pub const fn as_bytes(&self) -> &[u8] {
+ self.as_str().as_bytes()
+ }
+}
+
+#[unstable(feature = "ascii_char", issue = "110998")]
+impl fmt::Display for AsciiChar {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ <str as fmt::Display>::fmt(self.as_str(), f)
+ }
+}
diff --git a/library/core/src/bool.rs b/library/core/src/bool.rs
index db1c505ba..03cdff9b1 100644
--- a/library/core/src/bool.rs
+++ b/library/core/src/bool.rs
@@ -1,7 +1,5 @@
//! impl bool {}
-use crate::marker::Destruct;
-
impl bool {
/// Returns `Some(t)` if the `bool` is [`true`](../std/keyword.true.html),
/// or `None` otherwise.
@@ -31,12 +29,8 @@ impl bool {
/// assert_eq!(a, 2);
/// ```
#[stable(feature = "bool_to_option", since = "1.62.0")]
- #[rustc_const_unstable(feature = "const_bool_to_option", issue = "91917")]
#[inline]
- pub const fn then_some<T>(self, t: T) -> Option<T>
- where
- T: ~const Destruct,
- {
+ pub fn then_some<T>(self, t: T) -> Option<T> {
if self { Some(t) } else { None }
}
@@ -61,13 +55,8 @@ impl bool {
/// assert_eq!(a, 1);
/// ```
#[stable(feature = "lazy_bool_to_option", since = "1.50.0")]
- #[rustc_const_unstable(feature = "const_bool_to_option", issue = "91917")]
#[inline]
- pub const fn then<T, F>(self, f: F) -> Option<T>
- where
- F: ~const FnOnce() -> T,
- F: ~const Destruct,
- {
+ pub fn then<T, F: FnOnce() -> T>(self, f: F) -> Option<T> {
if self { Some(f()) } else { None }
}
}
diff --git a/library/core/src/borrow.rs b/library/core/src/borrow.rs
index 4a8302ee4..efc9ada38 100644
--- a/library/core/src/borrow.rs
+++ b/library/core/src/borrow.rs
@@ -154,7 +154,6 @@
/// [`String`]: ../../std/string/struct.String.html
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "Borrow"]
-#[const_trait]
pub trait Borrow<Borrowed: ?Sized> {
/// Immutably borrows from an owned value.
///
@@ -185,7 +184,6 @@ pub trait Borrow<Borrowed: ?Sized> {
/// an underlying type by providing a mutable reference. See [`Borrow<T>`]
/// for more information on borrowing as another type.
#[stable(feature = "rust1", since = "1.0.0")]
-#[const_trait]
pub trait BorrowMut<Borrowed: ?Sized>: Borrow<Borrowed> {
/// Mutably borrows from an owned value.
///
@@ -207,8 +205,7 @@ pub trait BorrowMut<Borrowed: ?Sized>: Borrow<Borrowed> {
}
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_borrow", issue = "91522")]
-impl<T: ?Sized> const Borrow<T> for T {
+impl<T: ?Sized> Borrow<T> for T {
#[rustc_diagnostic_item = "noop_method_borrow"]
fn borrow(&self) -> &T {
self
@@ -216,32 +213,28 @@ impl<T: ?Sized> const Borrow<T> for T {
}
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_borrow", issue = "91522")]
-impl<T: ?Sized> const BorrowMut<T> for T {
+impl<T: ?Sized> BorrowMut<T> for T {
fn borrow_mut(&mut self) -> &mut T {
self
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_borrow", issue = "91522")]
-impl<T: ?Sized> const Borrow<T> for &T {
+impl<T: ?Sized> Borrow<T> for &T {
fn borrow(&self) -> &T {
&**self
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_borrow", issue = "91522")]
-impl<T: ?Sized> const Borrow<T> for &mut T {
+impl<T: ?Sized> Borrow<T> for &mut T {
fn borrow(&self) -> &T {
&**self
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_borrow", issue = "91522")]
-impl<T: ?Sized> const BorrowMut<T> for &mut T {
+impl<T: ?Sized> BorrowMut<T> for &mut T {
fn borrow_mut(&mut self) -> &mut T {
&mut **self
}
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index 33d928e23..744767aae 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -115,7 +115,7 @@
//! let shared_map: Rc<RefCell<_>> = Rc::new(RefCell::new(HashMap::new()));
//! // Create a new block to limit the scope of the dynamic borrow
//! {
-//! let mut map: RefMut<_> = shared_map.borrow_mut();
+//! let mut map: RefMut<'_, _> = shared_map.borrow_mut();
//! map.insert("africa", 92388);
//! map.insert("kyoto", 11837);
//! map.insert("piccadilly", 11826);
@@ -370,8 +370,7 @@ impl<T: Ord + Copy> Ord for Cell<T> {
}
#[stable(feature = "cell_from", since = "1.12.0")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<T> const From<T> for Cell<T> {
+impl<T> From<T> for Cell<T> {
/// Creates a new `Cell<T>` containing the given value.
fn from(t: T) -> Cell<T> {
Cell::new(t)
@@ -1318,8 +1317,7 @@ impl<T: ?Sized + Ord> Ord for RefCell<T> {
}
#[stable(feature = "cell_from", since = "1.12.0")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<T> const From<T> for RefCell<T> {
+impl<T> From<T> for RefCell<T> {
/// Creates a new `RefCell<T>` containing the given value.
fn from(t: T) -> RefCell<T> {
RefCell::new(t)
@@ -1437,8 +1435,8 @@ impl<'b, T: ?Sized> Ref<'b, T> {
/// use std::cell::{RefCell, Ref};
///
/// let c = RefCell::new((5, 'b'));
- /// let b1: Ref<(u32, char)> = c.borrow();
- /// let b2: Ref<u32> = Ref::map(b1, |t| &t.0);
+ /// let b1: Ref<'_, (u32, char)> = c.borrow();
+ /// let b2: Ref<'_, u32> = Ref::map(b1, |t| &t.0);
/// assert_eq!(*b2, 5)
/// ```
#[stable(feature = "cell_map", since = "1.8.0")]
@@ -1466,8 +1464,8 @@ impl<'b, T: ?Sized> Ref<'b, T> {
/// use std::cell::{RefCell, Ref};
///
/// let c = RefCell::new(vec![1, 2, 3]);
- /// let b1: Ref<Vec<u32>> = c.borrow();
- /// let b2: Result<Ref<u32>, _> = Ref::filter_map(b1, |v| v.get(1));
+ /// let b1: Ref<'_, Vec<u32>> = c.borrow();
+ /// let b2: Result<Ref<'_, u32>, _> = Ref::filter_map(b1, |v| v.get(1));
/// assert_eq!(*b2.unwrap(), 2);
/// ```
#[stable(feature = "cell_filter_map", since = "1.63.0")]
@@ -1579,8 +1577,8 @@ impl<'b, T: ?Sized> RefMut<'b, T> {
///
/// let c = RefCell::new((5, 'b'));
/// {
- /// let b1: RefMut<(u32, char)> = c.borrow_mut();
- /// let mut b2: RefMut<u32> = RefMut::map(b1, |t| &mut t.0);
+ /// let b1: RefMut<'_, (u32, char)> = c.borrow_mut();
+ /// let mut b2: RefMut<'_, u32> = RefMut::map(b1, |t| &mut t.0);
/// assert_eq!(*b2, 5);
/// *b2 = 42;
/// }
@@ -1614,8 +1612,8 @@ impl<'b, T: ?Sized> RefMut<'b, T> {
/// let c = RefCell::new(vec![1, 2, 3]);
///
/// {
- /// let b1: RefMut<Vec<u32>> = c.borrow_mut();
- /// let mut b2: Result<RefMut<u32>, _> = RefMut::filter_map(b1, |v| v.get_mut(1));
+ /// let b1: RefMut<'_, Vec<u32>> = c.borrow_mut();
+ /// let mut b2: Result<RefMut<'_, u32>, _> = RefMut::filter_map(b1, |v| v.get_mut(1));
///
/// if let Ok(mut b2) = b2 {
/// *b2 += 2;
@@ -2032,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.
@@ -2102,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);
@@ -2126,8 +2147,7 @@ impl<T: Default> Default for UnsafeCell<T> {
}
#[stable(feature = "cell_from", since = "1.12.0")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<T> const From<T> for UnsafeCell<T> {
+impl<T> From<T> for UnsafeCell<T> {
/// Creates a new `UnsafeCell<T>` containing the given value.
fn from(t: T) -> UnsafeCell<T> {
UnsafeCell::new(t)
@@ -2226,8 +2246,7 @@ impl<T: Default> Default for SyncUnsafeCell<T> {
}
#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<T> const From<T> for SyncUnsafeCell<T> {
+impl<T> From<T> for SyncUnsafeCell<T> {
/// Creates a new `SyncUnsafeCell<T>` containing the given value.
fn from(t: T) -> SyncUnsafeCell<T> {
SyncUnsafeCell::new(t)
diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs
index 44adcfa1a..1b213f6a2 100644
--- a/library/core/src/cell/lazy.rs
+++ b/library/core/src/cell/lazy.rs
@@ -63,6 +63,34 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
LazyCell { state: UnsafeCell::new(State::Uninit(f)) }
}
+ /// Consumes this `LazyCell` returning the stored value.
+ ///
+ /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(lazy_cell)]
+ /// #![feature(lazy_cell_consume)]
+ ///
+ /// use std::cell::LazyCell;
+ ///
+ /// let hello = "Hello, World!".to_string();
+ ///
+ /// let lazy = LazyCell::new(|| hello.to_uppercase());
+ ///
+ /// assert_eq!(&*lazy, "HELLO, WORLD!");
+ /// assert_eq!(LazyCell::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string()));
+ /// ```
+ #[unstable(feature = "lazy_cell_consume", issue = "109736")]
+ pub fn into_inner(this: Self) -> Result<T, F> {
+ match this.state.into_inner() {
+ State::Init(data) => Ok(data),
+ State::Uninit(f) => Err(f),
+ State::Poisoned => panic!("LazyCell instance has previously been poisoned"),
+ }
+ }
+
/// Forces the evaluation of this lazy value and returns a reference to
/// the result.
///
diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs
index f7cd3ec5f..5f06a7b07 100644
--- a/library/core/src/cell/once.rs
+++ b/library/core/src/cell/once.rs
@@ -284,8 +284,7 @@ impl<T: PartialEq> PartialEq for OnceCell<T> {
impl<T: Eq> Eq for OnceCell<T> {}
#[stable(feature = "once_cell", since = "1.70.0")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<T> const From<T> for OnceCell<T> {
+impl<T> From<T> for OnceCell<T> {
/// Creates a new `OnceCell<T>` which already contains the given `value`.
#[inline]
fn from(value: T) -> Self {
diff --git a/library/core/src/char/convert.rs b/library/core/src/char/convert.rs
index 136bbcb8b..b84e4b35b 100644
--- a/library/core/src/char/convert.rs
+++ b/library/core/src/char/convert.rs
@@ -27,8 +27,7 @@ pub(super) const unsafe fn from_u32_unchecked(i: u32) -> char {
}
#[stable(feature = "char_convert", since = "1.13.0")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl const From<char> for u32 {
+impl From<char> for u32 {
/// Converts a [`char`] into a [`u32`].
///
/// # Examples
@@ -47,8 +46,7 @@ impl const From<char> for u32 {
}
#[stable(feature = "more_char_conversions", since = "1.51.0")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl const From<char> for u64 {
+impl From<char> for u64 {
/// Converts a [`char`] into a [`u64`].
///
/// # Examples
@@ -69,8 +67,7 @@ impl const From<char> for u64 {
}
#[stable(feature = "more_char_conversions", since = "1.51.0")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl const From<char> for u128 {
+impl From<char> for u128 {
/// Converts a [`char`] into a [`u128`].
///
/// # Examples
@@ -123,8 +120,7 @@ impl TryFrom<char> for u8 {
/// for a superset of Windows-1252 that fills the remaining blanks with corresponding
/// C0 and C1 control codes.
#[stable(feature = "char_convert", since = "1.13.0")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl const From<u8> for char {
+impl From<u8> for char {
/// Converts a [`u8`] into a [`char`].
///
/// # Examples
diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs
index 9bc97ea0b..515b8d20e 100644
--- a/library/core/src/char/methods.rs
+++ b/library/core/src/char/methods.rs
@@ -1,5 +1,6 @@
//! impl char {}
+use crate::ascii;
use crate::slice;
use crate::str::from_utf8_unchecked_mut;
use crate::unicode::printable::is_printable;
@@ -380,20 +381,7 @@ impl char {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn escape_unicode(self) -> EscapeUnicode {
- let c = self as u32;
-
- // or-ing 1 ensures that for c==0 the code computes that one
- // digit should be printed and (which is the same) avoids the
- // (31 - 32) underflow
- let msb = 31 - (c | 1).leading_zeros();
-
- // the index of the most significant hex digit
- let ms_hex_digit = msb / 4;
- EscapeUnicode {
- c: self,
- state: EscapeUnicodeState::Backslash,
- hex_digit_idx: ms_hex_digit as usize,
- }
+ EscapeUnicode::new(self)
}
/// An extended version of `escape_debug` that optionally permits escaping
@@ -403,21 +391,20 @@ impl char {
/// characters, and double quotes in strings.
#[inline]
pub(crate) fn escape_debug_ext(self, args: EscapeDebugExtArgs) -> EscapeDebug {
- let init_state = match self {
- '\0' => EscapeDefaultState::Backslash('0'),
- '\t' => EscapeDefaultState::Backslash('t'),
- '\r' => EscapeDefaultState::Backslash('r'),
- '\n' => EscapeDefaultState::Backslash('n'),
- '\\' => EscapeDefaultState::Backslash(self),
- '"' if args.escape_double_quote => EscapeDefaultState::Backslash(self),
- '\'' if args.escape_single_quote => EscapeDefaultState::Backslash(self),
+ match self {
+ '\0' => EscapeDebug::backslash(ascii::Char::Digit0),
+ '\t' => EscapeDebug::backslash(ascii::Char::SmallT),
+ '\r' => EscapeDebug::backslash(ascii::Char::SmallR),
+ '\n' => EscapeDebug::backslash(ascii::Char::SmallN),
+ '\\' => EscapeDebug::backslash(ascii::Char::ReverseSolidus),
+ '\"' if args.escape_double_quote => EscapeDebug::backslash(ascii::Char::QuotationMark),
+ '\'' if args.escape_single_quote => EscapeDebug::backslash(ascii::Char::Apostrophe),
_ if args.escape_grapheme_extended && self.is_grapheme_extended() => {
- EscapeDefaultState::Unicode(self.escape_unicode())
+ EscapeDebug::from_unicode(self.escape_unicode())
}
- _ if is_printable(self) => EscapeDefaultState::Char(self),
- _ => EscapeDefaultState::Unicode(self.escape_unicode()),
- };
- EscapeDebug(EscapeDefault { state: init_state })
+ _ if is_printable(self) => EscapeDebug::printable(self),
+ _ => EscapeDebug::from_unicode(self.escape_unicode()),
+ }
}
/// Returns an iterator that yields the literal escape code of a character
@@ -515,15 +502,14 @@ impl char {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn escape_default(self) -> EscapeDefault {
- let init_state = match self {
- '\t' => EscapeDefaultState::Backslash('t'),
- '\r' => EscapeDefaultState::Backslash('r'),
- '\n' => EscapeDefaultState::Backslash('n'),
- '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self),
- '\x20'..='\x7e' => EscapeDefaultState::Char(self),
- _ => EscapeDefaultState::Unicode(self.escape_unicode()),
- };
- EscapeDefault { state: init_state }
+ match self {
+ '\t' => EscapeDefault::backslash(ascii::Char::SmallT),
+ '\r' => EscapeDefault::backslash(ascii::Char::SmallR),
+ '\n' => EscapeDefault::backslash(ascii::Char::SmallN),
+ '\\' | '\'' | '"' => EscapeDefault::backslash(self.as_ascii().unwrap()),
+ '\x20'..='\x7e' => EscapeDefault::printable(self.as_ascii().unwrap()),
+ _ => EscapeDefault::from_unicode(self.escape_unicode()),
+ }
}
/// Returns the number of bytes this `char` would need if encoded in UTF-8.
@@ -1116,6 +1102,24 @@ impl char {
*self as u32 <= 0x7F
}
+ /// Returns `Some` if the value is within the ASCII range,
+ /// or `None` if it's not.
+ ///
+ /// This is preferred to [`Self::is_ascii`] when you're passing the value
+ /// along to something else that can take [`ascii::Char`] rather than
+ /// needing to check again for itself whether the value is in ASCII.
+ #[must_use]
+ #[unstable(feature = "ascii_char", issue = "110998")]
+ #[inline]
+ pub const fn as_ascii(&self) -> Option<ascii::Char> {
+ if self.is_ascii() {
+ // SAFETY: Just checked that this is ASCII.
+ Some(unsafe { ascii::Char::from_u8_unchecked(*self as u8) })
+ } else {
+ None
+ }
+ }
+
/// Makes a copy of the value in its ASCII upper case equivalent.
///
/// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs
index 8ec78e887..5c4291287 100644
--- a/library/core/src/char/mod.rs
+++ b/library/core/src/char/mod.rs
@@ -38,9 +38,12 @@ pub use self::methods::encode_utf16_raw;
#[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")]
pub use self::methods::encode_utf8_raw;
+use crate::ascii;
use crate::error::Error;
+use crate::escape;
use crate::fmt::{self, Write};
use crate::iter::FusedIterator;
+use crate::num::NonZeroUsize;
pub(crate) use self::methods::EscapeDebugExtArgs;
@@ -146,86 +149,44 @@ pub const fn from_digit(num: u32, radix: u32) -> Option<char> {
/// [`escape_unicode`]: char::escape_unicode
#[derive(Clone, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct EscapeUnicode {
- c: char,
- state: EscapeUnicodeState,
-
- // The index of the next hex digit to be printed (0 if none),
- // i.e., the number of remaining hex digits to be printed;
- // increasing from the least significant digit: 0x543210
- hex_digit_idx: usize,
-}
+pub struct EscapeUnicode(escape::EscapeIterInner<10>);
-// The enum values are ordered so that their representation is the
-// same as the remaining length (besides the hexadecimal digits). This
-// likely makes `len()` a single load from memory) and inline-worth.
-#[derive(Clone, Debug)]
-enum EscapeUnicodeState {
- Done,
- RightBrace,
- Value,
- LeftBrace,
- Type,
- Backslash,
+impl EscapeUnicode {
+ fn new(chr: char) -> Self {
+ let mut data = [ascii::Char::Null; 10];
+ let range = escape::escape_unicode_into(&mut data, chr);
+ Self(escape::EscapeIterInner::new(data, range))
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Iterator for EscapeUnicode {
type Item = char;
+ #[inline]
fn next(&mut self) -> Option<char> {
- match self.state {
- EscapeUnicodeState::Backslash => {
- self.state = EscapeUnicodeState::Type;
- Some('\\')
- }
- EscapeUnicodeState::Type => {
- self.state = EscapeUnicodeState::LeftBrace;
- Some('u')
- }
- EscapeUnicodeState::LeftBrace => {
- self.state = EscapeUnicodeState::Value;
- Some('{')
- }
- EscapeUnicodeState::Value => {
- let hex_digit = ((self.c as u32) >> (self.hex_digit_idx * 4)) & 0xf;
- let c = char::from_digit(hex_digit, 16).unwrap();
- if self.hex_digit_idx == 0 {
- self.state = EscapeUnicodeState::RightBrace;
- } else {
- self.hex_digit_idx -= 1;
- }
- Some(c)
- }
- EscapeUnicodeState::RightBrace => {
- self.state = EscapeUnicodeState::Done;
- Some('}')
- }
- EscapeUnicodeState::Done => None,
- }
+ self.0.next().map(char::from)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
- let n = self.len();
+ let n = self.0.len();
(n, Some(n))
}
#[inline]
fn count(self) -> usize {
- self.len()
+ self.0.len()
}
- fn last(self) -> Option<char> {
- match self.state {
- EscapeUnicodeState::Done => None,
+ #[inline]
+ fn last(mut self) -> Option<char> {
+ self.0.next_back().map(char::from)
+ }
- EscapeUnicodeState::RightBrace
- | EscapeUnicodeState::Value
- | EscapeUnicodeState::LeftBrace
- | EscapeUnicodeState::Type
- | EscapeUnicodeState::Backslash => Some('}'),
- }
+ #[inline]
+ fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+ self.0.advance_by(n)
}
}
@@ -233,16 +194,7 @@ impl Iterator for EscapeUnicode {
impl ExactSizeIterator for EscapeUnicode {
#[inline]
fn len(&self) -> usize {
- // The match is a single memory access with no branching
- self.hex_digit_idx
- + match self.state {
- EscapeUnicodeState::Done => 0,
- EscapeUnicodeState::RightBrace => 1,
- EscapeUnicodeState::Value => 2,
- EscapeUnicodeState::LeftBrace => 3,
- EscapeUnicodeState::Type => 4,
- EscapeUnicodeState::Backslash => 5,
- }
+ self.0.len()
}
}
@@ -252,10 +204,7 @@ impl FusedIterator for EscapeUnicode {}
#[stable(feature = "char_struct_display", since = "1.16.0")]
impl fmt::Display for EscapeUnicode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- for c in self.clone() {
- f.write_char(c)?;
- }
- Ok(())
+ f.write_str(self.0.as_str())
}
}
@@ -267,90 +216,60 @@ impl fmt::Display for EscapeUnicode {
/// [`escape_default`]: char::escape_default
#[derive(Clone, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct EscapeDefault {
- state: EscapeDefaultState,
-}
+pub struct EscapeDefault(escape::EscapeIterInner<10>);
-#[derive(Clone, Debug)]
-enum EscapeDefaultState {
- Done,
- Char(char),
- Backslash(char),
- Unicode(EscapeUnicode),
+impl EscapeDefault {
+ fn printable(chr: ascii::Char) -> Self {
+ let data = [chr];
+ Self(escape::EscapeIterInner::from_array(data))
+ }
+
+ fn backslash(chr: ascii::Char) -> Self {
+ let data = [ascii::Char::ReverseSolidus, chr];
+ Self(escape::EscapeIterInner::from_array(data))
+ }
+
+ fn from_unicode(esc: EscapeUnicode) -> Self {
+ Self(esc.0)
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Iterator for EscapeDefault {
type Item = char;
+ #[inline]
fn next(&mut self) -> Option<char> {
- match self.state {
- EscapeDefaultState::Backslash(c) => {
- self.state = EscapeDefaultState::Char(c);
- Some('\\')
- }
- EscapeDefaultState::Char(c) => {
- self.state = EscapeDefaultState::Done;
- Some(c)
- }
- EscapeDefaultState::Done => None,
- EscapeDefaultState::Unicode(ref mut iter) => iter.next(),
- }
+ self.0.next().map(char::from)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
- let n = self.len();
+ let n = self.0.len();
(n, Some(n))
}
#[inline]
fn count(self) -> usize {
- self.len()
+ self.0.len()
}
- fn nth(&mut self, n: usize) -> Option<char> {
- match self.state {
- EscapeDefaultState::Backslash(c) if n == 0 => {
- self.state = EscapeDefaultState::Char(c);
- Some('\\')
- }
- EscapeDefaultState::Backslash(c) if n == 1 => {
- self.state = EscapeDefaultState::Done;
- Some(c)
- }
- EscapeDefaultState::Backslash(_) => {
- self.state = EscapeDefaultState::Done;
- None
- }
- EscapeDefaultState::Char(c) => {
- self.state = EscapeDefaultState::Done;
-
- if n == 0 { Some(c) } else { None }
- }
- EscapeDefaultState::Done => None,
- EscapeDefaultState::Unicode(ref mut i) => i.nth(n),
- }
+ #[inline]
+ fn last(mut self) -> Option<char> {
+ self.0.next_back().map(char::from)
}
- fn last(self) -> Option<char> {
- match self.state {
- EscapeDefaultState::Unicode(iter) => iter.last(),
- EscapeDefaultState::Done => None,
- EscapeDefaultState::Backslash(c) | EscapeDefaultState::Char(c) => Some(c),
- }
+ #[inline]
+ fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+ self.0.advance_by(n)
}
}
#[stable(feature = "exact_size_escape", since = "1.11.0")]
impl ExactSizeIterator for EscapeDefault {
+ #[inline]
fn len(&self) -> usize {
- match self.state {
- EscapeDefaultState::Done => 0,
- EscapeDefaultState::Char(_) => 1,
- EscapeDefaultState::Backslash(_) => 2,
- EscapeDefaultState::Unicode(ref iter) => iter.len(),
- }
+ self.0.len()
}
}
@@ -360,10 +279,7 @@ impl FusedIterator for EscapeDefault {}
#[stable(feature = "char_struct_display", since = "1.16.0")]
impl fmt::Display for EscapeDefault {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- for c in self.clone() {
- f.write_char(c)?;
- }
- Ok(())
+ f.write_str(self.0.as_str())
}
}
@@ -375,21 +291,74 @@ impl fmt::Display for EscapeDefault {
/// [`escape_debug`]: char::escape_debug
#[stable(feature = "char_escape_debug", since = "1.20.0")]
#[derive(Clone, Debug)]
-pub struct EscapeDebug(EscapeDefault);
+pub struct EscapeDebug(EscapeDebugInner);
+
+#[derive(Clone, Debug)]
+// Note: It’s possible to manually encode the EscapeDebugInner inside of
+// EscapeIterInner (e.g. with alive=254..255 indicating that data[0..4] holds
+// a char) which would likely result in a more optimised code. For now we use
+// the option easier to implement.
+enum EscapeDebugInner {
+ Bytes(escape::EscapeIterInner<10>),
+ Char(char),
+}
+
+impl EscapeDebug {
+ fn printable(chr: char) -> Self {
+ Self(EscapeDebugInner::Char(chr))
+ }
+
+ fn backslash(chr: ascii::Char) -> Self {
+ let data = [ascii::Char::ReverseSolidus, chr];
+ let iter = escape::EscapeIterInner::from_array(data);
+ Self(EscapeDebugInner::Bytes(iter))
+ }
+
+ fn from_unicode(esc: EscapeUnicode) -> Self {
+ Self(EscapeDebugInner::Bytes(esc.0))
+ }
+
+ fn clear(&mut self) {
+ let bytes = escape::EscapeIterInner::from_array([]);
+ self.0 = EscapeDebugInner::Bytes(bytes);
+ }
+}
#[stable(feature = "char_escape_debug", since = "1.20.0")]
impl Iterator for EscapeDebug {
type Item = char;
+
+ #[inline]
fn next(&mut self) -> Option<char> {
- self.0.next()
+ match self.0 {
+ EscapeDebugInner::Bytes(ref mut bytes) => bytes.next().map(char::from),
+ EscapeDebugInner::Char(chr) => {
+ self.clear();
+ Some(chr)
+ }
+ }
}
+
fn size_hint(&self) -> (usize, Option<usize>) {
- self.0.size_hint()
+ let n = self.len();
+ (n, Some(n))
+ }
+
+ #[inline]
+ fn count(self) -> usize {
+ self.len()
}
}
#[stable(feature = "char_escape_debug", since = "1.20.0")]
-impl ExactSizeIterator for EscapeDebug {}
+impl ExactSizeIterator for EscapeDebug {
+ fn len(&self) -> usize {
+ match &self.0 {
+ EscapeDebugInner::Bytes(bytes) => bytes.len(),
+ EscapeDebugInner::Char(_) => 1,
+ }
+ }
+}
#[stable(feature = "fused", since = "1.26.0")]
impl FusedIterator for EscapeDebug {}
@@ -397,7 +366,10 @@ impl FusedIterator for EscapeDebug {}
#[stable(feature = "char_escape_debug", since = "1.20.0")]
impl fmt::Display for EscapeDebug {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Display::fmt(&self.0, f)
+ match &self.0 {
+ EscapeDebugInner::Bytes(bytes) => f.write_str(bytes.as_str()),
+ EscapeDebugInner::Char(chr) => f.write_char(*chr),
+ }
}
}
diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs
index 398437d9a..a6d6230d3 100644
--- a/library/core/src/clone.rs
+++ b/library/core/src/clone.rs
@@ -36,8 +36,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
-use crate::marker::Destruct;
-
/// A common trait for the ability to explicitly duplicate an object.
///
/// Differs from [`Copy`] in that [`Copy`] is implicit and an inexpensive bit-wise copy, while
@@ -106,7 +104,6 @@ use crate::marker::Destruct;
#[lang = "clone"]
#[rustc_diagnostic_item = "Clone"]
#[rustc_trivial_field_reads]
-#[const_trait]
pub trait Clone: Sized {
/// Returns a copy of the value.
///
@@ -129,10 +126,7 @@ pub trait Clone: Sized {
/// allocations.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- fn clone_from(&mut self, source: &Self)
- where
- Self: ~const Destruct,
- {
+ fn clone_from(&mut self, source: &Self) {
*self = source.clone()
}
}
@@ -182,8 +176,7 @@ mod impls {
($($t:ty)*) => {
$(
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_clone", issue = "91805")]
- impl const Clone for $t {
+ impl Clone for $t {
#[inline(always)]
fn clone(&self) -> Self {
*self
@@ -201,8 +194,7 @@ mod impls {
}
#[unstable(feature = "never_type", issue = "35121")]
- #[rustc_const_unstable(feature = "const_clone", issue = "91805")]
- impl const Clone for ! {
+ impl Clone for ! {
#[inline]
fn clone(&self) -> Self {
*self
@@ -210,8 +202,7 @@ mod impls {
}
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_clone", issue = "91805")]
- impl<T: ?Sized> const Clone for *const T {
+ impl<T: ?Sized> Clone for *const T {
#[inline(always)]
fn clone(&self) -> Self {
*self
@@ -219,8 +210,7 @@ mod impls {
}
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_clone", issue = "91805")]
- impl<T: ?Sized> const Clone for *mut T {
+ impl<T: ?Sized> Clone for *mut T {
#[inline(always)]
fn clone(&self) -> Self {
*self
@@ -229,8 +219,7 @@ mod impls {
/// Shared references can be cloned, but mutable references *cannot*!
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_clone", issue = "91805")]
- impl<T: ?Sized> const Clone for &T {
+ impl<T: ?Sized> Clone for &T {
#[inline(always)]
#[rustc_diagnostic_item = "noop_method_clone"]
fn clone(&self) -> Self {
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index 55331475a..faf48ae57 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -25,8 +25,6 @@
mod bytewise;
pub(crate) use bytewise::BytewiseEq;
-use crate::marker::Destruct;
-
use self::Ordering::*;
/// Trait for equality comparisons.
@@ -212,7 +210,6 @@ use self::Ordering::*;
label = "no implementation for `{Self} == {Rhs}`",
append_const_msg
)]
-#[const_trait]
#[rustc_diagnostic_item = "PartialEq"]
pub trait PartialEq<Rhs: ?Sized = Self> {
/// This method tests for `self` and `other` values to be equal, and is used
@@ -324,17 +321,13 @@ pub struct AssertParamIsEq<T: Eq + ?Sized> {
/// ```
/// use std::cmp::Ordering;
///
-/// let result = 1.cmp(&2);
-/// assert_eq!(Ordering::Less, result);
+/// assert_eq!(1.cmp(&2), Ordering::Less);
///
-/// let result = 1.cmp(&1);
-/// assert_eq!(Ordering::Equal, result);
+/// assert_eq!(1.cmp(&1), Ordering::Equal);
///
-/// let result = 2.cmp(&1);
-/// assert_eq!(Ordering::Greater, result);
+/// assert_eq!(2.cmp(&1), Ordering::Greater);
/// ```
-#[derive(Clone, Copy, Eq, Debug, Hash)]
-#[derive_const(PartialOrd, Ord, PartialEq)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
#[stable(feature = "rust1", since = "1.0.0")]
#[repr(i8)]
pub enum Ordering {
@@ -604,8 +597,7 @@ impl Ordering {
pub struct Reverse<T>(#[stable(feature = "reverse_cmp_key", since = "1.19.0")] pub T);
#[stable(feature = "reverse_cmp_key", since = "1.19.0")]
-#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
-impl<T: ~const PartialOrd> const PartialOrd for Reverse<T> {
+impl<T: PartialOrd> PartialOrd for Reverse<T> {
#[inline]
fn partial_cmp(&self, other: &Reverse<T>) -> Option<Ordering> {
other.0.partial_cmp(&self.0)
@@ -763,7 +755,6 @@ impl<T: Clone> Clone for Reverse<T> {
#[doc(alias = ">=")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "Ord"]
-#[const_trait]
pub trait Ord: Eq + PartialOrd<Self> {
/// This method returns an [`Ordering`] between `self` and `other`.
///
@@ -790,8 +781,8 @@ pub trait Ord: Eq + PartialOrd<Self> {
/// # Examples
///
/// ```
- /// assert_eq!(2, 1.max(2));
- /// assert_eq!(2, 2.max(2));
+ /// assert_eq!(1.max(2), 2);
+ /// assert_eq!(2.max(2), 2);
/// ```
#[stable(feature = "ord_max_min", since = "1.21.0")]
#[inline]
@@ -799,7 +790,6 @@ pub trait Ord: Eq + PartialOrd<Self> {
fn max(self, other: Self) -> Self
where
Self: Sized,
- Self: ~const Destruct,
{
max_by(self, other, Ord::cmp)
}
@@ -811,8 +801,8 @@ pub trait Ord: Eq + PartialOrd<Self> {
/// # Examples
///
/// ```
- /// assert_eq!(1, 1.min(2));
- /// assert_eq!(2, 2.min(2));
+ /// assert_eq!(1.min(2), 1);
+ /// assert_eq!(2.min(2), 2);
/// ```
#[stable(feature = "ord_max_min", since = "1.21.0")]
#[inline]
@@ -820,7 +810,6 @@ pub trait Ord: Eq + PartialOrd<Self> {
fn min(self, other: Self) -> Self
where
Self: Sized,
- Self: ~const Destruct,
{
min_by(self, other, Ord::cmp)
}
@@ -837,17 +826,16 @@ pub trait Ord: Eq + PartialOrd<Self> {
/// # Examples
///
/// ```
- /// assert!((-3).clamp(-2, 1) == -2);
- /// assert!(0.clamp(-2, 1) == 0);
- /// assert!(2.clamp(-2, 1) == 1);
+ /// assert_eq!((-3).clamp(-2, 1), -2);
+ /// assert_eq!(0.clamp(-2, 1), 0);
+ /// assert_eq!(2.clamp(-2, 1), 1);
/// ```
#[must_use]
#[stable(feature = "clamp", since = "1.50.0")]
fn clamp(self, min: Self, max: Self) -> Self
where
Self: Sized,
- Self: ~const Destruct,
- Self: ~const PartialOrd,
+ Self: PartialOrd,
{
assert!(min <= max);
if self < min {
@@ -1035,7 +1023,6 @@ pub macro Ord($item:item) {
label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`",
append_const_msg
)]
-#[const_trait]
#[rustc_diagnostic_item = "PartialOrd"]
pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
/// This method returns an ordering between `self` and `other` values if one exists.
@@ -1070,11 +1057,9 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
/// # Examples
///
/// ```
- /// let result = 1.0 < 2.0;
- /// assert_eq!(result, true);
- ///
- /// let result = 2.0 < 1.0;
- /// assert_eq!(result, false);
+ /// assert_eq!(1.0 < 1.0, false);
+ /// assert_eq!(1.0 < 2.0, true);
+ /// assert_eq!(2.0 < 1.0, false);
/// ```
#[inline]
#[must_use]
@@ -1089,11 +1074,9 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
/// # Examples
///
/// ```
- /// let result = 1.0 <= 2.0;
- /// assert_eq!(result, true);
- ///
- /// let result = 2.0 <= 2.0;
- /// assert_eq!(result, true);
+ /// assert_eq!(1.0 <= 1.0, true);
+ /// assert_eq!(1.0 <= 2.0, true);
+ /// assert_eq!(2.0 <= 1.0, false);
/// ```
#[inline]
#[must_use]
@@ -1107,11 +1090,9 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
/// # Examples
///
/// ```
- /// let result = 1.0 > 2.0;
- /// assert_eq!(result, false);
- ///
- /// let result = 2.0 > 2.0;
- /// assert_eq!(result, false);
+ /// assert_eq!(1.0 > 1.0, false);
+ /// assert_eq!(1.0 > 2.0, false);
+ /// assert_eq!(2.0 > 1.0, true);
/// ```
#[inline]
#[must_use]
@@ -1126,11 +1107,9 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
/// # Examples
///
/// ```
- /// let result = 2.0 >= 1.0;
- /// assert_eq!(result, true);
- ///
- /// let result = 2.0 >= 2.0;
- /// assert_eq!(result, true);
+ /// assert_eq!(1.0 >= 1.0, true);
+ /// assert_eq!(1.0 >= 2.0, false);
+ /// assert_eq!(2.0 >= 1.0, true);
/// ```
#[inline]
#[must_use]
@@ -1160,15 +1139,14 @@ pub macro PartialOrd($item:item) {
/// ```
/// use std::cmp;
///
-/// assert_eq!(1, cmp::min(1, 2));
-/// assert_eq!(2, cmp::min(2, 2));
+/// assert_eq!(cmp::min(1, 2), 1);
+/// assert_eq!(cmp::min(2, 2), 2);
/// ```
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
#[cfg_attr(not(test), rustc_diagnostic_item = "cmp_min")]
-pub const fn min<T: ~const Ord + ~const Destruct>(v1: T, v2: T) -> T {
+pub fn min<T: Ord>(v1: T, v2: T) -> T {
v1.min(v2)
}
@@ -1181,18 +1159,16 @@ pub const fn min<T: ~const Ord + ~const Destruct>(v1: T, v2: T) -> T {
/// ```
/// use std::cmp;
///
-/// assert_eq!(cmp::min_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), 1);
-/// assert_eq!(cmp::min_by(-2, 2, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), -2);
+/// let result = cmp::min_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs()));
+/// assert_eq!(result, 1);
+///
+/// let result = cmp::min_by(-2, 3, |x: &i32, y: &i32| x.abs().cmp(&y.abs()));
+/// assert_eq!(result, -2);
/// ```
#[inline]
#[must_use]
#[stable(feature = "cmp_min_max_by", since = "1.53.0")]
-#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
-pub const fn min_by<T, F: ~const FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T
-where
- T: ~const Destruct,
- F: ~const Destruct,
-{
+pub fn min_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
match compare(&v1, &v2) {
Ordering::Less | Ordering::Equal => v1,
Ordering::Greater => v2,
@@ -1208,20 +1184,17 @@ where
/// ```
/// use std::cmp;
///
-/// assert_eq!(cmp::min_by_key(-2, 1, |x: &i32| x.abs()), 1);
-/// assert_eq!(cmp::min_by_key(-2, 2, |x: &i32| x.abs()), -2);
+/// let result = cmp::min_by_key(-2, 1, |x: &i32| x.abs());
+/// assert_eq!(result, 1);
+///
+/// let result = cmp::min_by_key(-2, 2, |x: &i32| x.abs());
+/// assert_eq!(result, -2);
/// ```
#[inline]
#[must_use]
#[stable(feature = "cmp_min_max_by", since = "1.53.0")]
-#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
-pub const fn min_by_key<T, F: ~const FnMut(&T) -> K, K: ~const Ord>(v1: T, v2: T, mut f: F) -> T
-where
- T: ~const Destruct,
- F: ~const Destruct,
- K: ~const Destruct,
-{
- min_by(v1, v2, const |v1, v2| f(v1).cmp(&f(v2)))
+pub fn min_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
+ min_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2)))
}
/// Compares and returns the maximum of two values.
@@ -1235,15 +1208,14 @@ where
/// ```
/// use std::cmp;
///
-/// assert_eq!(2, cmp::max(1, 2));
-/// assert_eq!(2, cmp::max(2, 2));
+/// assert_eq!(cmp::max(1, 2), 2);
+/// assert_eq!(cmp::max(2, 2), 2);
/// ```
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
#[cfg_attr(not(test), rustc_diagnostic_item = "cmp_max")]
-pub const fn max<T: ~const Ord + ~const Destruct>(v1: T, v2: T) -> T {
+pub fn max<T: Ord>(v1: T, v2: T) -> T {
v1.max(v2)
}
@@ -1256,18 +1228,16 @@ pub const fn max<T: ~const Ord + ~const Destruct>(v1: T, v2: T) -> T {
/// ```
/// use std::cmp;
///
-/// assert_eq!(cmp::max_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), -2);
-/// assert_eq!(cmp::max_by(-2, 2, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), 2);
+/// let result = cmp::max_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs()));
+/// assert_eq!(result, -2);
+///
+/// let result = cmp::max_by(-2, 2, |x: &i32, y: &i32| x.abs().cmp(&y.abs())) ;
+/// assert_eq!(result, 2);
/// ```
#[inline]
#[must_use]
#[stable(feature = "cmp_min_max_by", since = "1.53.0")]
-#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
-pub const fn max_by<T, F: ~const FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T
-where
- T: ~const Destruct,
- F: ~const Destruct,
-{
+pub fn max_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
match compare(&v1, &v2) {
Ordering::Less | Ordering::Equal => v2,
Ordering::Greater => v1,
@@ -1283,20 +1253,17 @@ where
/// ```
/// use std::cmp;
///
-/// assert_eq!(cmp::max_by_key(-2, 1, |x: &i32| x.abs()), -2);
-/// assert_eq!(cmp::max_by_key(-2, 2, |x: &i32| x.abs()), 2);
+/// let result = cmp::max_by_key(-2, 1, |x: &i32| x.abs());
+/// assert_eq!(result, -2);
+///
+/// let result = cmp::max_by_key(-2, 2, |x: &i32| x.abs());
+/// assert_eq!(result, 2);
/// ```
#[inline]
#[must_use]
#[stable(feature = "cmp_min_max_by", since = "1.53.0")]
-#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
-pub const fn max_by_key<T, F: ~const FnMut(&T) -> K, K: ~const Ord>(v1: T, v2: T, mut f: F) -> T
-where
- T: ~const Destruct,
- F: ~const Destruct,
- K: ~const Destruct,
-{
- max_by(v1, v2, const |v1, v2| f(v1).cmp(&f(v2)))
+pub fn max_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
+ max_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2)))
}
// Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types
@@ -1307,8 +1274,7 @@ mod impls {
macro_rules! partial_eq_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
- impl const PartialEq for $t {
+ impl PartialEq for $t {
#[inline]
fn eq(&self, other: &$t) -> bool { (*self) == (*other) }
#[inline]
@@ -1318,8 +1284,7 @@ mod impls {
}
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
- impl const PartialEq for () {
+ impl PartialEq for () {
#[inline]
fn eq(&self, _other: &()) -> bool {
true
@@ -1346,8 +1311,7 @@ mod impls {
macro_rules! partial_ord_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
- impl const PartialOrd for $t {
+ impl PartialOrd for $t {
#[inline]
fn partial_cmp(&self, other: &$t) -> Option<Ordering> {
match (*self <= *other, *self >= *other) {
@@ -1357,21 +1321,20 @@ mod impls {
(true, true) => Some(Equal),
}
}
- #[inline]
+ #[inline(always)]
fn lt(&self, other: &$t) -> bool { (*self) < (*other) }
- #[inline]
+ #[inline(always)]
fn le(&self, other: &$t) -> bool { (*self) <= (*other) }
- #[inline]
+ #[inline(always)]
fn ge(&self, other: &$t) -> bool { (*self) >= (*other) }
- #[inline]
+ #[inline(always)]
fn gt(&self, other: &$t) -> bool { (*self) > (*other) }
}
)*)
}
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
- impl const PartialOrd for () {
+ impl PartialOrd for () {
#[inline]
fn partial_cmp(&self, _: &()) -> Option<Ordering> {
Some(Equal)
@@ -1379,8 +1342,7 @@ mod impls {
}
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
- impl const PartialOrd for bool {
+ impl PartialOrd for bool {
#[inline]
fn partial_cmp(&self, other: &bool) -> Option<Ordering> {
Some(self.cmp(other))
@@ -1392,25 +1354,23 @@ mod impls {
macro_rules! ord_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
- impl const PartialOrd for $t {
+ impl PartialOrd for $t {
#[inline]
fn partial_cmp(&self, other: &$t) -> Option<Ordering> {
Some(self.cmp(other))
}
- #[inline]
+ #[inline(always)]
fn lt(&self, other: &$t) -> bool { (*self) < (*other) }
- #[inline]
+ #[inline(always)]
fn le(&self, other: &$t) -> bool { (*self) <= (*other) }
- #[inline]
+ #[inline(always)]
fn ge(&self, other: &$t) -> bool { (*self) >= (*other) }
- #[inline]
+ #[inline(always)]
fn gt(&self, other: &$t) -> bool { (*self) > (*other) }
}
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
- impl const Ord for $t {
+ impl Ord for $t {
#[inline]
fn cmp(&self, other: &$t) -> Ordering {
// The order here is important to generate more optimal assembly.
@@ -1424,8 +1384,7 @@ mod impls {
}
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
- impl const Ord for () {
+ impl Ord for () {
#[inline]
fn cmp(&self, _other: &()) -> Ordering {
Equal
@@ -1433,8 +1392,7 @@ mod impls {
}
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
- impl const Ord for bool {
+ impl Ord for bool {
#[inline]
fn cmp(&self, other: &bool) -> Ordering {
// Casting to i8's and converting the difference to an Ordering generates
@@ -1453,8 +1411,8 @@ mod impls {
ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
#[unstable(feature = "never_type", issue = "35121")]
- #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
- impl const PartialEq for ! {
+ impl PartialEq for ! {
+ #[inline]
fn eq(&self, _: &!) -> bool {
*self
}
@@ -1464,16 +1422,16 @@ mod impls {
impl Eq for ! {}
#[unstable(feature = "never_type", issue = "35121")]
- #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
- impl const PartialOrd for ! {
+ impl PartialOrd for ! {
+ #[inline]
fn partial_cmp(&self, _: &!) -> Option<Ordering> {
*self
}
}
#[unstable(feature = "never_type", issue = "35121")]
- #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
- impl const Ord for ! {
+ impl Ord for ! {
+ #[inline]
fn cmp(&self, _: &!) -> Ordering {
*self
}
@@ -1482,10 +1440,9 @@ mod impls {
// & pointers
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
- impl<A: ?Sized, B: ?Sized> const PartialEq<&B> for &A
+ impl<A: ?Sized, B: ?Sized> PartialEq<&B> for &A
where
- A: ~const PartialEq<B>,
+ A: PartialEq<B>,
{
#[inline]
fn eq(&self, other: &&B) -> bool {
@@ -1497,10 +1454,9 @@ mod impls {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
- impl<A: ?Sized, B: ?Sized> const PartialOrd<&B> for &A
+ impl<A: ?Sized, B: ?Sized> PartialOrd<&B> for &A
where
- A: ~const PartialOrd<B>,
+ A: PartialOrd<B>,
{
#[inline]
fn partial_cmp(&self, other: &&B) -> Option<Ordering> {
diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs
index 5888e2960..38a6d1ccd 100644
--- a/library/core/src/convert/mod.rs
+++ b/library/core/src/convert/mod.rs
@@ -214,7 +214,6 @@ pub const fn identity<T>(x: T) -> T {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "AsRef")]
-#[const_trait]
pub trait AsRef<T: ?Sized> {
/// Converts this type into a shared reference of the (usually inferred) input type.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -366,7 +365,6 @@ pub trait AsRef<T: ?Sized> {
/// `&mut Vec<u8>`, for example, is the better choice (callers need to pass the correct type then).
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "AsMut")]
-#[const_trait]
pub trait AsMut<T: ?Sized> {
/// Converts this type into a mutable reference of the (usually inferred) input type.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -443,7 +441,6 @@ pub trait AsMut<T: ?Sized> {
/// [`Vec`]: ../../std/vec/struct.Vec.html
#[rustc_diagnostic_item = "Into"]
#[stable(feature = "rust1", since = "1.0.0")]
-#[const_trait]
pub trait Into<T>: Sized {
/// Converts this type into the (usually inferred) input type.
#[must_use]
@@ -539,7 +536,6 @@ pub trait Into<T>: Sized {
all(_Self = "&str", T = "std::string::String"),
note = "to coerce a `{T}` into a `{Self}`, use `&*` as a prefix",
))]
-#[const_trait]
pub trait From<T>: Sized {
/// Converts to this type from the input type.
#[rustc_diagnostic_item = "from_fn"]
@@ -564,7 +560,6 @@ pub trait From<T>: Sized {
/// [`Into`], see there for details.
#[rustc_diagnostic_item = "TryInto"]
#[stable(feature = "try_from", since = "1.34.0")]
-#[const_trait]
pub trait TryInto<T>: Sized {
/// The type returned in the event of a conversion error.
#[stable(feature = "try_from", since = "1.34.0")]
@@ -641,7 +636,6 @@ pub trait TryInto<T>: Sized {
/// [`try_from`]: TryFrom::try_from
#[rustc_diagnostic_item = "TryFrom"]
#[stable(feature = "try_from", since = "1.34.0")]
-#[const_trait]
pub trait TryFrom<T>: Sized {
/// The type returned in the event of a conversion error.
#[stable(feature = "try_from", since = "1.34.0")]
@@ -658,10 +652,9 @@ pub trait TryFrom<T>: Sized {
// As lifts over &
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<T: ?Sized, U: ?Sized> const AsRef<U> for &T
+impl<T: ?Sized, U: ?Sized> AsRef<U> for &T
where
- T: ~const AsRef<U>,
+ T: AsRef<U>,
{
#[inline]
fn as_ref(&self) -> &U {
@@ -671,10 +664,9 @@ where
// As lifts over &mut
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<T: ?Sized, U: ?Sized> const AsRef<U> for &mut T
+impl<T: ?Sized, U: ?Sized> AsRef<U> for &mut T
where
- T: ~const AsRef<U>,
+ T: AsRef<U>,
{
#[inline]
fn as_ref(&self) -> &U {
@@ -692,10 +684,9 @@ where
// AsMut lifts over &mut
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<T: ?Sized, U: ?Sized> const AsMut<U> for &mut T
+impl<T: ?Sized, U: ?Sized> AsMut<U> for &mut T
where
- T: ~const AsMut<U>,
+ T: AsMut<U>,
{
#[inline]
fn as_mut(&mut self) -> &mut U {
@@ -713,10 +704,9 @@ where
// From implies Into
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<T, U> const Into<U> for T
+impl<T, U> Into<U> for T
where
- U: ~const From<T>,
+ U: From<T>,
{
/// Calls `U::from(self)`.
///
@@ -730,8 +720,7 @@ where
// From (and thus Into) is reflexive
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<T> const From<T> for T {
+impl<T> From<T> for T {
/// Returns the argument unchanged.
#[inline(always)]
fn from(t: T) -> T {
@@ -748,8 +737,7 @@ impl<T> const From<T> for T {
#[allow(unused_attributes)] // FIXME(#58633): do a principled fix instead.
#[rustc_reservation_impl = "permitting this impl would forbid us from adding \
`impl<T> From<!> for T` later; see rust-lang/rust#64715 for details"]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<T> const From<!> for T {
+impl<T> From<!> for T {
fn from(t: !) -> T {
t
}
@@ -757,10 +745,9 @@ impl<T> const From<!> for T {
// TryFrom implies TryInto
#[stable(feature = "try_from", since = "1.34.0")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<T, U> const TryInto<U> for T
+impl<T, U> TryInto<U> for T
where
- U: ~const TryFrom<T>,
+ U: TryFrom<T>,
{
type Error = U::Error;
@@ -773,10 +760,9 @@ where
// Infallible conversions are semantically equivalent to fallible conversions
// with an uninhabited error type.
#[stable(feature = "try_from", since = "1.34.0")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<T, U> const TryFrom<U> for T
+impl<T, U> TryFrom<U> for T
where
- U: ~const Into<T>,
+ U: Into<T>,
{
type Error = Infallible;
@@ -876,8 +862,7 @@ impl AsMut<str> for str {
pub enum Infallible {}
#[stable(feature = "convert_infallible", since = "1.34.0")]
-#[rustc_const_unstable(feature = "const_clone", issue = "91805")]
-impl const Clone for Infallible {
+impl Clone for Infallible {
fn clone(&self) -> Infallible {
match *self {}
}
@@ -929,8 +914,8 @@ impl Ord for Infallible {
}
#[stable(feature = "convert_infallible", since = "1.34.0")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl const From<!> for Infallible {
+impl From<!> for Infallible {
+ #[inline]
fn from(x: !) -> Self {
x
}
diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs
index a74a56bc5..56ab63be2 100644
--- a/library/core/src/convert/num.rs
+++ b/library/core/src/convert/num.rs
@@ -44,8 +44,7 @@ impl_float_to_int!(f64 => u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize);
macro_rules! impl_from {
($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => {
#[$attr]
- #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")]
- impl const From<$Small> for $Large {
+ impl From<$Small> for $Large {
// Rustdocs on the impl block show a "[+] show undocumented items" toggle.
// Rustdocs on functions do not.
#[doc = $doc]
@@ -170,8 +169,7 @@ impl_from! { f32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0"
// bool -> Float
#[stable(feature = "float_from_bool", since = "1.68.0")]
-#[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")]
-impl const From<bool> for f32 {
+impl From<bool> for f32 {
/// Converts `bool` to `f32` losslessly. The resulting value is positive
/// `0.0` for `false` and `1.0` for `true` values.
///
@@ -190,8 +188,7 @@ impl const From<bool> for f32 {
}
}
#[stable(feature = "float_from_bool", since = "1.68.0")]
-#[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")]
-impl const From<bool> for f64 {
+impl From<bool> for f64 {
/// Converts `bool` to `f64` losslessly. The resulting value is positive
/// `0.0` for `false` and `1.0` for `true` values.
///
@@ -214,8 +211,7 @@ impl const From<bool> for f64 {
macro_rules! try_from_unbounded {
($source:ty, $($target:ty),*) => {$(
#[stable(feature = "try_from", since = "1.34.0")]
- #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")]
- impl const TryFrom<$source> for $target {
+ impl TryFrom<$source> for $target {
type Error = TryFromIntError;
/// Try to create the target number type from a source
@@ -233,8 +229,7 @@ macro_rules! try_from_unbounded {
macro_rules! try_from_lower_bounded {
($source:ty, $($target:ty),*) => {$(
#[stable(feature = "try_from", since = "1.34.0")]
- #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")]
- impl const TryFrom<$source> for $target {
+ impl TryFrom<$source> for $target {
type Error = TryFromIntError;
/// Try to create the target number type from a source
@@ -256,8 +251,7 @@ macro_rules! try_from_lower_bounded {
macro_rules! try_from_upper_bounded {
($source:ty, $($target:ty),*) => {$(
#[stable(feature = "try_from", since = "1.34.0")]
- #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")]
- impl const TryFrom<$source> for $target {
+ impl TryFrom<$source> for $target {
type Error = TryFromIntError;
/// Try to create the target number type from a source
@@ -279,8 +273,7 @@ macro_rules! try_from_upper_bounded {
macro_rules! try_from_both_bounded {
($source:ty, $($target:ty),*) => {$(
#[stable(feature = "try_from", since = "1.34.0")]
- #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")]
- impl const TryFrom<$source> for $target {
+ impl TryFrom<$source> for $target {
type Error = TryFromIntError;
/// Try to create the target number type from a source
@@ -431,8 +424,7 @@ use crate::num::NonZeroUsize;
macro_rules! nzint_impl_from {
($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => {
#[$attr]
- #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")]
- impl const From<$Small> for $Large {
+ impl From<$Small> for $Large {
// Rustdocs on the impl block show a "[+] show undocumented items" toggle.
// Rustdocs on functions do not.
#[doc = $doc]
diff --git a/library/core/src/default.rs b/library/core/src/default.rs
index d96b53de0..09dbc9581 100644
--- a/library/core/src/default.rs
+++ b/library/core/src/default.rs
@@ -99,7 +99,6 @@
/// ```
#[cfg_attr(not(test), rustc_diagnostic_item = "Default")]
#[stable(feature = "rust1", since = "1.0.0")]
-#[const_trait]
pub trait Default: Sized {
/// Returns the "default value" for a type.
///
@@ -190,8 +189,7 @@ pub macro Default($item:item) {
macro_rules! default_impl {
($t:ty, $v:expr, $doc:tt) => {
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
- impl const Default for $t {
+ impl Default for $t {
#[inline]
#[doc = $doc]
fn default() -> $t {
diff --git a/library/core/src/escape.rs b/library/core/src/escape.rs
new file mode 100644
index 000000000..3d471419b
--- /dev/null
+++ b/library/core/src/escape.rs
@@ -0,0 +1,112 @@
+//! Helper code for character escaping.
+
+use crate::ascii;
+use crate::num::NonZeroUsize;
+use crate::ops::Range;
+
+const HEX_DIGITS: [ascii::Char; 16] = *b"0123456789abcdef".as_ascii().unwrap();
+
+/// Escapes a byte into provided buffer; returns length of escaped
+/// representation.
+pub(crate) fn escape_ascii_into(output: &mut [ascii::Char; 4], byte: u8) -> Range<u8> {
+ #[inline]
+ fn backslash(a: ascii::Char) -> ([ascii::Char; 4], u8) {
+ ([ascii::Char::ReverseSolidus, a, ascii::Char::Null, ascii::Char::Null], 2)
+ }
+
+ let (data, len) = match byte {
+ b'\t' => backslash(ascii::Char::SmallT),
+ b'\r' => backslash(ascii::Char::SmallR),
+ b'\n' => backslash(ascii::Char::SmallN),
+ b'\\' => backslash(ascii::Char::ReverseSolidus),
+ b'\'' => backslash(ascii::Char::Apostrophe),
+ b'\"' => backslash(ascii::Char::QuotationMark),
+ _ => if let Some(a) = byte.as_ascii() && !byte.is_ascii_control() {
+ ([a, ascii::Char::Null, ascii::Char::Null, ascii::Char::Null], 1)
+ } else {
+ let hi = HEX_DIGITS[usize::from(byte >> 4)];
+ let lo = HEX_DIGITS[usize::from(byte & 0xf)];
+ ([ascii::Char::ReverseSolidus, ascii::Char::SmallX, hi, lo], 4)
+ }
+ };
+ *output = data;
+ 0..len
+}
+
+/// Escapes a character into provided buffer using `\u{NNNN}` representation.
+pub(crate) fn escape_unicode_into(output: &mut [ascii::Char; 10], ch: char) -> Range<u8> {
+ output[9] = ascii::Char::RightCurlyBracket;
+
+ let ch = ch as u32;
+ output[3] = HEX_DIGITS[((ch >> 20) & 15) as usize];
+ output[4] = HEX_DIGITS[((ch >> 16) & 15) as usize];
+ output[5] = HEX_DIGITS[((ch >> 12) & 15) as usize];
+ output[6] = HEX_DIGITS[((ch >> 8) & 15) as usize];
+ output[7] = HEX_DIGITS[((ch >> 4) & 15) as usize];
+ output[8] = HEX_DIGITS[((ch >> 0) & 15) as usize];
+
+ // or-ing 1 ensures that for ch==0 the code computes that one digit should
+ // be printed.
+ let start = (ch | 1).leading_zeros() as usize / 4 - 2;
+ const UNICODE_ESCAPE_PREFIX: &[ascii::Char; 3] = b"\\u{".as_ascii().unwrap();
+ output[start..][..3].copy_from_slice(UNICODE_ESCAPE_PREFIX);
+
+ (start as u8)..10
+}
+
+/// An iterator over an fixed-size array.
+///
+/// This is essentially equivalent to array’s IntoIter except that indexes are
+/// limited to u8 to reduce size of the structure.
+#[derive(Clone, Debug)]
+pub(crate) struct EscapeIterInner<const N: usize> {
+ // The element type ensures this is always ASCII, and thus also valid UTF-8.
+ pub(crate) data: [ascii::Char; N],
+
+ // Invariant: alive.start <= alive.end <= N.
+ pub(crate) alive: Range<u8>,
+}
+
+impl<const N: usize> EscapeIterInner<N> {
+ pub fn new(data: [ascii::Char; N], alive: Range<u8>) -> Self {
+ const { assert!(N < 256) };
+ debug_assert!(alive.start <= alive.end && usize::from(alive.end) <= N, "{alive:?}");
+ Self { data, alive }
+ }
+
+ pub fn from_array<const M: usize>(array: [ascii::Char; M]) -> Self {
+ const { assert!(M <= N) };
+
+ let mut data = [ascii::Char::Null; N];
+ data[..M].copy_from_slice(&array);
+ Self::new(data, 0..M as u8)
+ }
+
+ pub fn as_ascii(&self) -> &[ascii::Char] {
+ &self.data[usize::from(self.alive.start)..usize::from(self.alive.end)]
+ }
+
+ pub fn as_str(&self) -> &str {
+ self.as_ascii().as_str()
+ }
+
+ pub fn len(&self) -> usize {
+ usize::from(self.alive.end - self.alive.start)
+ }
+
+ pub fn next(&mut self) -> Option<u8> {
+ self.alive.next().map(|i| self.data[usize::from(i)].as_u8())
+ }
+
+ pub fn next_back(&mut self) -> Option<u8> {
+ self.alive.next_back().map(|i| self.data[usize::from(i)].as_u8())
+ }
+
+ pub fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+ self.alive.advance_by(n)
+ }
+
+ pub fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+ self.alive.advance_back_by(n)
+ }
+}
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 4a5306cca..e1e1a9b40 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -79,9 +79,9 @@ use crate::str;
///
/// [str]: prim@str "str"
#[derive(Hash)]
-#[cfg_attr(not(test), rustc_diagnostic_item = "CStr")]
#[stable(feature = "core_c_str", since = "1.64.0")]
#[rustc_has_incoherent_inherent_impls]
+#[cfg_attr(not(bootstrap), lang = "CStr")]
// FIXME:
// `fn from` in `impl From<&CStr> for Box<CStr>` current implementation relies
// on `CStr` being layout-compatible with `[u8]`.
@@ -324,14 +324,15 @@ impl CStr {
/// assert_eq!(c_str.to_str().unwrap(), "AAAAAAAA");
/// ```
///
- #[rustc_allow_const_fn_unstable(const_slice_index)]
#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")]
#[rustc_const_stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")]
pub const fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> {
let nul_pos = memchr::memchr(0, bytes);
match nul_pos {
Some(nul_pos) => {
- let subslice = &bytes[..nul_pos + 1];
+ // FIXME(const-hack) replace with range index
+ // SAFETY: nul_pos + 1 <= bytes.len()
+ let subslice = unsafe { crate::slice::from_raw_parts(bytes.as_ptr(), nul_pos + 1) };
// SAFETY: We know there is a nul byte at nul_pos, so this slice
// (ending at the nul byte) is a well-formed C string.
Ok(unsafe { CStr::from_bytes_with_nul_unchecked(subslice) })
@@ -516,8 +517,6 @@ impl CStr {
/// # Examples
///
/// ```
- /// #![feature(cstr_is_empty)]
- ///
/// use std::ffi::CStr;
/// # use std::ffi::FromBytesWithNulError;
///
@@ -532,11 +531,13 @@ impl CStr {
/// # }
/// ```
#[inline]
- #[unstable(feature = "cstr_is_empty", issue = "102444")]
+ #[stable(feature = "cstr_is_empty", since = "1.71.0")]
+ #[rustc_const_stable(feature = "cstr_is_empty", since = "1.71.0")]
pub const fn is_empty(&self) -> bool {
// SAFETY: We know there is at least one byte; for empty strings it
// is the NUL terminator.
- (unsafe { self.inner.get_unchecked(0) }) == &0
+ // FIXME(const-hack): use get_unchecked
+ unsafe { *self.inner.as_ptr() == 0 }
}
/// Converts this C string to a byte slice.
@@ -560,8 +561,7 @@ impl CStr {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
- pub const fn to_bytes(&self) -> &[u8] {
+ pub fn to_bytes(&self) -> &[u8] {
let bytes = self.to_bytes_with_nul();
// SAFETY: to_bytes_with_nul returns slice with length at least 1
unsafe { bytes.get_unchecked(..bytes.len() - 1) }
@@ -612,8 +612,7 @@ impl CStr {
/// assert_eq!(cstr.to_str(), Ok("foo"));
/// ```
#[stable(feature = "cstr_to_str", since = "1.4.0")]
- #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
- pub const fn to_str(&self) -> Result<&str, str::Utf8Error> {
+ pub fn to_str(&self) -> Result<&str, str::Utf8Error> {
// N.B., when `CStr` is changed to perform the length check in `.to_bytes()`
// instead of in `from_ptr()`, it may be worth considering if this should
// be rewritten to do the UTF-8 check inline with the length calculation
diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs
index c4f554c8c..b73abbbac 100644
--- a/library/core/src/ffi/mod.rs
+++ b/library/core/src/ffi/mod.rs
@@ -143,7 +143,10 @@ mod c_char_definition {
target_arch = "powerpc"
)
),
- all(target_os = "fuchsia", target_arch = "aarch64"),
+ all(
+ target_os = "fuchsia",
+ any(target_arch = "aarch64", target_arch = "riscv64")
+ ),
all(target_os = "nto", target_arch = "aarch64"),
target_os = "horizon"
))] {
@@ -199,7 +202,8 @@ mod c_long_definition {
// would be uninhabited and at least dereferencing such pointers would
// be UB.
#[doc = include_str!("c_void.md")]
-#[repr(u8)]
+#[cfg_attr(not(bootstrap), lang = "c_void")]
+#[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(
@@ -240,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 \
@@ -292,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",
@@ -312,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",
@@ -332,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",
@@ -351,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",
@@ -369,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/builders.rs b/library/core/src/fmt/builders.rs
index 7da49b04a..36f49d51c 100644
--- a/library/core/src/fmt/builders.rs
+++ b/library/core/src/fmt/builders.rs
@@ -60,7 +60,7 @@ impl fmt::Write for PadAdapter<'_, '_> {
/// }
///
/// impl fmt::Debug for Foo {
-/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+/// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_struct("Foo")
/// .field("bar", &self.bar)
/// .field("baz", &self.baz)
@@ -109,14 +109,14 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
/// .field("bar", &self.bar) // We add `bar` field.
/// .field("another", &self.another) // We add `another` field.
/// // We even add a field which doesn't exist (because why not?).
- /// .field("not_existing_field", &1)
+ /// .field("nonexistent_field", &1)
/// .finish() // We're good to go!
/// }
/// }
///
/// assert_eq!(
/// format!("{:?}", Bar { bar: 10, another: "Hello World".to_string() }),
- /// "Bar { bar: 10, another: \"Hello World\", not_existing_field: 1 }",
+ /// "Bar { bar: 10, another: \"Hello World\", nonexistent_field: 1 }",
/// );
/// ```
#[stable(feature = "debug_builders", since = "1.2.0")]
@@ -249,7 +249,7 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
/// struct Foo(i32, String);
///
/// impl fmt::Debug for Foo {
-/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+/// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_tuple("Foo")
/// .field(&self.0)
/// .field(&self.1)
@@ -418,7 +418,7 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> {
/// struct Foo(Vec<i32>);
///
/// impl fmt::Debug for Foo {
-/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+/// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_set().entries(self.0.iter()).finish()
/// }
/// }
@@ -548,7 +548,7 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> {
/// struct Foo(Vec<i32>);
///
/// impl fmt::Debug for Foo {
-/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+/// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_list().entries(self.0.iter()).finish()
/// }
/// }
@@ -678,7 +678,7 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> {
/// struct Foo(Vec<(String, i32)>);
///
/// impl fmt::Debug for Foo {
-/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+/// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_map().entries(self.0.iter().map(|&(ref k, ref v)| (k, v))).finish()
/// }
/// }
diff --git a/library/core/src/fmt/float.rs b/library/core/src/fmt/float.rs
index 89d5fac30..3bbf5d877 100644
--- a/library/core/src/fmt/float.rs
+++ b/library/core/src/fmt/float.rs
@@ -45,7 +45,8 @@ where
&mut buf,
&mut parts,
);
- fmt.pad_formatted_parts(&formatted)
+ // SAFETY: `to_exact_fixed_str` and `format_exact` produce only ASCII characters.
+ unsafe { fmt.pad_formatted_parts(&formatted) }
}
// Don't inline this so callers that call both this and the above won't wind
@@ -71,7 +72,8 @@ where
&mut buf,
&mut parts,
);
- fmt.pad_formatted_parts(&formatted)
+ // SAFETY: `to_shortest_str` and `format_shortest` produce only ASCII characters.
+ unsafe { fmt.pad_formatted_parts(&formatted) }
}
fn float_to_decimal_display<T>(fmt: &mut Formatter<'_>, num: &T) -> Result
@@ -116,7 +118,8 @@ where
&mut buf,
&mut parts,
);
- fmt.pad_formatted_parts(&formatted)
+ // SAFETY: `to_exact_exp_str` and `format_exact` produce only ASCII characters.
+ unsafe { fmt.pad_formatted_parts(&formatted) }
}
// Don't inline this so callers that call both this and the above won't wind
@@ -143,7 +146,8 @@ where
&mut buf,
&mut parts,
);
- fmt.pad_formatted_parts(&formatted)
+ // SAFETY: `to_shortest_exp_str` and `format_shortest` produce only ASCII characters.
+ unsafe { fmt.pad_formatted_parts(&formatted) }
}
// Common code of floating point LowerExp and UpperExp.
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index fcda097f0..1786b309c 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -18,6 +18,7 @@ mod float;
#[cfg(no_fp_fmt_parse)]
mod nofloat;
mod num;
+mod rt;
#[stable(feature = "fmt_flags_align", since = "1.28.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "Alignment")]
@@ -38,12 +39,6 @@ pub enum Alignment {
#[stable(feature = "debug_builders", since = "1.2.0")]
pub use self::builders::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple};
-#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
-#[doc(hidden)]
-pub mod rt {
- pub mod v1;
-}
-
/// The type returned by formatter methods.
///
/// # Examples
@@ -227,7 +222,7 @@ impl<W: Write + ?Sized> Write for &mut W {
pub struct Formatter<'a> {
flags: u32,
fill: char,
- align: rt::v1::Alignment,
+ align: rt::Alignment,
width: Option<usize>,
precision: Option<usize>,
@@ -248,7 +243,7 @@ impl<'a> Formatter<'a> {
Formatter {
flags: 0,
fill: ' ',
- align: rt::v1::Alignment::Unknown,
+ align: rt::Alignment::Unknown,
width: None,
precision: None,
buf,
@@ -256,145 +251,48 @@ impl<'a> Formatter<'a> {
}
}
-// NB. Argument is essentially an optimized partially applied formatting function,
-// equivalent to `exists T.(&T, fn(&T, &mut Formatter<'_>) -> Result`.
-
-extern "C" {
- type Opaque;
-}
-
-/// This struct represents the generic "argument" which is taken by the Xprintf
-/// family of functions. It contains a function to format the given value. At
-/// compile time it is ensured that the function and the value have the correct
-/// types, and then this struct is used to canonicalize arguments to one type.
-#[lang = "format_argument"]
+/// This structure represents a safely precompiled version of a format string
+/// and its arguments. This cannot be generated at runtime because it cannot
+/// safely be done, so no constructors are given and the fields are private
+/// to prevent modification.
+///
+/// The [`format_args!`] macro will safely create an instance of this structure.
+/// The macro validates the format string at compile-time so usage of the
+/// [`write()`] and [`format()`] functions can be safely performed.
+///
+/// You can use the `Arguments<'a>` that [`format_args!`] returns in `Debug`
+/// and `Display` contexts as seen below. The example also shows that `Debug`
+/// and `Display` format to the same thing: the interpolated format string
+/// in `format_args!`.
+///
+/// ```rust
+/// let debug = format!("{:?}", format_args!("{} foo {:?}", 1, 2));
+/// let display = format!("{}", format_args!("{} foo {:?}", 1, 2));
+/// assert_eq!("1 foo 2", display);
+/// assert_eq!(display, debug);
+/// ```
+///
+/// [`format()`]: ../../std/fmt/fn.format.html
+#[lang = "format_arguments"]
+#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Copy, Clone)]
-#[allow(missing_debug_implementations)]
-#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
-#[doc(hidden)]
-pub struct ArgumentV1<'a> {
- value: &'a Opaque,
- formatter: fn(&Opaque, &mut Formatter<'_>) -> Result,
-}
-
-/// This struct represents the unsafety of constructing an `Arguments`.
-/// It exists, rather than an unsafe function, in order to simplify the expansion
-/// of `format_args!(..)` and reduce the scope of the `unsafe` block.
-#[lang = "format_unsafe_arg"]
-#[allow(missing_debug_implementations)]
-#[doc(hidden)]
-#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
-pub struct UnsafeArg {
- _private: (),
-}
-
-impl UnsafeArg {
- /// See documentation where `UnsafeArg` is required to know when it is safe to
- /// create and use `UnsafeArg`.
- #[doc(hidden)]
- #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
- #[inline(always)]
- pub unsafe fn new() -> Self {
- Self { _private: () }
- }
-}
-
-// This guarantees a single stable value for the function pointer associated with
-// indices/counts in the formatting infrastructure.
-//
-// Note that a function defined as such would not be correct as functions are
-// always tagged unnamed_addr with the current lowering to LLVM IR, so their
-// address is not considered important to LLVM and as such the as_usize cast
-// could have been miscompiled. In practice, we never call as_usize on non-usize
-// containing data (as a matter of static generation of the formatting
-// arguments), so this is merely an additional check.
-//
-// We primarily want to ensure that the function pointer at `USIZE_MARKER` has
-// an address corresponding *only* to functions that also take `&usize` as their
-// first argument. The read_volatile here ensures that we can safely ready out a
-// usize from the passed reference and that this address does not point at a
-// non-usize taking function.
-#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
-static USIZE_MARKER: fn(&usize, &mut Formatter<'_>) -> Result = |ptr, _| {
- // SAFETY: ptr is a reference
- let _v: usize = unsafe { crate::ptr::read_volatile(ptr) };
- loop {}
-};
-
-macro_rules! arg_new {
- ($f: ident, $t: ident) => {
- #[doc(hidden)]
- #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
- #[inline]
- pub fn $f<'b, T: $t>(x: &'b T) -> ArgumentV1<'_> {
- Self::new(x, $t::fmt)
- }
- };
-}
-
-#[rustc_diagnostic_item = "ArgumentV1Methods"]
-impl<'a> ArgumentV1<'a> {
- #[doc(hidden)]
- #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
- #[inline]
- pub fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> ArgumentV1<'b> {
- // SAFETY: `mem::transmute(x)` is safe because
- // 1. `&'b T` keeps the lifetime it originated with `'b`
- // (so as to not have an unbounded lifetime)
- // 2. `&'b T` and `&'b Opaque` have the same memory layout
- // (when `T` is `Sized`, as it is here)
- // `mem::transmute(f)` is safe since `fn(&T, &mut Formatter<'_>) -> Result`
- // and `fn(&Opaque, &mut Formatter<'_>) -> Result` have the same ABI
- // (as long as `T` is `Sized`)
- unsafe { ArgumentV1 { formatter: mem::transmute(f), value: mem::transmute(x) } }
- }
-
- arg_new!(new_display, Display);
- arg_new!(new_debug, Debug);
- arg_new!(new_octal, Octal);
- arg_new!(new_lower_hex, LowerHex);
- arg_new!(new_upper_hex, UpperHex);
- arg_new!(new_pointer, Pointer);
- arg_new!(new_binary, Binary);
- arg_new!(new_lower_exp, LowerExp);
- arg_new!(new_upper_exp, UpperExp);
+pub struct Arguments<'a> {
+ // Format string pieces to print.
+ pieces: &'a [&'static str],
- #[doc(hidden)]
- #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
- pub fn from_usize(x: &usize) -> ArgumentV1<'_> {
- ArgumentV1::new(x, USIZE_MARKER)
- }
-
- fn as_usize(&self) -> Option<usize> {
- // We are type punning a bit here: USIZE_MARKER only takes an &usize but
- // formatter takes an &Opaque. Rust understandably doesn't think we should compare
- // the function pointers if they don't have the same signature, so we cast to
- // usizes to tell it that we just want to compare addresses.
- if self.formatter as usize == USIZE_MARKER as usize {
- // SAFETY: The `formatter` field is only set to USIZE_MARKER if
- // the value is a usize, so this is safe
- Some(unsafe { *(self.value as *const _ as *const usize) })
- } else {
- None
- }
- }
-}
+ // Placeholder specs, or `None` if all specs are default (as in "{}{}").
+ fmt: Option<&'a [rt::Placeholder]>,
-// flags available in the v1 format of format_args
-#[derive(Copy, Clone)]
-enum FlagV1 {
- SignPlus,
- SignMinus,
- Alternate,
- SignAwareZeroPad,
- DebugLowerHex,
- DebugUpperHex,
+ // Dynamic arguments for interpolation, to be interleaved with string
+ // pieces. (Every argument is preceded by a string piece.)
+ args: &'a [rt::Argument<'a>],
}
+/// Used by the format_args!() macro to create a fmt::Arguments object.
+#[doc(hidden)]
+#[unstable(feature = "fmt_internals", issue = "none")]
impl<'a> Arguments<'a> {
- #[doc(hidden)]
#[inline]
- #[unstable(feature = "fmt_internals", issue = "none")]
#[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")]
pub const fn new_const(pieces: &'a [&'static str]) -> Self {
if pieces.len() > 1 {
@@ -405,23 +303,8 @@ impl<'a> Arguments<'a> {
/// When using the format_args!() macro, this function is used to generate the
/// Arguments structure.
- #[cfg(not(bootstrap))]
- #[doc(hidden)]
#[inline]
- #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
- pub fn new_v1(pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a> {
- if pieces.len() < args.len() || pieces.len() > args.len() + 1 {
- panic!("invalid args");
- }
- Arguments { pieces, fmt: None, args }
- }
-
- #[cfg(bootstrap)]
- #[doc(hidden)]
- #[inline]
- #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
- #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")]
- pub const fn new_v1(pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a> {
+ pub fn new_v1(pieces: &'a [&'static str], args: &'a [rt::Argument<'a>]) -> Arguments<'a> {
if pieces.len() < args.len() || pieces.len() > args.len() + 1 {
panic!("invalid args");
}
@@ -430,21 +313,17 @@ impl<'a> Arguments<'a> {
/// This function is used to specify nonstandard formatting parameters.
///
- /// An `UnsafeArg` is required because the following invariants must be held
+ /// An `rt::UnsafeArg` is required because the following invariants must be held
/// in order for this function to be safe:
/// 1. The `pieces` slice must be at least as long as `fmt`.
- /// 2. Every [`rt::v1::Argument::position`] value within `fmt` must be a
- /// valid index of `args`.
- /// 3. Every [`rt::v1::Count::Param`] within `fmt` must contain a valid index of
- /// `args`.
- #[doc(hidden)]
+ /// 2. Every `rt::Placeholder::position` value within `fmt` must be a valid index of `args`.
+ /// 3. Every `rt::Count::Param` within `fmt` must contain a valid index of `args`.
#[inline]
- #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
pub fn new_v1_formatted(
pieces: &'a [&'static str],
- args: &'a [ArgumentV1<'a>],
- fmt: &'a [rt::v1::Argument],
- _unsafe_arg: UnsafeArg,
+ args: &'a [rt::Argument<'a>],
+ fmt: &'a [rt::Placeholder],
+ _unsafe_arg: rt::UnsafeArg,
) -> Arguments<'a> {
Arguments { pieces, fmt: Some(fmt), args }
}
@@ -453,9 +332,7 @@ impl<'a> Arguments<'a> {
///
/// This is intended to be used for setting initial `String` capacity
/// when using `format!`. Note: this is neither the lower nor upper bound.
- #[doc(hidden)]
#[inline]
- #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
pub fn estimated_capacity(&self) -> usize {
let pieces_length: usize = self.pieces.iter().map(|x| x.len()).sum();
@@ -475,43 +352,6 @@ impl<'a> Arguments<'a> {
}
}
-/// This structure represents a safely precompiled version of a format string
-/// and its arguments. This cannot be generated at runtime because it cannot
-/// safely be done, so no constructors are given and the fields are private
-/// to prevent modification.
-///
-/// The [`format_args!`] macro will safely create an instance of this structure.
-/// The macro validates the format string at compile-time so usage of the
-/// [`write()`] and [`format()`] functions can be safely performed.
-///
-/// You can use the `Arguments<'a>` that [`format_args!`] returns in `Debug`
-/// and `Display` contexts as seen below. The example also shows that `Debug`
-/// and `Display` format to the same thing: the interpolated format string
-/// in `format_args!`.
-///
-/// ```rust
-/// let debug = format!("{:?}", format_args!("{} foo {:?}", 1, 2));
-/// let display = format!("{}", format_args!("{} foo {:?}", 1, 2));
-/// assert_eq!("1 foo 2", display);
-/// assert_eq!(display, debug);
-/// ```
-///
-/// [`format()`]: ../../std/fmt/fn.format.html
-#[lang = "format_arguments"]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[derive(Copy, Clone)]
-pub struct Arguments<'a> {
- // Format string pieces to print.
- pieces: &'a [&'static str],
-
- // Placeholder specs, or `None` if all specs are default (as in "{}{}").
- fmt: Option<&'a [rt::v1::Argument]>,
-
- // Dynamic arguments for interpolation, to be interleaved with string
- // pieces. (Every argument is preceded by a string piece.)
- args: &'a [ArgumentV1<'a>],
-}
-
impl<'a> Arguments<'a> {
/// Get the formatted string, if it has no arguments to be formatted at runtime.
///
@@ -541,7 +381,7 @@ impl<'a> Arguments<'a> {
///
/// fn write_str(_: &str) { /* ... */ }
///
- /// fn write_fmt(args: &Arguments) {
+ /// fn write_fmt(args: &Arguments<'_>) {
/// if let Some(s) = args.as_str() {
/// write_str(s)
/// } else {
@@ -1251,7 +1091,7 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result {
if !piece.is_empty() {
formatter.buf.write_str(*piece)?;
}
- (arg.formatter)(arg.value, &mut formatter)?;
+ arg.fmt(&mut formatter)?;
idx += 1;
}
}
@@ -1281,15 +1121,15 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result {
Ok(())
}
-unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::v1::Argument, args: &[ArgumentV1<'_>]) -> Result {
- fmt.fill = arg.format.fill;
- fmt.align = arg.format.align;
- fmt.flags = arg.format.flags;
+unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argument<'_>]) -> Result {
+ fmt.fill = arg.fill;
+ fmt.align = arg.align;
+ fmt.flags = arg.flags;
// SAFETY: arg and args come from the same Arguments,
// which guarantees the indexes are always within bounds.
unsafe {
- fmt.width = getcount(args, &arg.format.width);
- fmt.precision = getcount(args, &arg.format.precision);
+ fmt.width = getcount(args, &arg.width);
+ fmt.precision = getcount(args, &arg.precision);
}
// Extract the correct argument
@@ -1299,14 +1139,14 @@ unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::v1::Argument, args: &[ArgumentV
let value = unsafe { args.get_unchecked(arg.position) };
// Then actually do some printing
- (value.formatter)(value.value, fmt)
+ value.fmt(fmt)
}
-unsafe fn getcount(args: &[ArgumentV1<'_>], cnt: &rt::v1::Count) -> Option<usize> {
+unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option<usize> {
match *cnt {
- rt::v1::Count::Is(n) => Some(n),
- rt::v1::Count::Implied => None,
- rt::v1::Count::Param(i) => {
+ rt::Count::Is(n) => Some(n),
+ rt::Count::Implied => None,
+ rt::Count::Param(i) => {
debug_assert!(i < args.len());
// SAFETY: cnt and args come from the same Arguments,
// which guarantees this index is always within bounds.
@@ -1388,7 +1228,7 @@ impl<'a> Formatter<'a> {
/// }
///
/// impl fmt::Display for Foo {
- /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
/// // We need to remove "-" from the number output.
/// let tmp = self.nb.abs().to_string();
///
@@ -1449,9 +1289,9 @@ impl<'a> Formatter<'a> {
// is zero
Some(min) if self.sign_aware_zero_pad() => {
let old_fill = crate::mem::replace(&mut self.fill, '0');
- let old_align = crate::mem::replace(&mut self.align, rt::v1::Alignment::Right);
+ let old_align = crate::mem::replace(&mut self.align, rt::Alignment::Right);
write_prefix(self, sign, prefix)?;
- let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?;
+ let post_padding = self.padding(min - width, Alignment::Right)?;
self.buf.write_str(buf)?;
post_padding.write(self)?;
self.fill = old_fill;
@@ -1460,7 +1300,7 @@ impl<'a> Formatter<'a> {
}
// Otherwise, the sign and prefix goes after the padding
Some(min) => {
- let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?;
+ let post_padding = self.padding(min - width, Alignment::Right)?;
write_prefix(self, sign, prefix)?;
self.buf.write_str(buf)?;
post_padding.write(self)
@@ -1488,7 +1328,7 @@ impl<'a> Formatter<'a> {
/// struct Foo;
///
/// impl fmt::Display for Foo {
- /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
/// formatter.pad("Foo")
/// }
/// }
@@ -1535,7 +1375,7 @@ impl<'a> Formatter<'a> {
// If we're under both the maximum and the minimum width, then fill
// up the minimum width with the specified string + some alignment.
else {
- let align = rt::v1::Alignment::Left;
+ let align = Alignment::Left;
let post_padding = self.padding(width - chars_count, align)?;
self.buf.write_str(s)?;
post_padding.write(self)
@@ -1550,17 +1390,19 @@ impl<'a> Formatter<'a> {
pub(crate) fn padding(
&mut self,
padding: usize,
- default: rt::v1::Alignment,
+ default: Alignment,
) -> result::Result<PostPadding, Error> {
let align = match self.align {
- rt::v1::Alignment::Unknown => default,
- _ => self.align,
+ rt::Alignment::Unknown => default,
+ rt::Alignment::Left => Alignment::Left,
+ rt::Alignment::Right => Alignment::Right,
+ rt::Alignment::Center => Alignment::Center,
};
let (pre_pad, post_pad) = match align {
- rt::v1::Alignment::Left => (0, padding),
- rt::v1::Alignment::Right | rt::v1::Alignment::Unknown => (padding, 0),
- rt::v1::Alignment::Center => (padding / 2, (padding + 1) / 2),
+ Alignment::Left => (0, padding),
+ Alignment::Right => (padding, 0),
+ Alignment::Center => (padding / 2, (padding + 1) / 2),
};
for _ in 0..pre_pad {
@@ -1573,14 +1415,17 @@ impl<'a> Formatter<'a> {
/// Takes the formatted parts and applies the padding.
/// Assumes that the caller already has rendered the parts with required precision,
/// so that `self.precision` can be ignored.
- fn pad_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result {
+ ///
+ /// # Safety
+ ///
+ /// Any `numfmt::Part::Copy` parts in `formatted` must contain valid UTF-8.
+ unsafe fn pad_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result {
if let Some(mut width) = self.width {
// for the sign-aware zero padding, we render the sign first and
// behave as if we had no sign from the beginning.
let mut formatted = formatted.clone();
let old_fill = self.fill;
let old_align = self.align;
- let mut align = old_align;
if self.sign_aware_zero_pad() {
// a sign always goes first
let sign = formatted.sign;
@@ -1589,19 +1434,22 @@ impl<'a> Formatter<'a> {
// remove the sign from the formatted parts
formatted.sign = "";
width = width.saturating_sub(sign.len());
- align = rt::v1::Alignment::Right;
self.fill = '0';
- self.align = rt::v1::Alignment::Right;
+ self.align = rt::Alignment::Right;
}
// remaining parts go through the ordinary padding process.
let len = formatted.len();
let ret = if width <= len {
// no padding
- self.write_formatted_parts(&formatted)
+ // SAFETY: Per the precondition.
+ unsafe { self.write_formatted_parts(&formatted) }
} else {
- let post_padding = self.padding(width - len, align)?;
- self.write_formatted_parts(&formatted)?;
+ let post_padding = self.padding(width - len, Alignment::Right)?;
+ // SAFETY: Per the precondition.
+ unsafe {
+ self.write_formatted_parts(&formatted)?;
+ }
post_padding.write(self)
};
self.fill = old_fill;
@@ -1609,20 +1457,20 @@ impl<'a> Formatter<'a> {
ret
} else {
// this is the common case and we take a shortcut
- self.write_formatted_parts(formatted)
+ // SAFETY: Per the precondition.
+ unsafe { self.write_formatted_parts(formatted) }
}
}
- fn write_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result {
- fn write_bytes(buf: &mut dyn Write, s: &[u8]) -> Result {
+ /// # Safety
+ ///
+ /// Any `numfmt::Part::Copy` parts in `formatted` must contain valid UTF-8.
+ unsafe fn write_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result {
+ unsafe fn write_bytes(buf: &mut dyn Write, s: &[u8]) -> Result {
// SAFETY: This is used for `numfmt::Part::Num` and `numfmt::Part::Copy`.
// It's safe to use for `numfmt::Part::Num` since every char `c` is between
- // `b'0'` and `b'9'`, which means `s` is valid UTF-8.
- // It's also probably safe in practice to use for `numfmt::Part::Copy(buf)`
- // since `buf` should be plain ASCII, but it's possible for someone to pass
- // in a bad value for `buf` into `numfmt::to_shortest_str` since it is a
- // public function.
- // FIXME: Determine whether this could result in UB.
+ // `b'0'` and `b'9'`, which means `s` is valid UTF-8. It's safe to use for
+ // `numfmt::Part::Copy` due to this function's precondition.
buf.write_str(unsafe { str::from_utf8_unchecked(s) })
}
@@ -1649,11 +1497,15 @@ impl<'a> Formatter<'a> {
*c = b'0' + (v % 10) as u8;
v /= 10;
}
- write_bytes(self.buf, &s[..len])?;
+ // SAFETY: Per the precondition.
+ unsafe {
+ write_bytes(self.buf, &s[..len])?;
+ }
}
- numfmt::Part::Copy(buf) => {
+ // SAFETY: Per the precondition.
+ numfmt::Part::Copy(buf) => unsafe {
write_bytes(self.buf, buf)?;
- }
+ },
}
}
Ok(())
@@ -1670,7 +1522,7 @@ impl<'a> Formatter<'a> {
/// struct Foo;
///
/// impl fmt::Display for Foo {
- /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
/// formatter.write_str("Foo")
/// // This is equivalent to:
/// // write!(formatter, "Foo")
@@ -1695,7 +1547,7 @@ impl<'a> Formatter<'a> {
/// struct Foo(i32);
///
/// impl fmt::Display for Foo {
- /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
/// formatter.write_fmt(format_args!("Foo {}", self.0))
/// }
/// }
@@ -1730,7 +1582,7 @@ impl<'a> Formatter<'a> {
/// struct Foo;
///
/// impl fmt::Display for Foo {
- /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
/// let c = formatter.fill();
/// if let Some(width) = formatter.width() {
/// for _ in 0..width {
@@ -1758,14 +1610,12 @@ impl<'a> Formatter<'a> {
/// # Examples
///
/// ```
- /// extern crate core;
- ///
/// use std::fmt::{self, Alignment};
///
/// struct Foo;
///
/// impl fmt::Display for Foo {
- /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
/// let s = if let Some(s) = formatter.align() {
/// match s {
/// Alignment::Left => "left",
@@ -1788,10 +1638,10 @@ impl<'a> Formatter<'a> {
#[stable(feature = "fmt_flags_align", since = "1.28.0")]
pub fn align(&self) -> Option<Alignment> {
match self.align {
- rt::v1::Alignment::Left => Some(Alignment::Left),
- rt::v1::Alignment::Right => Some(Alignment::Right),
- rt::v1::Alignment::Center => Some(Alignment::Center),
- rt::v1::Alignment::Unknown => None,
+ rt::Alignment::Left => Some(Alignment::Left),
+ rt::Alignment::Right => Some(Alignment::Right),
+ rt::Alignment::Center => Some(Alignment::Center),
+ rt::Alignment::Unknown => None,
}
}
@@ -1805,7 +1655,7 @@ impl<'a> Formatter<'a> {
/// struct Foo(i32);
///
/// impl fmt::Display for Foo {
- /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
/// if let Some(width) = formatter.width() {
/// // If we received a width, we use it
/// write!(formatter, "{:width$}", format!("Foo({})", self.0), width = width)
@@ -1836,7 +1686,7 @@ impl<'a> Formatter<'a> {
/// struct Foo(f32);
///
/// impl fmt::Display for Foo {
- /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
/// if let Some(precision) = formatter.precision() {
/// // If we received a precision, we use it.
/// write!(formatter, "Foo({1:.*})", precision, self.0)
@@ -1866,7 +1716,7 @@ impl<'a> Formatter<'a> {
/// struct Foo(i32);
///
/// impl fmt::Display for Foo {
- /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
/// if formatter.sign_plus() {
/// write!(formatter,
/// "Foo({}{})",
@@ -1885,7 +1735,7 @@ impl<'a> Formatter<'a> {
#[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn sign_plus(&self) -> bool {
- self.flags & (1 << FlagV1::SignPlus as u32) != 0
+ self.flags & (1 << rt::Flag::SignPlus as u32) != 0
}
/// Determines if the `-` flag was specified.
@@ -1898,7 +1748,7 @@ impl<'a> Formatter<'a> {
/// struct Foo(i32);
///
/// impl fmt::Display for Foo {
- /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
/// if formatter.sign_minus() {
/// // You want a minus sign? Have one!
/// write!(formatter, "-Foo({})", self.0)
@@ -1914,7 +1764,7 @@ impl<'a> Formatter<'a> {
#[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn sign_minus(&self) -> bool {
- self.flags & (1 << FlagV1::SignMinus as u32) != 0
+ self.flags & (1 << rt::Flag::SignMinus as u32) != 0
}
/// Determines if the `#` flag was specified.
@@ -1927,7 +1777,7 @@ impl<'a> Formatter<'a> {
/// struct Foo(i32);
///
/// impl fmt::Display for Foo {
- /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
/// if formatter.alternate() {
/// write!(formatter, "Foo({})", self.0)
/// } else {
@@ -1942,7 +1792,7 @@ impl<'a> Formatter<'a> {
#[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn alternate(&self) -> bool {
- self.flags & (1 << FlagV1::Alternate as u32) != 0
+ self.flags & (1 << rt::Flag::Alternate as u32) != 0
}
/// Determines if the `0` flag was specified.
@@ -1955,7 +1805,7 @@ impl<'a> Formatter<'a> {
/// struct Foo(i32);
///
/// impl fmt::Display for Foo {
- /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
/// assert!(formatter.sign_aware_zero_pad());
/// assert_eq!(formatter.width(), Some(4));
/// // We ignore the formatter's options.
@@ -1968,17 +1818,17 @@ impl<'a> Formatter<'a> {
#[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn sign_aware_zero_pad(&self) -> bool {
- self.flags & (1 << FlagV1::SignAwareZeroPad as u32) != 0
+ self.flags & (1 << rt::Flag::SignAwareZeroPad as u32) != 0
}
// FIXME: Decide what public API we want for these two flags.
// https://github.com/rust-lang/rust/issues/48584
fn debug_lower_hex(&self) -> bool {
- self.flags & (1 << FlagV1::DebugLowerHex as u32) != 0
+ self.flags & (1 << rt::Flag::DebugLowerHex as u32) != 0
}
fn debug_upper_hex(&self) -> bool {
- self.flags & (1 << FlagV1::DebugUpperHex as u32) != 0
+ self.flags & (1 << rt::Flag::DebugUpperHex as u32) != 0
}
/// Creates a [`DebugStruct`] builder designed to assist with creation of
@@ -1999,7 +1849,7 @@ impl<'a> Formatter<'a> {
/// }
///
/// impl fmt::Debug for Foo {
- /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_struct("Foo")
/// .field("bar", &self.bar)
/// .field("baz", &self.baz)
@@ -2157,7 +2007,7 @@ impl<'a> Formatter<'a> {
/// struct Foo<T>(i32, String, PhantomData<T>);
///
/// impl<T> fmt::Debug for Foo<T> {
- /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_tuple("Foo")
/// .field(&self.0)
/// .field(&self.1)
@@ -2289,7 +2139,7 @@ impl<'a> Formatter<'a> {
/// struct Foo(Vec<i32>);
///
/// impl fmt::Debug for Foo {
- /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_list().entries(self.0.iter()).finish()
/// }
/// }
@@ -2312,7 +2162,7 @@ impl<'a> Formatter<'a> {
/// struct Foo(Vec<i32>);
///
/// impl fmt::Debug for Foo {
- /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_set().entries(self.0.iter()).finish()
/// }
/// }
@@ -2328,14 +2178,14 @@ impl<'a> Formatter<'a> {
/// ```rust
/// use std::fmt;
///
- /// struct Arm<'a, L: 'a, R: 'a>(&'a (L, R));
- /// struct Table<'a, K: 'a, V: 'a>(&'a [(K, V)], V);
+ /// struct Arm<'a, L, R>(&'a (L, R));
+ /// struct Table<'a, K, V>(&'a [(K, V)], V);
///
/// impl<'a, L, R> fmt::Debug for Arm<'a, L, R>
/// where
/// L: 'a + fmt::Debug, R: 'a + fmt::Debug
/// {
- /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// L::fmt(&(self.0).0, fmt)?;
/// fmt.write_str(" => ")?;
/// R::fmt(&(self.0).1, fmt)
@@ -2346,7 +2196,7 @@ impl<'a> Formatter<'a> {
/// where
/// K: 'a + fmt::Debug, V: 'a + fmt::Debug
/// {
- /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_set()
/// .entries(self.0.iter().map(Arm))
/// .entry(&Arm(&(format_args!("_"), &self.1)))
@@ -2370,7 +2220,7 @@ impl<'a> Formatter<'a> {
/// struct Foo(Vec<(String, i32)>);
///
/// impl fmt::Debug for Foo {
- /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_map().entries(self.0.iter().map(|&(ref k, ref v)| (k, v))).finish()
/// }
/// }
@@ -2429,6 +2279,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
}
@@ -2436,6 +2287,7 @@ impl Debug for ! {
#[unstable(feature = "never_type", issue = "35121")]
impl Display for ! {
+ #[inline]
fn fmt(&self, _: &mut Formatter<'_>) -> Result {
*self
}
@@ -2538,13 +2390,13 @@ pub(crate) fn pointer_fmt_inner(ptr_addr: usize, f: &mut Formatter<'_>) -> Resul
// or not to zero extend, and then unconditionally set it to get the
// prefix.
if f.alternate() {
- f.flags |= 1 << (FlagV1::SignAwareZeroPad as u32);
+ f.flags |= 1 << (rt::Flag::SignAwareZeroPad as u32);
if f.width.is_none() {
f.width = Some((usize::BITS / 4) as usize + 2);
}
}
- f.flags |= 1 << (FlagV1::Alternate as u32);
+ f.flags |= 1 << (rt::Flag::Alternate as u32);
let ret = LowerHex::fmt(&ptr_addr, f);
diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs
index d8365ae9b..4f42f73eb 100644
--- a/library/core/src/fmt/num.rs
+++ b/library/core/src/fmt/num.rs
@@ -52,8 +52,12 @@ impl_int! { i8 i16 i32 i64 i128 isize }
impl_uint! { u8 u16 u32 u64 u128 usize }
/// A type that represents a specific radix
+///
+/// # Safety
+///
+/// `digit` must return an ASCII character.
#[doc(hidden)]
-trait GenericRadix: Sized {
+unsafe trait GenericRadix: Sized {
/// The number of digits.
const BASE: u8;
@@ -129,7 +133,7 @@ struct UpperHex;
macro_rules! radix {
($T:ident, $base:expr, $prefix:expr, $($x:pat => $conv:expr),+) => {
- impl GenericRadix for $T {
+ unsafe impl GenericRadix for $T {
const BASE: u8 = $base;
const PREFIX: &'static str = $prefix;
fn digit(x: u8) -> u8 {
@@ -407,7 +411,7 @@ macro_rules! impl_Exp {
let parts = &[
numfmt::Part::Copy(buf_slice),
numfmt::Part::Zero(added_precision),
- numfmt::Part::Copy(exp_slice)
+ numfmt::Part::Copy(exp_slice),
];
let sign = if !is_nonnegative {
"-"
@@ -416,8 +420,9 @@ macro_rules! impl_Exp {
} else {
""
};
- let formatted = numfmt::Formatted{sign, parts};
- f.pad_formatted_parts(&formatted)
+ let formatted = numfmt::Formatted { sign, parts };
+ // SAFETY: `buf_slice` and `exp_slice` contain only ASCII characters.
+ unsafe { f.pad_formatted_parts(&formatted) }
}
$(
diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs
new file mode 100644
index 000000000..d37888c27
--- /dev/null
+++ b/library/core/src/fmt/rt.rs
@@ -0,0 +1,212 @@
+#![allow(missing_debug_implementations)]
+#![unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
+
+//! These are the lang items used by format_args!().
+
+use super::*;
+
+#[lang = "format_placeholder"]
+#[derive(Copy, Clone)]
+pub struct Placeholder {
+ pub position: usize,
+ pub fill: char,
+ pub align: Alignment,
+ pub flags: u32,
+ pub precision: Count,
+ pub width: Count,
+}
+
+impl Placeholder {
+ #[inline(always)]
+ pub const fn new(
+ position: usize,
+ fill: char,
+ align: Alignment,
+ flags: u32,
+ precision: Count,
+ width: Count,
+ ) -> Self {
+ Self { position, fill, align, flags, precision, width }
+ }
+}
+
+#[lang = "format_alignment"]
+#[derive(Copy, Clone, PartialEq, Eq)]
+pub enum Alignment {
+ Left,
+ Right,
+ Center,
+ Unknown,
+}
+
+/// Used by [width](https://doc.rust-lang.org/std/fmt/#width)
+/// and [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers.
+#[lang = "format_count"]
+#[derive(Copy, Clone)]
+pub enum Count {
+ /// Specified with a literal number, stores the value
+ Is(usize),
+ /// Specified using `$` and `*` syntaxes, stores the index into `args`
+ Param(usize),
+ /// Not specified
+ Implied,
+}
+
+// This needs to match the order of flags in compiler/rustc_ast_lowering/src/format.rs.
+#[derive(Copy, Clone)]
+pub(super) enum Flag {
+ SignPlus,
+ SignMinus,
+ Alternate,
+ SignAwareZeroPad,
+ DebugLowerHex,
+ DebugUpperHex,
+}
+
+/// This struct represents the generic "argument" which is taken by format_args!().
+/// It contains a function to format the given value. At compile time it is ensured that the
+/// function and the value have the correct types, and then this struct is used to canonicalize
+/// arguments to one type.
+///
+/// Argument is essentially an optimized partially applied formatting function,
+/// equivalent to `exists T.(&T, fn(&T, &mut Formatter<'_>) -> Result`.
+#[lang = "format_argument"]
+#[derive(Copy, Clone)]
+pub struct Argument<'a> {
+ value: &'a Opaque,
+ formatter: fn(&Opaque, &mut Formatter<'_>) -> Result,
+}
+
+#[rustc_diagnostic_item = "ArgumentMethods"]
+impl<'a> Argument<'a> {
+ #[inline(always)]
+ fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'b> {
+ // SAFETY: `mem::transmute(x)` is safe because
+ // 1. `&'b T` keeps the lifetime it originated with `'b`
+ // (so as to not have an unbounded lifetime)
+ // 2. `&'b T` and `&'b Opaque` have the same memory layout
+ // (when `T` is `Sized`, as it is here)
+ // `mem::transmute(f)` is safe since `fn(&T, &mut Formatter<'_>) -> Result`
+ // and `fn(&Opaque, &mut Formatter<'_>) -> Result` have the same ABI
+ // (as long as `T` is `Sized`)
+ unsafe { Argument { formatter: mem::transmute(f), value: mem::transmute(x) } }
+ }
+
+ #[inline(always)]
+ pub fn new_display<'b, T: Display>(x: &'b T) -> Argument<'_> {
+ Self::new(x, Display::fmt)
+ }
+ #[inline(always)]
+ pub fn new_debug<'b, T: Debug>(x: &'b T) -> Argument<'_> {
+ Self::new(x, Debug::fmt)
+ }
+ #[inline(always)]
+ pub fn new_octal<'b, T: Octal>(x: &'b T) -> Argument<'_> {
+ Self::new(x, Octal::fmt)
+ }
+ #[inline(always)]
+ pub fn new_lower_hex<'b, T: LowerHex>(x: &'b T) -> Argument<'_> {
+ Self::new(x, LowerHex::fmt)
+ }
+ #[inline(always)]
+ pub fn new_upper_hex<'b, T: UpperHex>(x: &'b T) -> Argument<'_> {
+ Self::new(x, UpperHex::fmt)
+ }
+ #[inline(always)]
+ pub fn new_pointer<'b, T: Pointer>(x: &'b T) -> Argument<'_> {
+ Self::new(x, Pointer::fmt)
+ }
+ #[inline(always)]
+ pub fn new_binary<'b, T: Binary>(x: &'b T) -> Argument<'_> {
+ Self::new(x, Binary::fmt)
+ }
+ #[inline(always)]
+ pub fn new_lower_exp<'b, T: LowerExp>(x: &'b T) -> Argument<'_> {
+ Self::new(x, LowerExp::fmt)
+ }
+ #[inline(always)]
+ pub fn new_upper_exp<'b, T: UpperExp>(x: &'b T) -> Argument<'_> {
+ Self::new(x, UpperExp::fmt)
+ }
+ #[inline(always)]
+ pub fn from_usize(x: &usize) -> Argument<'_> {
+ Self::new(x, USIZE_MARKER)
+ }
+
+ #[inline(always)]
+ pub(super) fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ (self.formatter)(self.value, f)
+ }
+
+ #[inline(always)]
+ pub(super) fn as_usize(&self) -> Option<usize> {
+ // We are type punning a bit here: USIZE_MARKER only takes an &usize but
+ // formatter takes an &Opaque. Rust understandably doesn't think we should compare
+ // the function pointers if they don't have the same signature, so we cast to
+ // usizes to tell it that we just want to compare addresses.
+ if self.formatter as usize == USIZE_MARKER as usize {
+ // SAFETY: The `formatter` field is only set to USIZE_MARKER if
+ // the value is a usize, so this is safe
+ Some(unsafe { *(self.value as *const _ as *const usize) })
+ } else {
+ 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`.
+/// It exists, rather than an unsafe function, in order to simplify the expansion
+/// of `format_args!(..)` and reduce the scope of the `unsafe` block.
+#[lang = "format_unsafe_arg"]
+pub struct UnsafeArg {
+ _private: (),
+}
+
+impl UnsafeArg {
+ /// See documentation where `UnsafeArg` is required to know when it is safe to
+ /// create and use `UnsafeArg`.
+ #[inline(always)]
+ pub unsafe fn new() -> Self {
+ Self { _private: () }
+ }
+}
+
+extern "C" {
+ type Opaque;
+}
+
+// This guarantees a single stable value for the function pointer associated with
+// indices/counts in the formatting infrastructure.
+//
+// Note that a function defined as such would not be correct as functions are
+// always tagged unnamed_addr with the current lowering to LLVM IR, so their
+// address is not considered important to LLVM and as such the as_usize cast
+// could have been miscompiled. In practice, we never call as_usize on non-usize
+// containing data (as a matter of static generation of the formatting
+// arguments), so this is merely an additional check.
+//
+// We primarily want to ensure that the function pointer at `USIZE_MARKER` has
+// an address corresponding *only* to functions that also take `&usize` as their
+// first argument. The read_volatile here ensures that we can safely ready out a
+// usize from the passed reference and that this address does not point at a
+// non-usize taking function.
+static USIZE_MARKER: fn(&usize, &mut Formatter<'_>) -> Result = |ptr, _| {
+ // SAFETY: ptr is a reference
+ let _v: usize = unsafe { crate::ptr::read_volatile(ptr) };
+ loop {}
+};
diff --git a/library/core/src/fmt/rt/v1.rs b/library/core/src/fmt/rt/v1.rs
deleted file mode 100644
index 6d70796f7..000000000
--- a/library/core/src/fmt/rt/v1.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-//! This is an internal module used by the ifmt! runtime. These structures are
-//! emitted to static arrays to precompile format strings ahead of time.
-//!
-//! These definitions are similar to their `ct` equivalents, but differ in that
-//! these can be statically allocated and are slightly optimized for the runtime
-#![allow(missing_debug_implementations)]
-
-#[lang = "format_placeholder"]
-#[derive(Copy, Clone)]
-// FIXME: Rename this to Placeholder
-pub struct Argument {
- pub position: usize,
- pub format: FormatSpec,
-}
-
-#[derive(Copy, Clone)]
-pub struct FormatSpec {
- pub fill: char,
- pub align: Alignment,
- pub flags: u32,
- pub precision: Count,
- pub width: Count,
-}
-
-impl Argument {
- #[inline(always)]
- pub const fn new(
- position: usize,
- fill: char,
- align: Alignment,
- flags: u32,
- precision: Count,
- width: Count,
- ) -> Self {
- Self { position, format: FormatSpec { fill, align, flags, precision, width } }
- }
-}
-
-/// Possible alignments that can be requested as part of a formatting directive.
-#[lang = "format_alignment"]
-#[derive(Copy, Clone, PartialEq, Eq)]
-pub enum Alignment {
- /// Indication that contents should be left-aligned.
- Left,
- /// Indication that contents should be right-aligned.
- Right,
- /// Indication that contents should be center-aligned.
- Center,
- /// No alignment was requested.
- Unknown,
-}
-
-/// Used by [width](https://doc.rust-lang.org/std/fmt/#width) and [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers.
-#[lang = "format_count"]
-#[derive(Copy, Clone)]
-pub enum Count {
- /// Specified with a literal number, stores the value
- Is(usize),
- /// Specified using `$` and `*` syntaxes, stores the index into `args`
- Param(usize),
- /// Not specified
- Implied,
-}
diff --git a/library/core/src/future/into_future.rs b/library/core/src/future/into_future.rs
index 649b43387..38c654e76 100644
--- a/library/core/src/future/into_future.rs
+++ b/library/core/src/future/into_future.rs
@@ -99,6 +99,7 @@ use crate::future::Future;
/// }
/// ```
#[stable(feature = "into_future", since = "1.64.0")]
+#[rustc_diagnostic_item = "IntoFuture"]
pub trait IntoFuture {
/// The output that the future will produce on completion.
#[stable(feature = "into_future", since = "1.64.0")]
diff --git a/library/core/src/future/join.rs b/library/core/src/future/join.rs
index 35f0dea06..3f35179dd 100644
--- a/library/core/src/future/join.rs
+++ b/library/core/src/future/join.rs
@@ -4,7 +4,7 @@ use crate::cell::UnsafeCell;
use crate::future::{poll_fn, Future};
use crate::mem;
use crate::pin::Pin;
-use crate::task::{Context, Poll};
+use crate::task::{ready, Context, Poll};
/// Polls multiple futures simultaneously, returning a tuple
/// of all results once complete.
@@ -118,7 +118,7 @@ macro join_internal {
fut
})
};
- // Despite how tempting it may be to `let () = fut.poll(cx).ready()?;`
+ // Despite how tempting it may be to `let () = ready!(fut.poll(cx));`
// doing so would defeat the point of `join!`: to start polling eagerly all
// of the futures, to allow parallelizing the waits.
done &= fut.poll(cx).is_ready();
@@ -180,7 +180,7 @@ impl<F: Future> Future for MaybeDone<F> {
// Do not mix match ergonomics with unsafe.
match *self.as_mut().get_unchecked_mut() {
MaybeDone::Future(ref mut f) => {
- let val = Pin::new_unchecked(f).poll(cx).ready()?;
+ let val = ready!(Pin::new_unchecked(f).poll(cx));
self.set(Self::Done(val));
}
MaybeDone::Done(_) => {}
diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs
index 04f02d47f..089493d37 100644
--- a/library/core/src/future/mod.rs
+++ b/library/core/src/future/mod.rs
@@ -66,11 +66,3 @@ pub unsafe fn get_context<'a, 'b>(cx: ResumeTy) -> &'a mut Context<'b> {
// that fulfills all the requirements for a mutable reference.
unsafe { &mut *cx.0.as_ptr().cast() }
}
-
-#[doc(hidden)]
-#[unstable(feature = "gen_future", issue = "50547")]
-#[inline]
-#[cfg_attr(bootstrap, lang = "identity_future")]
-pub const fn identity_future<O, Fut: Future<Output = O>>(f: Fut) -> Fut {
- f
-}
diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs
index 4e7bae7bc..794a57f09 100644
--- a/library/core/src/hash/mod.rs
+++ b/library/core/src/hash/mod.rs
@@ -86,8 +86,7 @@
#![stable(feature = "rust1", since = "1.0.0")]
use crate::fmt;
-use crate::intrinsics::const_eval_select;
-use crate::marker::{self, Destruct};
+use crate::marker;
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
@@ -184,7 +183,6 @@ mod sip;
/// [impl]: ../../std/primitive.str.html#impl-Hash-for-str
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "Hash"]
-#[const_trait]
pub trait Hash {
/// Feeds this value into the given [`Hasher`].
///
@@ -199,7 +197,7 @@ pub trait Hash {
/// println!("Hash is {:x}!", hasher.finish());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- fn hash<H: ~const Hasher>(&self, state: &mut H);
+ fn hash<H: Hasher>(&self, state: &mut H);
/// Feeds a slice of this type into the given [`Hasher`].
///
@@ -236,25 +234,13 @@ pub trait Hash {
/// [`hash`]: Hash::hash
/// [`hash_slice`]: Hash::hash_slice
#[stable(feature = "hash_slice", since = "1.3.0")]
- fn hash_slice<H: ~const Hasher>(data: &[Self], state: &mut H)
+ fn hash_slice<H: Hasher>(data: &[Self], state: &mut H)
where
Self: Sized,
{
- //FIXME(const_trait_impl): revert to only a for loop
- fn rt<T: Hash, H: Hasher>(data: &[T], state: &mut H) {
- for piece in data {
- piece.hash(state)
- }
- }
- const fn ct<T: ~const Hash, H: ~const Hasher>(data: &[T], state: &mut H) {
- let mut i = 0;
- while i < data.len() {
- data[i].hash(state);
- i += 1;
- }
+ for piece in data {
+ piece.hash(state)
}
- // SAFETY: same behavior, CT just uses while instead of for
- unsafe { const_eval_select((data, state), ct, rt) };
}
}
@@ -327,7 +313,6 @@ pub use macros::Hash;
/// [`write_u8`]: Hasher::write_u8
/// [`write_u32`]: Hasher::write_u32
#[stable(feature = "rust1", since = "1.0.0")]
-#[const_trait]
pub trait Hasher {
/// Returns the hash value for the values written so far.
///
@@ -573,8 +558,7 @@ pub trait Hasher {
}
#[stable(feature = "indirect_hasher_impl", since = "1.22.0")]
-#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
-impl<H: ~const Hasher + ?Sized> const Hasher for &mut H {
+impl<H: Hasher + ?Sized> Hasher for &mut H {
fn finish(&self) -> u64 {
(**self).finish()
}
@@ -654,7 +638,6 @@ impl<H: ~const Hasher + ?Sized> const Hasher for &mut H {
/// [`build_hasher`]: BuildHasher::build_hasher
/// [`HashMap`]: ../../std/collections/struct.HashMap.html
#[stable(since = "1.7.0", feature = "build_hasher")]
-#[const_trait]
pub trait BuildHasher {
/// Type of the hasher that will be created.
#[stable(since = "1.7.0", feature = "build_hasher")]
@@ -691,8 +674,6 @@ pub trait BuildHasher {
/// # Example
///
/// ```
- /// #![feature(build_hasher_simple_hash_one)]
- ///
/// use std::cmp::{max, min};
/// use std::hash::{BuildHasher, Hash, Hasher};
/// struct OrderAmbivalentPair<T: Ord>(T, T);
@@ -714,11 +695,11 @@ pub trait BuildHasher {
/// bh.hash_one(&OrderAmbivalentPair(2, 10))
/// );
/// ```
- #[unstable(feature = "build_hasher_simple_hash_one", issue = "86161")]
- fn hash_one<T: ~const Hash + ~const Destruct>(&self, x: T) -> u64
+ #[stable(feature = "build_hasher_simple_hash_one", since = "1.71.0")]
+ fn hash_one<T: Hash>(&self, x: T) -> u64
where
Self: Sized,
- Self::Hasher: ~const Hasher + ~const Destruct,
+ Self::Hasher: Hasher,
{
let mut hasher = self.build_hasher();
x.hash(&mut hasher);
@@ -782,8 +763,7 @@ impl<H> fmt::Debug for BuildHasherDefault<H> {
}
#[stable(since = "1.7.0", feature = "build_hasher")]
-#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
-impl<H: ~const Default + Hasher> const BuildHasher for BuildHasherDefault<H> {
+impl<H: Default + Hasher> BuildHasher for BuildHasherDefault<H> {
type Hasher = H;
fn build_hasher(&self) -> H {
@@ -799,8 +779,7 @@ impl<H> Clone for BuildHasherDefault<H> {
}
#[stable(since = "1.7.0", feature = "build_hasher")]
-#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
-impl<H> const Default for BuildHasherDefault<H> {
+impl<H> Default for BuildHasherDefault<H> {
fn default() -> BuildHasherDefault<H> {
BuildHasherDefault(marker::PhantomData)
}
@@ -825,15 +804,14 @@ mod impls {
macro_rules! impl_write {
($(($ty:ident, $meth:ident),)*) => {$(
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
- impl const Hash for $ty {
+ impl Hash for $ty {
#[inline]
- fn hash<H: ~const Hasher>(&self, state: &mut H) {
+ fn hash<H: Hasher>(&self, state: &mut H) {
state.$meth(*self)
}
#[inline]
- fn hash_slice<H: ~const Hasher>(data: &[$ty], state: &mut H) {
+ fn hash_slice<H: Hasher>(data: &[$ty], state: &mut H) {
let newlen = mem::size_of_val(data);
let ptr = data.as_ptr() as *const u8;
// SAFETY: `ptr` is valid and aligned, as this macro is only used
@@ -862,37 +840,33 @@ mod impls {
}
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
- impl const Hash for bool {
+ impl Hash for bool {
#[inline]
- fn hash<H: ~const Hasher>(&self, state: &mut H) {
+ fn hash<H: Hasher>(&self, state: &mut H) {
state.write_u8(*self as u8)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
- impl const Hash for char {
+ impl Hash for char {
#[inline]
- fn hash<H: ~const Hasher>(&self, state: &mut H) {
+ fn hash<H: Hasher>(&self, state: &mut H) {
state.write_u32(*self as u32)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
- impl const Hash for str {
+ impl Hash for str {
#[inline]
- fn hash<H: ~const Hasher>(&self, state: &mut H) {
+ fn hash<H: Hasher>(&self, state: &mut H) {
state.write_str(self);
}
}
#[stable(feature = "never_hash", since = "1.29.0")]
- #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
- impl const Hash for ! {
+ impl Hash for ! {
#[inline]
- fn hash<H: ~const Hasher>(&self, _: &mut H) {
+ fn hash<H: Hasher>(&self, _: &mut H) {
*self
}
}
@@ -900,10 +874,9 @@ mod impls {
macro_rules! impl_hash_tuple {
() => (
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
- impl const Hash for () {
+ impl Hash for () {
#[inline]
- fn hash<H: ~const Hasher>(&self, _state: &mut H) {}
+ fn hash<H: Hasher>(&self, _state: &mut H) {}
}
);
@@ -911,11 +884,10 @@ mod impls {
maybe_tuple_doc! {
$($name)+ @
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
- impl<$($name: ~const Hash),+> const Hash for ($($name,)+) where last_type!($($name,)+): ?Sized {
+ impl<$($name: Hash),+> Hash for ($($name,)+) where last_type!($($name,)+): ?Sized {
#[allow(non_snake_case)]
#[inline]
- fn hash<S: ~const Hasher>(&self, state: &mut S) {
+ fn hash<S: Hasher>(&self, state: &mut S) {
let ($(ref $name,)+) = *self;
$($name.hash(state);)+
}
@@ -958,29 +930,26 @@ mod impls {
impl_hash_tuple! { T B C D E F G H I J K L }
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
- impl<T: ~const Hash> const Hash for [T] {
+ impl<T: Hash> Hash for [T] {
#[inline]
- fn hash<H: ~const Hasher>(&self, state: &mut H) {
+ fn hash<H: Hasher>(&self, state: &mut H) {
state.write_length_prefix(self.len());
Hash::hash_slice(self, state)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
- impl<T: ?Sized + ~const Hash> const Hash for &T {
+ impl<T: ?Sized + Hash> Hash for &T {
#[inline]
- fn hash<H: ~const Hasher>(&self, state: &mut H) {
+ fn hash<H: Hasher>(&self, state: &mut H) {
(**self).hash(state);
}
}
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
- impl<T: ?Sized + ~const Hash> const Hash for &mut T {
+ impl<T: ?Sized + Hash> Hash for &mut T {
#[inline]
- fn hash<H: ~const Hasher>(&self, state: &mut H) {
+ fn hash<H: Hasher>(&self, state: &mut H) {
(**self).hash(state);
}
}
diff --git a/library/core/src/hash/sip.rs b/library/core/src/hash/sip.rs
index 7f8287bf5..6b9f2e842 100644
--- a/library/core/src/hash/sip.rs
+++ b/library/core/src/hash/sip.rs
@@ -118,7 +118,7 @@ macro_rules! load_int_le {
/// Safety: this performs unchecked indexing of `buf` at `start..start+len`, so
/// that must be in-bounds.
#[inline]
-const unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 {
+unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 {
debug_assert!(len < 8);
let mut i = 0; // current byte index (from LSB) in the output u64
let mut out = 0;
@@ -225,8 +225,7 @@ impl<S: Sip> Hasher<S> {
}
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
-impl const super::Hasher for SipHasher {
+impl super::Hasher for SipHasher {
#[inline]
fn write(&mut self, msg: &[u8]) {
self.0.hasher.write(msg)
@@ -244,8 +243,7 @@ impl const super::Hasher for SipHasher {
}
#[unstable(feature = "hashmap_internals", issue = "none")]
-#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
-impl const super::Hasher for SipHasher13 {
+impl super::Hasher for SipHasher13 {
#[inline]
fn write(&mut self, msg: &[u8]) {
self.hasher.write(msg)
@@ -262,7 +260,7 @@ impl const super::Hasher for SipHasher13 {
}
}
-impl<S: ~const Sip> const super::Hasher for Hasher<S> {
+impl<S: Sip> super::Hasher for Hasher<S> {
// Note: no integer hashing methods (`write_u*`, `write_i*`) are defined
// for this type. We could add them, copy the `short_write` implementation
// in librustc_data_structures/sip128.rs, and add `write_u*`/`write_i*`
@@ -342,7 +340,7 @@ impl<S: ~const Sip> const super::Hasher for Hasher<S> {
}
}
-impl<S: Sip> const Clone for Hasher<S> {
+impl<S: Sip> Clone for Hasher<S> {
#[inline]
fn clone(&self) -> Hasher<S> {
Hasher {
@@ -366,7 +364,6 @@ impl<S: Sip> Default for Hasher<S> {
}
#[doc(hidden)]
-#[const_trait]
trait Sip {
fn c_rounds(_: &mut State);
fn d_rounds(_: &mut State);
@@ -375,7 +372,7 @@ trait Sip {
#[derive(Debug, Clone, Default)]
struct Sip13Rounds;
-impl const Sip for Sip13Rounds {
+impl Sip for Sip13Rounds {
#[inline]
fn c_rounds(state: &mut State) {
compress!(state);
@@ -392,7 +389,7 @@ impl const Sip for Sip13Rounds {
#[derive(Debug, Clone, Default)]
struct Sip24Rounds;
-impl const Sip for Sip24Rounds {
+impl Sip for Sip24Rounds {
#[inline]
fn c_rounds(state: &mut State) {
compress!(state);
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index a20556577..75c104ce2 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -73,8 +73,8 @@ use crate::intrinsics;
/// ```
///
/// While using `unreachable_unchecked()` is perfectly sound in the following
-/// example, the compiler is able to prove that a division by zero is not
-/// possible. Benchmarking reveals that `unreachable_unchecked()` provides
+/// example, as the compiler is able to prove that a division by zero is not
+/// possible, benchmarking reveals that `unreachable_unchecked()` provides
/// no benefit over using [`unreachable!`], while the latter does not introduce
/// the possibility of Undefined Behavior.
///
@@ -217,17 +217,14 @@ pub fn spin_loop() {
/// Note however, that `black_box` is only (and can only be) provided on a "best-effort" basis. The
/// extent to which it can block optimisations may vary depending upon the platform and code-gen
/// backend used. Programs cannot rely on `black_box` for *correctness*, beyond it behaving as the
-/// identity function.
+/// identity function. As such, it **must not be relied upon to control critical program behavior.**
+/// This _immediately_ precludes any direct use of this function for cryptographic or security
+/// purposes.
///
/// [`std::convert::identity`]: crate::convert::identity
///
/// # When is this useful?
///
-/// First and foremost: `black_box` does _not_ guarantee any exact behavior and, in some cases, may
-/// do nothing at all. As such, it **must not be relied upon to control critical program behavior.**
-/// This _immediately_ precludes any direct use of this function for cryptographic or security
-/// purposes.
-///
/// While not suitable in those mission-critical cases, `black_box`'s functionality can generally be
/// relied upon for benchmarking, and should be used there. It will try to ensure that the
/// compiler doesn't optimize away part of the intended test code based on context. For
diff --git a/library/core/src/internal_macros.rs b/library/core/src/internal_macros.rs
index 5d4c9ba73..5774107f5 100644
--- a/library/core/src/internal_macros.rs
+++ b/library/core/src/internal_macros.rs
@@ -1,23 +1,10 @@
// implements the unary operator "op &T"
// based on "op T" where T is expected to be `Copy`able
macro_rules! forward_ref_unop {
- (impl const $imp:ident, $method:ident for $t:ty) => {
- forward_ref_unop!(impl const $imp, $method for $t,
+ (impl $imp:ident, $method:ident for $t:ty) => {
+ forward_ref_unop!(impl $imp, $method for $t,
#[stable(feature = "rust1", since = "1.0.0")]);
};
- // Equivalent to the non-const version, with the addition of `rustc_const_unstable`
- (impl const $imp:ident, $method:ident for $t:ty, #[$attr:meta]) => {
- #[$attr]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const $imp for &$t {
- type Output = <$t as $imp>::Output;
-
- #[inline]
- fn $method(self) -> <$t as $imp>::Output {
- $imp::$method(*self)
- }
- }
- };
(impl $imp:ident, $method:ident for $t:ty, #[$attr:meta]) => {
#[$attr]
impl $imp for &$t {
@@ -34,45 +21,10 @@ macro_rules! forward_ref_unop {
// implements binary operators "&T op U", "T op &U", "&T op &U"
// based on "T op U" where T and U are expected to be `Copy`able
macro_rules! forward_ref_binop {
- (impl const $imp:ident, $method:ident for $t:ty, $u:ty) => {
- forward_ref_binop!(impl const $imp, $method for $t, $u,
+ (impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
+ forward_ref_binop!(impl $imp, $method for $t, $u,
#[stable(feature = "rust1", since = "1.0.0")]);
};
- // Equivalent to the non-const version, with the addition of `rustc_const_unstable`
- (impl const $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => {
- #[$attr]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl<'a> const $imp<$u> for &'a $t {
- type Output = <$t as $imp<$u>>::Output;
-
- #[inline]
- fn $method(self, other: $u) -> <$t as $imp<$u>>::Output {
- $imp::$method(*self, other)
- }
- }
-
- #[$attr]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const $imp<&$u> for $t {
- type Output = <$t as $imp<$u>>::Output;
-
- #[inline]
- fn $method(self, other: &$u) -> <$t as $imp<$u>>::Output {
- $imp::$method(self, *other)
- }
- }
-
- #[$attr]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const $imp<&$u> for &$t {
- type Output = <$t as $imp<$u>>::Output;
-
- #[inline]
- fn $method(self, other: &$u) -> <$t as $imp<$u>>::Output {
- $imp::$method(*self, *other)
- }
- }
- };
(impl $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => {
#[$attr]
impl<'a> $imp<$u> for &'a $t {
@@ -113,21 +65,6 @@ macro_rules! forward_ref_op_assign {
forward_ref_op_assign!(impl $imp, $method for $t, $u,
#[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]);
};
- (impl const $imp:ident, $method:ident for $t:ty, $u:ty) => {
- forward_ref_op_assign!(impl const $imp, $method for $t, $u,
- #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]);
- };
- // Equivalent to the non-const version, with the addition of `rustc_const_unstable`
- (impl const $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => {
- #[$attr]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const $imp<&$u> for $t {
- #[inline]
- fn $method(&mut self, other: &$u) {
- $imp::$method(self, *other);
- }
- }
- };
(impl $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => {
#[$attr]
impl $imp<&$u> for $t {
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index a7c100e1b..f5c5dd29f 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];
@@ -1376,6 +1376,20 @@ extern "rust-intrinsic" {
#[rustc_nounwind]
pub fn transmute<Src, Dst>(src: Src) -> Dst;
+ /// Like [`transmute`], but even less checked at compile-time: rather than
+ /// giving an error for `size_of::<Src>() != size_of::<Dst>()`, it's
+ /// **Undefined Behaviour** at runtime.
+ ///
+ /// Prefer normal `transmute` where possible, for the extra checking, since
+ /// both do exactly the same thing at runtime, if they both compile.
+ ///
+ /// This is not expected to ever be exposed directly to users, rather it
+ /// may eventually be exposed through some more-constrained API.
+ #[cfg(not(bootstrap))]
+ #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")]
+ #[rustc_nounwind]
+ pub fn transmute_unchecked<Src, Dst>(src: Src) -> Dst;
+
/// Returns `true` if the actual type given as `T` requires drop
/// glue; returns `false` if the actual type provided for `T`
/// implements `Copy`.
@@ -1399,6 +1413,10 @@ extern "rust-intrinsic" {
/// This is implemented as an intrinsic to avoid converting to and from an
/// integer, since the conversion would throw away aliasing information.
///
+ /// This can only be used with `Ptr` as a raw pointer type (`*mut` or `*const`)
+ /// to a `Sized` pointee and with `Delta` as `usize` or `isize`. Any other
+ /// instantiations may arbitrarily misbehave, and that's *not* a compiler bug.
+ ///
/// # Safety
///
/// Both the starting and resulting pointer must be either in bounds or one
@@ -1407,6 +1425,14 @@ extern "rust-intrinsic" {
/// returned value will result in undefined behavior.
///
/// The stabilized version of this intrinsic is [`pointer::offset`].
+ #[cfg(not(bootstrap))]
+ #[must_use = "returns a new pointer rather than modifying its argument"]
+ #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
+ #[rustc_nounwind]
+ pub fn offset<Ptr, Delta>(dst: Ptr, offset: Delta) -> Ptr;
+
+ /// The bootstrap version of this is more restricted.
+ #[cfg(bootstrap)]
#[must_use = "returns a new pointer rather than modifying its argument"]
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
#[rustc_nounwind]
@@ -1797,14 +1823,12 @@ extern "rust-intrinsic" {
/// with an even least significant digit.
///
/// This intrinsic does not have a stable counterpart.
- #[cfg(not(bootstrap))]
#[rustc_nounwind]
pub fn roundevenf32(x: f32) -> f32;
/// Returns the nearest integer to an `f64`. Rounds half-way cases to the number
/// with an even least significant digit.
///
/// This intrinsic does not have a stable counterpart.
- #[cfg(not(bootstrap))]
#[rustc_nounwind]
pub fn roundevenf64(x: f64) -> f64;
@@ -2233,13 +2257,23 @@ extern "rust-intrinsic" {
/// This is an implementation detail of [`crate::ptr::read`] and should
/// not be used anywhere else. See its comments for why this exists.
///
- /// This intrinsic can *only* be called where the argument is a local without
- /// projections (`read_via_copy(p)`, not `read_via_copy(*p)`) so that it
+ /// 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_stable(feature = "const_ptr_read", since = "1.71.0")]
+ #[rustc_nounwind]
+ pub fn read_via_copy<T>(ptr: *const T) -> T;
+
+ /// This is an implementation detail of [`crate::ptr::write`] and should
+ /// not be used anywhere else. See its comments for why this exists.
+ ///
+ /// This intrinsic can *only* be called where the pointer is a local without
+ /// projections (`write_via_move(ptr, x)`, not `write_via_move(*ptr, x)`) so
+ /// that it trivially obeys runtime-MIR rules about derefs in operands.
#[cfg(not(bootstrap))]
- #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
+ #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
#[rustc_nounwind]
- pub fn read_via_copy<T>(p: *const T) -> T;
+ pub fn write_via_move<T>(ptr: *mut T, value: T);
/// Returns the value of the discriminant for the variant in 'v';
/// if `T` has no discriminant, returns `0`.
@@ -2444,7 +2478,6 @@ extern "rust-intrinsic" {
/// This method creates a pointer to any `Some` value. If the argument is
/// `None`, an invalid within-bounds pointer (that is still acceptable for
/// constructing an empty slice) is returned.
- #[cfg(not(bootstrap))]
#[rustc_nounwind]
pub fn option_payload_ptr<T>(arg: *const Option<T>) -> *const T;
}
@@ -2460,7 +2493,7 @@ extern "rust-intrinsic" {
/// This macro should be called as `assert_unsafe_precondition!([Generics](name: Type) => Expression)`
/// where the names specified will be moved into the macro as captured variables, and defines an item
/// to call `const_eval_select` on. The tokens inside the square brackets are used to denote generics
-/// for the function declaractions and can be omitted if there is no generics.
+/// for the function declarations and can be omitted if there is no generics.
///
/// # Safety
///
@@ -2490,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);
@@ -2519,7 +2553,9 @@ pub(crate) fn is_valid_allocation_size<T>(len: usize) -> bool {
pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -> bool {
let src_usize = src.addr();
let dst_usize = dst.addr();
- let size = mem::size_of::<T>().checked_mul(count).unwrap();
+ let size = mem::size_of::<T>()
+ .checked_mul(count)
+ .expect("is_nonoverlapping: `size_of::<T>() * count` overflows a usize");
let diff = if src_usize > dst_usize { src_usize - dst_usize } else { dst_usize - src_usize };
// If the absolute distance between the ptrs is at least as big as the size of the buffer,
// they do not overlap.
@@ -2717,7 +2753,7 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
// SAFETY: the safety contract for `copy` must be upheld by the caller.
unsafe {
assert_unsafe_precondition!(
- "ptr::copy requires that both pointer arguments are aligned aligned and non-null",
+ "ptr::copy requires that both pointer arguments are aligned and non-null",
[T](src: *const T, dst: *mut T) =>
is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)
);
@@ -2796,3 +2832,24 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
write_bytes(dst, val, count)
}
}
+
+/// Polyfill for bootstrap
+#[cfg(bootstrap)]
+pub const unsafe fn transmute_unchecked<Src, Dst>(src: Src) -> Dst {
+ use crate::mem::*;
+ // SAFETY: It's a transmute -- the caller promised it's fine.
+ unsafe { transmute_copy(&ManuallyDrop::new(src)) }
+}
+
+/// Polyfill for bootstrap
+#[cfg(bootstrap)]
+pub const unsafe fn write_via_move<T>(ptr: *mut T, value: T) {
+ use crate::mem::*;
+ // SAFETY: the caller must guarantee that `dst` is valid for writes.
+ // `dst` cannot overlap `src` because the caller has mutable access
+ // to `dst` while `src` is owned by this function.
+ unsafe {
+ copy_nonoverlapping::<T>(&value, ptr, 1);
+ forget(value);
+ }
+}
diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs
index 45498a54b..5944a0de1 100644
--- a/library/core/src/intrinsics/mir.rs
+++ b/library/core/src/intrinsics/mir.rs
@@ -15,7 +15,6 @@
//! ```rust
//! #![feature(core_intrinsics, custom_mir)]
//!
-//! extern crate core;
//! use core::intrinsics::mir::*;
//!
//! #[custom_mir(dialect = "built")]
@@ -65,7 +64,6 @@
//! ```rust
//! #![feature(core_intrinsics, custom_mir)]
//!
-//! extern crate core;
//! use core::intrinsics::mir::*;
//!
//! #[custom_mir(dialect = "built")]
@@ -230,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`].
@@ -265,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!() }
}
@@ -280,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);
@@ -317,7 +317,6 @@ define!(
/// ```rust
/// #![feature(custom_mir, core_intrinsics)]
///
- /// extern crate core;
/// use core::intrinsics::mir::*;
///
/// #[custom_mir(dialect = "built")]
diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs
index 75727c3a2..26aa959e6 100644
--- a/library/core/src/iter/adapters/chain.rs
+++ b/library/core/src/iter/adapters/chain.rs
@@ -15,7 +15,7 @@ use crate::ops::Try;
///
/// let a1 = [1, 2, 3];
/// let a2 = [4, 5, 6];
-/// let iter: Chain<Iter<_>, Iter<_>> = a1.iter().chain(a2.iter());
+/// let iter: Chain<Iter<'_, _>, Iter<'_, _>> = a1.iter().chain(a2.iter());
/// ```
#[derive(Clone, Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
diff --git a/library/core/src/iter/adapters/filter.rs b/library/core/src/iter/adapters/filter.rs
index a0afaa326..723657b9e 100644
--- a/library/core/src/iter/adapters/filter.rs
+++ b/library/core/src/iter/adapters/filter.rs
@@ -1,6 +1,9 @@
use crate::fmt;
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable};
use crate::ops::Try;
+use core::array;
+use core::mem::{ManuallyDrop, MaybeUninit};
+use core::ops::ControlFlow;
/// An iterator that filters the elements of `iter` with `predicate`.
///
@@ -57,6 +60,58 @@ where
}
#[inline]
+ fn next_chunk<const N: usize>(
+ &mut self,
+ ) -> Result<[Self::Item; N], array::IntoIter<Self::Item, N>> {
+ let mut array: [MaybeUninit<Self::Item>; N] = MaybeUninit::uninit_array();
+
+ struct Guard<'a, T> {
+ array: &'a mut [MaybeUninit<T>],
+ initialized: usize,
+ }
+
+ impl<T> Drop for Guard<'_, T> {
+ #[inline]
+ fn drop(&mut self) {
+ if const { crate::mem::needs_drop::<T>() } {
+ // SAFETY: self.initialized is always <= N, which also is the length of the array.
+ unsafe {
+ core::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(
+ self.array.get_unchecked_mut(..self.initialized),
+ ));
+ }
+ }
+ }
+ }
+
+ let mut guard = Guard { array: &mut array, initialized: 0 };
+
+ let result = self.iter.try_for_each(|element| {
+ let idx = guard.initialized;
+ guard.initialized = idx + (self.predicate)(&element) as usize;
+
+ // SAFETY: Loop conditions ensure the index is in bounds.
+ unsafe { guard.array.get_unchecked_mut(idx) }.write(element);
+
+ if guard.initialized < N { ControlFlow::Continue(()) } else { ControlFlow::Break(()) }
+ });
+
+ let guard = ManuallyDrop::new(guard);
+
+ match result {
+ ControlFlow::Break(()) => {
+ // SAFETY: The loop above is only explicitly broken when the array has been fully initialized
+ Ok(unsafe { MaybeUninit::array_assume_init(array) })
+ }
+ ControlFlow::Continue(()) => {
+ let initialized = guard.initialized;
+ // SAFETY: The range is in bounds since the loop breaks when reaching N elements.
+ Err(unsafe { array::IntoIter::new_unchecked(array, 0..initialized) })
+ }
+ }
+ }
+
+ #[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
(0, upper) // can't know a lower bound, due to the predicate
diff --git a/library/core/src/iter/adapters/filter_map.rs b/library/core/src/iter/adapters/filter_map.rs
index 6bdf53f7f..693479977 100644
--- a/library/core/src/iter/adapters/filter_map.rs
+++ b/library/core/src/iter/adapters/filter_map.rs
@@ -1,6 +1,7 @@
-use crate::fmt;
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable};
+use crate::mem::{ManuallyDrop, MaybeUninit};
use crate::ops::{ControlFlow, Try};
+use crate::{array, fmt};
/// An iterator that uses `f` to both filter and map elements from `iter`.
///
@@ -62,6 +63,65 @@ where
}
#[inline]
+ fn next_chunk<const N: usize>(
+ &mut self,
+ ) -> Result<[Self::Item; N], array::IntoIter<Self::Item, N>> {
+ let mut array: [MaybeUninit<Self::Item>; N] = MaybeUninit::uninit_array();
+
+ struct Guard<'a, T> {
+ array: &'a mut [MaybeUninit<T>],
+ initialized: usize,
+ }
+
+ impl<T> Drop for Guard<'_, T> {
+ #[inline]
+ fn drop(&mut self) {
+ if const { crate::mem::needs_drop::<T>() } {
+ // SAFETY: self.initialized is always <= N, which also is the length of the array.
+ unsafe {
+ core::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(
+ self.array.get_unchecked_mut(..self.initialized),
+ ));
+ }
+ }
+ }
+ }
+
+ let mut guard = Guard { array: &mut array, initialized: 0 };
+
+ let result = self.iter.try_for_each(|element| {
+ let idx = guard.initialized;
+ let val = (self.f)(element);
+ guard.initialized = idx + val.is_some() as usize;
+
+ // SAFETY: Loop conditions ensure the index is in bounds.
+
+ unsafe {
+ let opt_payload_at = core::intrinsics::option_payload_ptr(&val);
+ let dst = guard.array.as_mut_ptr().add(idx);
+ crate::ptr::copy_nonoverlapping(opt_payload_at.cast(), dst, 1);
+ crate::mem::forget(val);
+ };
+
+ if guard.initialized < N { ControlFlow::Continue(()) } else { ControlFlow::Break(()) }
+ });
+
+ let guard = ManuallyDrop::new(guard);
+
+ match result {
+ ControlFlow::Break(()) => {
+ // SAFETY: The loop above is only explicitly broken when the array has been fully initialized
+ Ok(unsafe { MaybeUninit::array_assume_init(array) })
+ }
+ ControlFlow::Continue(()) => {
+ let initialized = guard.initialized;
+ // SAFETY: The range is in bounds since the loop breaks when reaching N elements.
+ Err(unsafe { array::IntoIter::new_unchecked(array, 0..initialized) })
+ }
+ }
+ }
+
+ #[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
(0, upper) // can't know a lower bound, due to the predicate
diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs
index 2fd8a5c1d..2568aaf34 100644
--- a/library/core/src/iter/adapters/flatten.rs
+++ b/library/core/src/iter/adapters/flatten.rs
@@ -136,26 +136,12 @@ where
}
#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T, I, F, const N: usize> TrustedLen for FlatMap<I, [T; N], F>
+unsafe impl<I, U, F> TrustedLen for FlatMap<I, U, F>
where
- I: TrustedLen,
- F: FnMut(I::Item) -> [T; N],
-{
-}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<'a, T, I, F, const N: usize> TrustedLen for FlatMap<I, &'a [T; N], F>
-where
- I: TrustedLen,
- F: FnMut(I::Item) -> &'a [T; N],
-{
-}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<'a, T, I, F, const N: usize> TrustedLen for FlatMap<I, &'a mut [T; N], F>
-where
- I: TrustedLen,
- F: FnMut(I::Item) -> &'a mut [T; N],
+ I: Iterator,
+ U: IntoIterator,
+ F: FnMut(I::Item) -> U,
+ FlattenCompat<Map<I, F>, <U as IntoIterator>::IntoIter>: TrustedLen,
{
}
@@ -298,8 +284,8 @@ where
#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<I> TrustedLen for Flatten<I>
where
- I: TrustedLen,
- <I as Iterator>::Item: TrustedConstSize,
+ I: Iterator<Item: IntoIterator>,
+ FlattenCompat<I, <I::Item as IntoIterator>::IntoIter>: TrustedLen,
{
}
@@ -324,6 +310,7 @@ where
/// Real logic of both `Flatten` and `FlatMap` which simply delegate to
/// this type.
#[derive(Clone, Debug)]
+#[unstable(feature = "trusted_len", issue = "37572")]
struct FlattenCompat<I, U> {
iter: Fuse<I>,
frontiter: Option<U>,
@@ -477,6 +464,7 @@ where
}
}
+#[unstable(feature = "trusted_len", issue = "37572")]
impl<I, U> Iterator for FlattenCompat<I, U>
where
I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
@@ -591,6 +579,7 @@ where
}
}
+#[unstable(feature = "trusted_len", issue = "37572")]
impl<I, U> DoubleEndedIterator for FlattenCompat<I, U>
where
I: DoubleEndedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
@@ -660,6 +649,30 @@ where
}
}
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<const N: usize, I, T> TrustedLen
+ for FlattenCompat<I, <[T; N] as IntoIterator>::IntoIter>
+where
+ I: TrustedLen<Item = [T; N]>,
+{
+}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<'a, const N: usize, I, T> TrustedLen
+ for FlattenCompat<I, <&'a [T; N] as IntoIterator>::IntoIter>
+where
+ I: TrustedLen<Item = &'a [T; N]>,
+{
+}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<'a, const N: usize, I, T> TrustedLen
+ for FlattenCompat<I, <&'a mut [T; N] as IntoIterator>::IntoIter>
+where
+ I: TrustedLen<Item = &'a mut [T; N]>,
+{
+}
+
trait ConstSizeIntoIterator: IntoIterator {
// FIXME(#31844): convert to an associated const once specialization supports that
fn size() -> Option<usize>;
@@ -696,19 +709,6 @@ impl<T, const N: usize> ConstSizeIntoIterator for &mut [T; N] {
}
}
-#[doc(hidden)]
-#[unstable(feature = "std_internals", issue = "none")]
-// FIXME(#20400): Instead of this helper trait there should be multiple impl TrustedLen for Flatten<>
-// blocks with different bounds on Iterator::Item but the compiler erroneously considers them overlapping
-pub unsafe trait TrustedConstSize: IntoIterator {}
-
-#[unstable(feature = "std_internals", issue = "none")]
-unsafe impl<T, const N: usize> TrustedConstSize for [T; N] {}
-#[unstable(feature = "std_internals", issue = "none")]
-unsafe impl<T, const N: usize> TrustedConstSize for &'_ [T; N] {}
-#[unstable(feature = "std_internals", issue = "none")]
-unsafe impl<T, const N: usize> TrustedConstSize for &'_ mut [T; N] {}
-
#[inline]
fn and_then_or_clear<T, U>(opt: &mut Option<T>, f: impl FnOnce(&mut T) -> Option<U>) -> Option<U> {
let x = f(opt.as_mut()?);
diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs
index 37db07429..0171d8981 100644
--- a/library/core/src/iter/range.rs
+++ b/library/core/src/iter/range.rs
@@ -732,12 +732,18 @@ impl<A: Step> Iterator for ops::Range<A> {
}
#[inline]
- fn min(mut self) -> Option<A> {
+ fn min(mut self) -> Option<A>
+ where
+ A: Ord,
+ {
self.next()
}
#[inline]
- fn max(mut self) -> Option<A> {
+ fn max(mut self) -> Option<A>
+ where
+ A: Ord,
+ {
self.next_back()
}
@@ -1158,12 +1164,18 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
}
#[inline]
- fn min(mut self) -> Option<A> {
+ fn min(mut self) -> Option<A>
+ where
+ A: Ord,
+ {
self.next()
}
#[inline]
- fn max(mut self) -> Option<A> {
+ fn max(mut self) -> Option<A>
+ where
+ A: Ord,
+ {
self.next_back()
}
diff --git a/library/core/src/iter/sources/empty.rs b/library/core/src/iter/sources/empty.rs
index 617dfd123..243df015f 100644
--- a/library/core/src/iter/sources/empty.rs
+++ b/library/core/src/iter/sources/empty.rs
@@ -81,8 +81,7 @@ impl<T> Clone for Empty<T> {
// not #[derive] because that adds a Default bound on T,
// which isn't necessary.
#[stable(feature = "iter_empty", since = "1.2.0")]
-#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
-impl<T> const Default for Empty<T> {
+impl<T> Default for Empty<T> {
fn default() -> Empty<T> {
Empty(marker::PhantomData)
}
diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs
index e099700e3..0675e5635 100644
--- a/library/core/src/iter/traits/collect.rs
+++ b/library/core/src/iter/traits/collect.rs
@@ -95,6 +95,16 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented(
on(
+ _Self = "&[{A}]",
+ message = "a slice of type `{Self}` cannot be built since we need to store the elements somewhere",
+ label = "try explicitly collecting into a `Vec<{A}>`",
+ ),
+ on(
+ all(A = "{integer}", any(_Self = "&[{integral}]",)),
+ message = "a slice of type `{Self}` cannot be built since we need to store the elements somewhere",
+ label = "try explicitly collecting into a `Vec<{A}>`",
+ ),
+ on(
_Self = "[{A}]",
message = "a slice of type `{Self}` cannot be built since `{Self}` has no definite size",
label = "try explicitly collecting into a `Vec<{A}>`",
@@ -228,7 +238,6 @@ pub trait FromIterator<A>: Sized {
#[rustc_diagnostic_item = "IntoIterator"]
#[rustc_skip_array_during_method_dispatch]
#[stable(feature = "rust1", since = "1.0.0")]
-#[const_trait]
pub trait IntoIterator {
/// The type of the elements being iterated over.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -264,7 +273,7 @@ pub trait IntoIterator {
#[rustc_const_unstable(feature = "const_intoiterator_identity", issue = "90603")]
#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: Iterator> const IntoIterator for I {
+impl<I: Iterator> IntoIterator for I {
type Item = I::Item;
type IntoIter = I;
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 028776042..dabfce144 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -70,7 +70,6 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
#[doc(notable_trait)]
#[rustc_diagnostic_item = "Iterator"]
#[must_use = "iterators are lazy and do nothing unless consumed"]
-#[const_trait]
pub trait Iterator {
/// The type of the elements being iterated over.
#[rustc_diagnostic_item = "IteratorItem"]
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 04243544b..6c419eb16 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -107,16 +107,13 @@
#![feature(const_arguments_as_str)]
#![feature(const_array_from_ref)]
#![feature(const_array_into_iter_constructors)]
+#![feature(const_assume)]
#![feature(const_bigint_helper_methods)]
#![feature(const_black_box)]
#![feature(const_caller_location)]
#![feature(const_cell_into_inner)]
#![feature(const_char_from_u32_unchecked)]
-#![feature(const_clone)]
-#![feature(const_cmp)]
-#![feature(const_convert)]
#![feature(const_cstr_methods)]
-#![feature(const_default_impls)]
#![feature(const_discriminant)]
#![feature(const_eval_select)]
#![feature(const_exact_div)]
@@ -131,14 +128,12 @@
#![feature(const_intrinsic_forget)]
#![feature(const_ipv4)]
#![feature(const_ipv6)]
-#![feature(const_is_char_boundary)]
#![feature(const_likely)]
#![feature(const_maybe_uninit_as_mut_ptr)]
#![feature(const_maybe_uninit_assume_init)]
#![feature(const_maybe_uninit_uninit_array)]
#![feature(const_nonnull_new)]
-#![feature(const_num_from_num)]
-#![feature(const_ops)]
+#![feature(const_num_midpoint)]
#![feature(const_option)]
#![feature(const_option_ext)]
#![feature(const_pin)]
@@ -146,22 +141,20 @@
#![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)]
#![feature(const_replace)]
-#![feature(const_result_drop)]
#![feature(const_size_of_val)]
#![feature(const_size_of_val_raw)]
#![feature(const_slice_from_raw_parts_mut)]
#![feature(const_slice_from_ref)]
#![feature(const_slice_index)]
+#![feature(const_slice_is_ascii)]
#![feature(const_slice_ptr_len)]
#![feature(const_slice_split_at_mut)]
#![feature(const_str_from_utf8_unchecked_mut)]
#![feature(const_swap)]
-#![feature(const_trait_impl)]
#![feature(const_transmute_copy)]
#![feature(const_try)]
#![feature(const_type_id)]
@@ -171,6 +164,7 @@
#![feature(const_waker)]
#![feature(core_panic)]
#![feature(duration_consts_float)]
+#![feature(internal_impls_macro)]
#![feature(ip)]
#![feature(is_ascii_octdigit)]
#![feature(maybe_uninit_uninit_array)]
@@ -207,9 +201,9 @@
#![feature(const_mut_refs)]
#![feature(const_precise_live_drops)]
#![feature(const_refs_to_cell)]
+#![feature(const_trait_impl)]
#![feature(decl_macro)]
#![feature(deprecated_suggestion)]
-#![feature(derive_const)]
#![feature(doc_cfg)]
#![feature(doc_cfg_hide)]
#![feature(doc_notable_trait)]
@@ -222,6 +216,7 @@
#![feature(intra_doc_pointers)]
#![feature(intrinsics)]
#![feature(lang_items)]
+#![feature(let_chains)]
#![feature(link_llvm_intrinsics)]
#![feature(macro_metavar_expr)]
#![feature(min_specialization)]
@@ -385,6 +380,7 @@ pub mod alloc;
// note: does not need to be public
mod bool;
+mod escape;
mod tuple;
mod unit;
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 7c93c93b4..c4134dbcd 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -498,7 +498,6 @@ macro_rules! r#try {
/// In a `no_std` setup you are responsible for the implementation details of the components.
///
/// ```no_run
-/// # extern crate core;
/// use core::fmt::Write;
///
/// struct Example;
@@ -1428,7 +1427,7 @@ pub(crate) mod builtin {
#[rustc_builtin_macro]
#[macro_export]
#[rustc_diagnostic_item = "assert_macro"]
- #[allow_internal_unstable(core_panic, edition_panic)]
+ #[allow_internal_unstable(core_panic, edition_panic, generic_assert_internals)]
macro_rules! assert {
($cond:expr $(,)?) => {{ /* compiler built-in */ }};
($cond:expr, $($arg:tt)+) => {{ /* compiler built-in */ }};
diff --git a/library/core/src/macros/panic.md b/library/core/src/macros/panic.md
index 98fb7e9e4..8b549e187 100644
--- a/library/core/src/macros/panic.md
+++ b/library/core/src/macros/panic.md
@@ -42,7 +42,7 @@ the successful result of some computation, `Ok(T)`, or error types that
represent an anticipated runtime failure mode of that computation, `Err(E)`.
`Result` is used alongside user defined types which represent the various
anticipated runtime failure modes that the associated computation could
-encounter. `Result` must be propagated manually, often with the the help of the
+encounter. `Result` must be propagated manually, often with the help of the
`?` operator and `Try` trait, and they must be reported manually, often with
the help of the `Error` trait.
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 3cd4f5104..8dab8d1a6 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -12,6 +12,50 @@ use crate::fmt::Debug;
use crate::hash::Hash;
use crate::hash::Hasher;
+/// Implements a given marker trait for multiple types at the same time.
+///
+/// The basic syntax looks like this:
+/// ```ignore private macro
+/// marker_impls! { MarkerTrait for u8, i8 }
+/// ```
+/// You can also implement `unsafe` traits
+/// ```ignore private macro
+/// marker_impls! { unsafe MarkerTrait for u8, i8 }
+/// ```
+/// Add attributes to all impls:
+/// ```ignore private macro
+/// marker_impls! {
+/// #[allow(lint)]
+/// #[unstable(feature = "marker_trait", issue = "none")]
+/// MarkerTrait for u8, i8
+/// }
+/// ```
+/// And use generics:
+/// ```ignore private macro
+/// marker_impls! {
+/// MarkerTrait for
+/// u8, i8,
+/// {T: ?Sized} *const T,
+/// {T: ?Sized} *mut T,
+/// {T: MarkerTrait} PhantomData<T>,
+/// u32,
+/// }
+/// ```
+#[unstable(feature = "internal_impls_macro", issue = "none")]
+macro marker_impls {
+ ( $(#[$($meta:tt)*])* $Trait:ident for $({$($bounds:tt)*})? $T:ty $(, $($rest:tt)*)? ) => {
+ $(#[$($meta)*])* impl< $($($bounds)*)? > $Trait for $T {}
+ marker_impls! { $(#[$($meta)*])* $Trait for $($($rest)*)? }
+ },
+ ( $(#[$($meta:tt)*])* $Trait:ident for ) => {},
+
+ ( $(#[$($meta:tt)*])* unsafe $Trait:ident for $({$($bounds:tt)*})? $T:ty $(, $($rest:tt)*)? ) => {
+ $(#[$($meta)*])* unsafe impl< $($($bounds)*)? > $Trait for $T {}
+ marker_impls! { $(#[$($meta)*])* unsafe $Trait for $($($rest)*)? }
+ },
+ ( $(#[$($meta:tt)*])* unsafe $Trait:ident for ) => {},
+}
+
/// Types that can be transferred across thread boundaries.
///
/// This trait is automatically implemented when the compiler determines it's
@@ -24,7 +68,7 @@ use crate::hash::Hasher;
/// operations. Its cousin [`sync::Arc`][arc] does use atomic operations (incurring
/// some overhead) and thus is `Send`.
///
-/// See [the Nomicon](../../nomicon/send-and-sync.html) for more details.
+/// See [the Nomicon](../../nomicon/send-and-sync.html) and the [`Sync`] trait for more details.
///
/// [`Rc`]: ../../std/rc/struct.Rc.html
/// [arc]: ../../std/sync/struct.Arc.html
@@ -214,6 +258,20 @@ pub trait StructuralEq {
// Empty.
}
+// FIXME: Remove special cases of these types from the compiler pattern checking code and always check `T: StructuralEq` instead
+marker_impls! {
+ #[unstable(feature = "structural_match", issue = "31434")]
+ StructuralEq for
+ usize, u8, u16, u32, u64, u128,
+ isize, i8, i16, i32, i64, i128,
+ bool,
+ char,
+ str /* Technically requires `[u8]: StructuralEq` */,
+ {T, const N: usize} [T; N],
+ {T} [T],
+ {T: ?Sized} &T,
+}
+
/// Types whose values can be duplicated simply by copying bits.
///
/// By default, variable bindings have 'move semantics.' In other
@@ -401,6 +459,30 @@ pub macro Copy($item:item) {
/* compiler built-in */
}
+// Implementations of `Copy` for primitive types.
+//
+// Implementations that cannot be described in Rust
+// are implemented in `traits::SelectionContext::copy_clone_conditions()`
+// in `rustc_trait_selection`.
+marker_impls! {
+ #[stable(feature = "rust1", since = "1.0.0")]
+ Copy for
+ usize, u8, u16, u32, u64, u128,
+ isize, i8, i16, i32, i64, i128,
+ f32, f64,
+ bool, char,
+ {T: ?Sized} *const T,
+ {T: ?Sized} *mut T,
+
+}
+
+#[unstable(feature = "never_type", issue = "35121")]
+impl Copy for ! {}
+
+/// Shared references can be copied, but mutable references *cannot*!
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> Copy for &T {}
+
/// Types for which it is safe to share references between threads.
///
/// This trait is automatically implemented when the compiler determines
@@ -426,6 +508,11 @@ pub macro Copy($item:item) {
/// becomes read-only, as if it were a `& &T`. Hence there is no risk
/// of a data race.
///
+/// A shorter overview of how [`Sync`] and [`Send`] relate to referencing:
+/// * `&T` is [`Send`] if and only if `T` is [`Sync`]
+/// * `&mut T` is [`Send`] if and only if `T` is [`Send`]
+/// * `&T` and `&mut T` are [`Sync`] if and only if `T` is [`Sync`]
+///
/// Types that are not `Sync` are those that have "interior
/// mutability" in a non-thread-safe form, such as [`Cell`][cell]
/// and [`RefCell`][refcell]. These types allow for mutation of
@@ -591,14 +678,14 @@ impl<T: ?Sized> !Sync for *mut T {}
/// use std::marker::PhantomData;
///
/// # #[allow(dead_code)]
-/// struct Slice<'a, T: 'a> {
+/// struct Slice<'a, T> {
/// start: *const T,
/// end: *const T,
/// phantom: PhantomData<&'a 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
@@ -607,7 +694,7 @@ impl<T: ?Sized> !Sync for *mut T {}
/// ```
/// # #![allow(dead_code)]
/// # use std::marker::PhantomData;
-/// # struct Slice<'a, T: 'a> {
+/// # struct Slice<'a, T> {
/// # start: *const T,
/// # end: *const T,
/// # phantom: PhantomData<&'a T>,
@@ -669,16 +756,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
///
@@ -686,7 +768,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>;
@@ -732,8 +814,7 @@ impl<T: ?Sized> Clone for PhantomData<T> {
}
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
-impl<T: ?Sized> const Default for PhantomData<T> {
+impl<T: ?Sized> Default for PhantomData<T> {
fn default() -> Self {
Self
}
@@ -774,11 +855,14 @@ pub trait DiscriminantKind {
pub(crate) unsafe auto trait Freeze {}
impl<T: ?Sized> !Freeze for UnsafeCell<T> {}
-unsafe impl<T: ?Sized> Freeze for PhantomData<T> {}
-unsafe impl<T: ?Sized> Freeze for *const T {}
-unsafe impl<T: ?Sized> Freeze for *mut T {}
-unsafe impl<T: ?Sized> Freeze for &T {}
-unsafe impl<T: ?Sized> Freeze for &mut T {}
+marker_impls! {
+ unsafe Freeze for
+ {T: ?Sized} PhantomData<T>,
+ {T: ?Sized} *const T,
+ {T: ?Sized} *mut T,
+ {T: ?Sized} &T,
+ {T: ?Sized} &mut T,
+}
/// Types that can be safely moved after being pinned.
///
@@ -839,17 +923,19 @@ pub struct PhantomPinned;
#[stable(feature = "pin", since = "1.33.0")]
impl !Unpin for PhantomPinned {}
-#[stable(feature = "pin", since = "1.33.0")]
-impl<'a, T: ?Sized + 'a> Unpin for &'a T {}
-
-#[stable(feature = "pin", since = "1.33.0")]
-impl<'a, T: ?Sized + 'a> Unpin for &'a mut T {}
-
-#[stable(feature = "pin_raw", since = "1.38.0")]
-impl<T: ?Sized> Unpin for *const T {}
+marker_impls! {
+ #[stable(feature = "pin", since = "1.33.0")]
+ Unpin for
+ {T: ?Sized} &T,
+ {T: ?Sized} &mut T,
+}
-#[stable(feature = "pin_raw", since = "1.38.0")]
-impl<T: ?Sized> Unpin for *mut T {}
+marker_impls! {
+ #[stable(feature = "pin_raw", since = "1.38.0")]
+ Unpin for
+ {T: ?Sized} *const T,
+ {T: ?Sized} *mut T,
+}
/// A marker for types that can be dropped.
///
@@ -858,8 +944,8 @@ impl<T: ?Sized> Unpin for *mut T {}
#[unstable(feature = "const_trait_impl", issue = "67792")]
#[lang = "destruct"]
#[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)]
-#[const_trait]
#[rustc_deny_explicit_impl]
+#[const_trait]
pub trait Destruct {}
/// A marker for tuple types.
@@ -884,43 +970,33 @@ pub trait Tuple {}
)]
pub trait PointerLike {}
-/// Implementations of `Copy` for primitive types.
-///
-/// Implementations that cannot be described in Rust
-/// are implemented in `traits::SelectionContext::copy_clone_conditions()`
-/// in `rustc_trait_selection`.
-mod copy_impls {
-
- use super::Copy;
-
- macro_rules! impl_copy {
- ($($t:ty)*) => {
- $(
- #[stable(feature = "rust1", since = "1.0.0")]
- impl Copy for $t {}
- )*
- }
- }
-
- impl_copy! {
- usize u8 u16 u32 u64 u128
- isize i8 i16 i32 i64 i128
- f32 f64
- bool char
- }
-
- #[unstable(feature = "never_type", issue = "35121")]
- impl Copy for ! {}
-
- #[stable(feature = "rust1", since = "1.0.0")]
- impl<T: ?Sized> Copy for *const T {}
+/// A marker for types which can be used as types of `const` generic parameters.
+#[cfg_attr(not(bootstrap), lang = "const_param_ty")]
+#[unstable(feature = "adt_const_params", issue = "95174")]
+#[rustc_on_unimplemented(message = "`{Self}` can't be used as a const parameter type")]
+pub trait ConstParamTy: StructuralEq {}
- #[stable(feature = "rust1", since = "1.0.0")]
- impl<T: ?Sized> Copy for *mut T {}
+/// Derive macro generating an impl of the trait `ConstParamTy`.
+#[rustc_builtin_macro]
+#[unstable(feature = "adt_const_params", issue = "95174")]
+#[cfg(not(bootstrap))]
+pub macro ConstParamTy($item:item) {
+ /* compiler built-in */
+}
- /// Shared references can be copied, but mutable references *cannot*!
- #[stable(feature = "rust1", since = "1.0.0")]
- impl<T: ?Sized> Copy for &T {}
+// FIXME(generic_const_parameter_types): handle `ty::FnDef`/`ty::Closure`
+// FIXME(generic_const_parameter_types): handle `ty::Tuple`
+marker_impls! {
+ #[unstable(feature = "adt_const_params", issue = "95174")]
+ ConstParamTy for
+ usize, u8, u16, u32, u64, u128,
+ isize, i8, i16, i32, i64, i128,
+ bool,
+ char,
+ str /* Technically requires `[u8]: ConstParamTy` */,
+ {T: ConstParamTy, const N: usize} [T; N],
+ {T: ConstParamTy} [T],
+ {T: ?Sized + ConstParamTy} &T,
}
/// A common trait implemented by all function pointers.
@@ -930,7 +1006,6 @@ mod copy_impls {
reason = "internal trait for implementing various traits for all function pointers"
)]
#[lang = "fn_ptr_trait"]
-#[cfg(not(bootstrap))]
#[rustc_deny_explicit_impl]
pub trait FnPtr: Copy + Clone {
/// Returns the address of the function pointer.
diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs
index 3d719afe4..5f3d66e37 100644
--- a/library/core/src/mem/manually_drop.rs
+++ b/library/core/src/mem/manually_drop.rs
@@ -146,8 +146,7 @@ impl<T: ?Sized> ManuallyDrop<T> {
}
#[stable(feature = "manually_drop", since = "1.20.0")]
-#[rustc_const_unstable(feature = "const_deref", issue = "88955")]
-impl<T: ?Sized> const Deref for ManuallyDrop<T> {
+impl<T: ?Sized> Deref for ManuallyDrop<T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &T {
@@ -156,8 +155,7 @@ impl<T: ?Sized> const Deref for ManuallyDrop<T> {
}
#[stable(feature = "manually_drop", since = "1.20.0")]
-#[rustc_const_unstable(feature = "const_deref", issue = "88955")]
-impl<T: ?Sized> const DerefMut for ManuallyDrop<T> {
+impl<T: ?Sized> DerefMut for ManuallyDrop<T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut T {
&mut self.value
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index 9c6d48675..d09a24b4b 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -945,14 +945,10 @@ impl<T> MaybeUninit<T> {
// * `MaybeUninit<T>` and T are guaranteed to have the same layout
// * `MaybeUninit` does not drop, so there are no double-frees
// And thus the conversion is safe
- let ret = unsafe {
+ unsafe {
intrinsics::assert_inhabited::<[T; N]>();
- (&array as *const _ as *const [T; N]).read()
- };
-
- // FIXME: required to avoid `~const Destruct` bound
- super::forget(array);
- ret
+ intrinsics::transmute_unchecked(array)
+ }
}
/// Assuming all the elements are initialized, get a slice to them.
@@ -1291,7 +1287,7 @@ impl<T, const N: usize> MaybeUninit<[T; N]> {
#[inline]
pub const fn transpose(self) -> [MaybeUninit<T>; N] {
// SAFETY: T and MaybeUninit<T> have the same layout
- unsafe { super::transmute_copy(&ManuallyDrop::new(self)) }
+ unsafe { intrinsics::transmute_unchecked(self) }
}
}
@@ -1311,6 +1307,6 @@ impl<T, const N: usize> [MaybeUninit<T>; N] {
#[inline]
pub const fn transpose(self) -> MaybeUninit<[T; N]> {
// SAFETY: T and MaybeUninit<T> have the same layout
- unsafe { super::transmute_copy(&ManuallyDrop::new(self)) }
+ unsafe { intrinsics::transmute_unchecked(self) }
}
}
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index a67df7ed5..afbfd6d36 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -170,7 +170,7 @@ pub fn forget_unsized<T: ?Sized>(t: T) {
///
/// The following table gives the size for primitives.
///
-/// Type | size_of::\<Type>()
+/// Type | `size_of::<Type>()`
/// ---- | ---------------
/// () | 0
/// bool | 1
@@ -190,8 +190,8 @@ pub fn forget_unsized<T: ?Sized>(t: T) {
///
/// Furthermore, `usize` and `isize` have the same size.
///
-/// The types `*const T`, `&T`, `Box<T>`, `Option<&T>`, and `Option<Box<T>>` all have
-/// the same size. If `T` is Sized, all of those types have the same size as `usize`.
+/// The types [`*const T`], `&T`, [`Box<T>`], [`Option<&T>`], and `Option<Box<T>>` all have
+/// the same size. If `T` is `Sized`, all of those types have the same size as `usize`.
///
/// The mutability of a pointer does not change its size. As such, `&T` and `&mut T`
/// have the same size. Likewise for `*const T` and `*mut T`.
@@ -203,7 +203,7 @@ pub fn forget_unsized<T: ?Sized>(t: T) {
///
/// ## Size of Structs
///
-/// For `structs`, the size is determined by the following algorithm.
+/// For `struct`s, the size is determined by the following algorithm.
///
/// For each field in the struct ordered by declaration order:
///
@@ -299,6 +299,10 @@ pub fn forget_unsized<T: ?Sized>(t: T) {
/// ```
///
/// [alignment]: align_of
+/// [`*const T`]: primitive@pointer
+/// [`Box<T>`]: ../../std/boxed/struct.Box.html
+/// [`Option<&T>`]: crate::option::Option
+///
#[inline(always)]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
@@ -311,7 +315,7 @@ pub const fn size_of<T>() -> usize {
/// Returns the size of the pointed-to value in bytes.
///
-/// This is usually the same as `size_of::<T>()`. However, when `T` *has* no
+/// This is usually the same as [`size_of::<T>()`]. However, when `T` *has* no
/// statically-known size, e.g., a slice [`[T]`][slice] or a [trait object],
/// then `size_of_val` can be used to get the dynamically-known size.
///
@@ -328,6 +332,8 @@ pub const fn size_of<T>() -> usize {
/// let y: &[u8] = &x;
/// assert_eq!(13, mem::size_of_val(y));
/// ```
+///
+/// [`size_of::<T>()`]: size_of
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
@@ -340,7 +346,7 @@ pub const fn size_of_val<T: ?Sized>(val: &T) -> usize {
/// Returns the size of the pointed-to value in bytes.
///
-/// This is usually the same as `size_of::<T>()`. However, when `T` *has* no
+/// This is usually the same as [`size_of::<T>()`]. However, when `T` *has* no
/// statically-known size, e.g., a slice [`[T]`][slice] or a [trait object],
/// then `size_of_val_raw` can be used to get the dynamically-known size.
///
@@ -363,6 +369,7 @@ pub const fn size_of_val<T: ?Sized>(val: &T) -> usize {
/// [`size_of_val`] on a reference to a type with an extern type tail.
/// - otherwise, it is conservatively not allowed to call this function.
///
+/// [`size_of::<T>()`]: size_of
/// [trait object]: ../../book/ch17-02-trait-objects.html
/// [extern type]: ../../unstable-book/language-features/extern-types.html
///
@@ -961,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(dropping_copy_types))]
/// #[derive(Copy, Clone)]
/// struct Foo(u8);
///
@@ -1272,3 +1280,45 @@ pub trait SizedTypeProperties: Sized {
#[doc(hidden)]
#[unstable(feature = "sized_type_properties", issue = "none")]
impl<T> SizedTypeProperties for T {}
+
+/// Expands to the offset in bytes of a field from the beginning of the given type.
+///
+/// Only structs, unions and tuples are supported.
+///
+/// Nested field accesses may be used, but not array indexes like in `C`'s `offsetof`.
+///
+/// Note that the output of this macro is not stable, except for `#[repr(C)]` types.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(offset_of)]
+///
+/// use std::mem;
+/// #[repr(C)]
+/// struct FieldStruct {
+/// first: u8,
+/// second: u16,
+/// third: u8
+/// }
+///
+/// assert_eq!(mem::offset_of!(FieldStruct, first), 0);
+/// assert_eq!(mem::offset_of!(FieldStruct, second), 2);
+/// assert_eq!(mem::offset_of!(FieldStruct, third), 4);
+///
+/// #[repr(C)]
+/// struct NestedA {
+/// b: NestedB
+/// }
+///
+/// #[repr(C)]
+/// struct NestedB(u8);
+///
+/// assert_eq!(mem::offset_of!(NestedA, b.0), 0);
+/// ```
+#[cfg(not(bootstrap))]
+#[unstable(feature = "offset_of", issue = "106655")]
+#[allow_internal_unstable(builtin_syntax)]
+pub macro offset_of($Container:ty, $($fields:tt).+ $(,)?) {
+ builtin # offset_of($Container, $($fields).+)
+}
diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs
index b53a330fa..87ae30619 100644
--- a/library/core/src/mem/transmutability.rs
+++ b/library/core/src/mem/transmutability.rs
@@ -81,8 +81,7 @@ impl Assume {
// FIXME(jswrenn): This const op is not actually usable. Why?
// https://github.com/rust-lang/rust/pull/100726#issuecomment-1219928926
#[unstable(feature = "transmutability", issue = "99571")]
-#[rustc_const_unstable(feature = "transmutability", issue = "99571")]
-impl const core::ops::Add for Assume {
+impl core::ops::Add for Assume {
type Output = Assume;
fn add(self, other_assumptions: Assume) -> Assume {
@@ -93,8 +92,7 @@ impl const core::ops::Add for Assume {
// FIXME(jswrenn): This const op is not actually usable. Why?
// https://github.com/rust-lang/rust/pull/100726#issuecomment-1219928926
#[unstable(feature = "transmutability", issue = "99571")]
-#[rustc_const_unstable(feature = "transmutability", issue = "99571")]
-impl const core::ops::Sub for Assume {
+impl core::ops::Sub for Assume {
type Output = Assume;
fn sub(self, other_assumptions: Assume) -> Assume {
diff --git a/library/core/src/net/socket_addr.rs b/library/core/src/net/socket_addr.rs
index 2d48e2715..8396aecf9 100644
--- a/library/core/src/net/socket_addr.rs
+++ b/library/core/src/net/socket_addr.rs
@@ -122,6 +122,7 @@ impl SocketAddr {
#[stable(feature = "ip_addr", since = "1.7.0")]
#[must_use]
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+ #[inline]
pub const fn new(ip: IpAddr, port: u16) -> SocketAddr {
match ip {
IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)),
@@ -142,6 +143,7 @@ impl SocketAddr {
#[must_use]
#[stable(feature = "ip_addr", since = "1.7.0")]
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+ #[inline]
pub const fn ip(&self) -> IpAddr {
match *self {
SocketAddr::V4(ref a) => IpAddr::V4(*a.ip()),
@@ -161,6 +163,7 @@ impl SocketAddr {
/// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1)));
/// ```
#[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ #[inline]
pub fn set_ip(&mut self, new_ip: IpAddr) {
// `match (*self, new_ip)` would have us mutate a copy of self only to throw it away.
match (self, new_ip) {
@@ -183,6 +186,7 @@ impl SocketAddr {
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+ #[inline]
pub const fn port(&self) -> u16 {
match *self {
SocketAddr::V4(ref a) => a.port(),
@@ -202,6 +206,7 @@ impl SocketAddr {
/// assert_eq!(socket.port(), 1025);
/// ```
#[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ #[inline]
pub fn set_port(&mut self, new_port: u16) {
match *self {
SocketAddr::V4(ref mut a) => a.set_port(new_port),
@@ -227,6 +232,7 @@ impl SocketAddr {
#[must_use]
#[stable(feature = "sockaddr_checker", since = "1.16.0")]
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+ #[inline]
pub const fn is_ipv4(&self) -> bool {
matches!(*self, SocketAddr::V4(_))
}
@@ -249,6 +255,7 @@ impl SocketAddr {
#[must_use]
#[stable(feature = "sockaddr_checker", since = "1.16.0")]
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+ #[inline]
pub const fn is_ipv6(&self) -> bool {
matches!(*self, SocketAddr::V6(_))
}
@@ -269,6 +276,7 @@ impl SocketAddrV4 {
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use]
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+ #[inline]
pub const fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 {
SocketAddrV4 { ip, port }
}
@@ -286,6 +294,7 @@ impl SocketAddrV4 {
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+ #[inline]
pub const fn ip(&self) -> &Ipv4Addr {
&self.ip
}
@@ -302,6 +311,7 @@ impl SocketAddrV4 {
/// assert_eq!(socket.ip(), &Ipv4Addr::new(192, 168, 0, 1));
/// ```
#[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ #[inline]
pub fn set_ip(&mut self, new_ip: Ipv4Addr) {
self.ip = new_ip;
}
@@ -319,6 +329,7 @@ impl SocketAddrV4 {
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+ #[inline]
pub const fn port(&self) -> u16 {
self.port
}
@@ -335,6 +346,7 @@ impl SocketAddrV4 {
/// assert_eq!(socket.port(), 4242);
/// ```
#[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ #[inline]
pub fn set_port(&mut self, new_port: u16) {
self.port = new_port;
}
@@ -360,6 +372,7 @@ impl SocketAddrV6 {
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use]
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+ #[inline]
pub const fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> SocketAddrV6 {
SocketAddrV6 { ip, port, flowinfo, scope_id }
}
@@ -377,6 +390,7 @@ impl SocketAddrV6 {
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+ #[inline]
pub const fn ip(&self) -> &Ipv6Addr {
&self.ip
}
@@ -393,6 +407,7 @@ impl SocketAddrV6 {
/// assert_eq!(socket.ip(), &Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0));
/// ```
#[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ #[inline]
pub fn set_ip(&mut self, new_ip: Ipv6Addr) {
self.ip = new_ip;
}
@@ -410,6 +425,7 @@ impl SocketAddrV6 {
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+ #[inline]
pub const fn port(&self) -> u16 {
self.port
}
@@ -426,6 +442,7 @@ impl SocketAddrV6 {
/// assert_eq!(socket.port(), 4242);
/// ```
#[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ #[inline]
pub fn set_port(&mut self, new_port: u16) {
self.port = new_port;
}
@@ -453,6 +470,7 @@ impl SocketAddrV6 {
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+ #[inline]
pub const fn flowinfo(&self) -> u32 {
self.flowinfo
}
@@ -471,6 +489,7 @@ impl SocketAddrV6 {
/// assert_eq!(socket.flowinfo(), 56);
/// ```
#[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ #[inline]
pub fn set_flowinfo(&mut self, new_flowinfo: u32) {
self.flowinfo = new_flowinfo;
}
@@ -493,6 +512,7 @@ impl SocketAddrV6 {
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+ #[inline]
pub const fn scope_id(&self) -> u32 {
self.scope_id
}
@@ -511,6 +531,7 @@ impl SocketAddrV6 {
/// assert_eq!(socket.scope_id(), 42);
/// ```
#[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ #[inline]
pub fn set_scope_id(&mut self, new_scope_id: u32) {
self.scope_id = new_scope_id;
}
@@ -519,6 +540,7 @@ impl SocketAddrV6 {
#[stable(feature = "ip_from_ip", since = "1.16.0")]
impl From<SocketAddrV4> for SocketAddr {
/// Converts a [`SocketAddrV4`] into a [`SocketAddr::V4`].
+ #[inline]
fn from(sock4: SocketAddrV4) -> SocketAddr {
SocketAddr::V4(sock4)
}
@@ -527,6 +549,7 @@ impl From<SocketAddrV4> for SocketAddr {
#[stable(feature = "ip_from_ip", since = "1.16.0")]
impl From<SocketAddrV6> for SocketAddr {
/// Converts a [`SocketAddrV6`] into a [`SocketAddr::V6`].
+ #[inline]
fn from(sock6: SocketAddrV6) -> SocketAddr {
SocketAddr::V6(sock6)
}
@@ -624,6 +647,7 @@ impl fmt::Debug for SocketAddrV6 {
#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
impl PartialOrd for SocketAddrV4 {
+ #[inline]
fn partial_cmp(&self, other: &SocketAddrV4) -> Option<Ordering> {
Some(self.cmp(other))
}
@@ -631,6 +655,7 @@ impl PartialOrd for SocketAddrV4 {
#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
impl PartialOrd for SocketAddrV6 {
+ #[inline]
fn partial_cmp(&self, other: &SocketAddrV6) -> Option<Ordering> {
Some(self.cmp(other))
}
@@ -638,6 +663,7 @@ impl PartialOrd for SocketAddrV6 {
#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
impl Ord for SocketAddrV4 {
+ #[inline]
fn cmp(&self, other: &SocketAddrV4) -> Ordering {
self.ip().cmp(other.ip()).then(self.port().cmp(&other.port()))
}
@@ -645,6 +671,7 @@ impl Ord for SocketAddrV4 {
#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
impl Ord for SocketAddrV6 {
+ #[inline]
fn cmp(&self, other: &SocketAddrV6) -> Ordering {
self.ip().cmp(other.ip()).then(self.port().cmp(&other.port()))
}
diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs
index 1bae4efe7..14e99578a 100644
--- a/library/core/src/num/error.rs
+++ b/library/core/src/num/error.rs
@@ -26,15 +26,15 @@ impl Error for TryFromIntError {
}
#[stable(feature = "try_from", since = "1.34.0")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl const From<Infallible> for TryFromIntError {
+impl From<Infallible> for TryFromIntError {
fn from(x: Infallible) -> TryFromIntError {
match x {}
}
}
#[unstable(feature = "never_type", issue = "35121")]
-impl const From<!> for TryFromIntError {
+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 1c6819b54..4a035ad61 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 1e7387217..3aafc435f 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/flt2dec/strategy/grisu.rs b/library/core/src/num/flt2dec/strategy/grisu.rs
index ed3e0edaf..b9f0d114c 100644
--- a/library/core/src/num/flt2dec/strategy/grisu.rs
+++ b/library/core/src/num/flt2dec/strategy/grisu.rs
@@ -487,6 +487,22 @@ pub fn format_exact_opt<'a>(
let vint = (v.f >> e) as u32;
let vfrac = v.f & ((1 << e) - 1);
+ let requested_digits = buf.len();
+
+ const POW10_UP_TO_9: [u32; 10] =
+ [1, 10, 100, 1000, 10_000, 100_000, 1_000_000, 10_000_000, 100_000_000, 1_000_000_000];
+
+ // We deviate from the original algorithm here and do some early checks to determine if we can satisfy requested_digits.
+ // If we determine that we can't, we exit early and avoid most of the heavy lifting that the algorithm otherwise does.
+ //
+ // When vfrac is zero, we can easily determine if vint can satisfy requested digits:
+ // If requested_digits >= 11, vint is not able to exhaust the count by itself since 10^(11 -1) > u32 max value >= vint.
+ // If vint < 10^(requested_digits - 1), vint cannot exhaust the count.
+ // Otherwise, vint might be able to exhaust the count and we need to execute the rest of the code.
+ if (vfrac == 0) && ((requested_digits >= 11) || (vint < POW10_UP_TO_9[requested_digits - 1])) {
+ return None;
+ }
+
// both old `v` and new `v` (scaled by `10^-k`) has an error of < 1 ulp (Theorem 5.1).
// as we don't know the error is positive or negative, we use two approximations
// spaced equally and have the maximal error of 2 ulps (same to the shortest case).
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index aec15212d..1199d09b5 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -785,7 +785,7 @@ macro_rules! int_impl {
// SAFETY: the caller must uphold the safety contract for
// `unchecked_shl`.
// Any legal shift amount is losslessly representable in the self type.
- unsafe { intrinsics::unchecked_shl(self, rhs.try_into().ok().unwrap_unchecked()) }
+ unsafe { intrinsics::unchecked_shl(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
}
/// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
@@ -833,7 +833,7 @@ macro_rules! int_impl {
// SAFETY: the caller must uphold the safety contract for
// `unchecked_shr`.
// Any legal shift amount is losslessly representable in the self type.
- unsafe { intrinsics::unchecked_shr(self, rhs.try_into().ok().unwrap_unchecked()) }
+ unsafe { intrinsics::unchecked_shr(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
}
/// Checked absolute value. Computes `self.abs()`, returning `None` if
@@ -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.
///
@@ -2603,13 +2641,16 @@ macro_rules! int_impl {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline(always)]
- #[rustc_allow_const_fn_unstable(const_cmp)]
pub const fn signum(self) -> Self {
// Picking the right way to phrase this is complicated
// (<https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign>)
// so delegate it to `Ord` which is already producing -1/0/+1
// exactly like we need and can be the place to deal with the complexity.
- self.cmp(&0) as _
+
+ // FIXME(const-hack): replace with cmp
+ if self < 0 { -1 }
+ else if self == 0 { 0 }
+ else { 1 }
}
/// Returns `true` if `self` is positive and `false` if the number is zero or
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 9b812bbfc..c9baa09f4 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.
@@ -225,6 +276,23 @@ macro_rules! widening_impl {
};
}
+macro_rules! conv_rhs_for_unchecked_shift {
+ ($SelfT:ty, $x:expr) => {{
+ #[inline]
+ fn conv(x: u32) -> $SelfT {
+ // FIXME(const-hack) replace with `.try_into().ok().unwrap_unchecked()`.
+ // SAFETY: Any legal shift amount must be losslessly representable in the self type.
+ unsafe { x.try_into().ok().unwrap_unchecked() }
+ }
+ #[inline]
+ const fn const_conv(x: u32) -> $SelfT {
+ x as _
+ }
+
+ intrinsics::const_eval_select(($x,), const_conv, conv)
+ }};
+}
+
impl i8 {
int_impl! {
Self = i8,
@@ -438,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.
///
@@ -455,7 +524,16 @@ impl u8 {
#[rustc_const_stable(feature = "const_u8_is_ascii", since = "1.43.0")]
#[inline]
pub const fn is_ascii(&self) -> bool {
- *self & 128 == 0
+ *self <= 127
+ }
+
+ /// If the value of this byte is within the ASCII range, returns it as an
+ /// [ASCII character](ascii::Char). Otherwise, returns `None`.
+ #[must_use]
+ #[unstable(feature = "ascii_char", issue = "110998")]
+ #[inline]
+ pub const fn as_ascii(&self) -> Option<ascii::Char> {
+ ascii::Char::from_u8(*self)
}
/// Makes a copy of the value in its ASCII upper case equivalent.
@@ -1040,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`].
///
@@ -1088,6 +1167,7 @@ impl u32 {
bound_condition = "",
}
widening_impl! { u32, u64, 32, unsigned }
+ midpoint_impl! { u32, u64, unsigned }
}
impl u64 {
@@ -1111,6 +1191,7 @@ impl u64 {
bound_condition = "",
}
widening_impl! { u64, u128, 64, unsigned }
+ midpoint_impl! { u64, u128, unsigned }
}
impl u128 {
@@ -1135,6 +1216,7 @@ impl u128 {
from_xe_bytes_doc = "",
bound_condition = "",
}
+ midpoint_impl! { u128, unsigned }
}
#[cfg(target_pointer_width = "16")]
@@ -1159,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")]
@@ -1183,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")]
@@ -1207,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 49d23abee..7f06e170a 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -1,7 +1,7 @@
//! Definitions of integer that is known not to equal zero.
use crate::fmt;
-use crate::ops::{BitOr, BitOrAssign, Div, Rem};
+use crate::ops::{BitOr, BitOrAssign, Div, Neg, Rem};
use crate::str::FromStr;
use super::from_str_radix;
@@ -96,8 +96,7 @@ macro_rules! nonzero_integers {
}
#[stable(feature = "from_nonzero", since = "1.31.0")]
- #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")]
- impl const From<$Ty> for $Int {
+ impl From<$Ty> for $Int {
#[doc = concat!("Converts a `", stringify!($Ty), "` into an `", stringify!($Int), "`")]
#[inline]
fn from(nonzero: $Ty) -> Self {
@@ -106,8 +105,7 @@ macro_rules! nonzero_integers {
}
#[stable(feature = "nonzero_bitor", since = "1.45.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const BitOr for $Ty {
+ impl BitOr for $Ty {
type Output = Self;
#[inline]
fn bitor(self, rhs: Self) -> Self::Output {
@@ -118,8 +116,7 @@ macro_rules! nonzero_integers {
}
#[stable(feature = "nonzero_bitor", since = "1.45.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const BitOr<$Int> for $Ty {
+ impl BitOr<$Int> for $Ty {
type Output = Self;
#[inline]
fn bitor(self, rhs: $Int) -> Self::Output {
@@ -131,8 +128,7 @@ macro_rules! nonzero_integers {
}
#[stable(feature = "nonzero_bitor", since = "1.45.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const BitOr<$Ty> for $Int {
+ impl BitOr<$Ty> for $Int {
type Output = $Ty;
#[inline]
fn bitor(self, rhs: $Ty) -> Self::Output {
@@ -144,8 +140,7 @@ macro_rules! nonzero_integers {
}
#[stable(feature = "nonzero_bitor", since = "1.45.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const BitOrAssign for $Ty {
+ impl BitOrAssign for $Ty {
#[inline]
fn bitor_assign(&mut self, rhs: Self) {
*self = *self | rhs;
@@ -153,8 +148,7 @@ macro_rules! nonzero_integers {
}
#[stable(feature = "nonzero_bitor", since = "1.45.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const BitOrAssign<$Int> for $Ty {
+ impl BitOrAssign<$Int> for $Ty {
#[inline]
fn bitor_assign(&mut self, rhs: $Int) {
*self = *self | rhs;
@@ -276,8 +270,7 @@ macro_rules! nonzero_integers_div {
( $( $Ty: ident($Int: ty); )+ ) => {
$(
#[stable(feature = "nonzero_div", since = "1.51.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const Div<$Ty> for $Int {
+ impl Div<$Ty> for $Int {
type Output = $Int;
/// This operation rounds towards zero,
/// truncating any fractional part of the exact result, and cannot panic.
@@ -290,8 +283,7 @@ macro_rules! nonzero_integers_div {
}
#[stable(feature = "nonzero_div", since = "1.51.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const Rem<$Ty> for $Int {
+ impl Rem<$Ty> for $Int {
type Output = $Int;
/// This operation satisfies `n % d == n - (n / d) * d`, and cannot panic.
#[inline]
@@ -501,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())) }
+ }
}
)+
}
@@ -672,8 +701,7 @@ macro_rules! nonzero_signed_operations {
/// assert_eq!(pos, pos.wrapping_abs());
/// assert_eq!(pos, neg.wrapping_abs());
/// assert_eq!(min, min.wrapping_abs());
- /// # // FIXME: add once Neg is implemented?
- /// # // assert_eq!(max, (-max).wrapping_abs());
+ /// assert_eq!(max, (-max).wrapping_abs());
/// # Some(())
/// # }
/// ```
@@ -722,14 +750,37 @@ macro_rules! nonzero_signed_operations {
unsafe { $Uty::new_unchecked(self.get().unsigned_abs()) }
}
+ /// Returns `true` if `self` is positive and `false` if the
+ /// number is negative.
+ ///
+ /// # Example
+ ///
+ /// ```
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")]
+ #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")]
+ ///
+ /// assert!(pos_five.is_positive());
+ /// assert!(!neg_five.is_positive());
+ /// # Some(())
+ /// # }
+ /// ```
+ #[must_use]
+ #[inline]
+ #[stable(feature = "nonzero_negation_ops", since = "1.71.0")]
+ #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")]
+ pub const fn is_positive(self) -> bool {
+ self.get().is_positive()
+ }
+
/// Returns `true` if `self` is negative and `false` if the
/// number is positive.
///
/// # Example
///
/// ```
- /// #![feature(nonzero_negation_ops)]
- ///
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
@@ -743,7 +794,8 @@ macro_rules! nonzero_signed_operations {
/// ```
#[must_use]
#[inline]
- #[unstable(feature = "nonzero_negation_ops", issue = "102443")]
+ #[stable(feature = "nonzero_negation_ops", since = "1.71.0")]
+ #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")]
pub const fn is_negative(self) -> bool {
self.get().is_negative()
}
@@ -753,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<()> {
@@ -769,7 +819,8 @@ macro_rules! nonzero_signed_operations {
/// # }
/// ```
#[inline]
- #[unstable(feature = "nonzero_negation_ops", issue = "102443")]
+ #[stable(feature = "nonzero_negation_ops", since = "1.71.0")]
+ #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")]
pub const fn checked_neg(self) -> Option<$Ty> {
if let Some(result) = self.get().checked_neg() {
// SAFETY: negation of nonzero cannot yield zero values.
@@ -786,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<()> {
@@ -802,7 +851,8 @@ macro_rules! nonzero_signed_operations {
/// # }
/// ```
#[inline]
- #[unstable(feature = "nonzero_negation_ops", issue = "102443")]
+ #[stable(feature = "nonzero_negation_ops", since = "1.71.0")]
+ #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")]
pub const fn overflowing_neg(self) -> ($Ty, bool) {
let (result, overflow) = self.get().overflowing_neg();
// SAFETY: negation of nonzero cannot yield zero values.
@@ -815,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<()> {
@@ -836,7 +884,8 @@ macro_rules! nonzero_signed_operations {
/// # }
/// ```
#[inline]
- #[unstable(feature = "nonzero_negation_ops", issue = "102443")]
+ #[stable(feature = "nonzero_negation_ops", since = "1.71.0")]
+ #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")]
pub const fn saturating_neg(self) -> $Ty {
if let Some(result) = self.checked_neg() {
return result;
@@ -853,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<()> {
@@ -869,13 +916,28 @@ macro_rules! nonzero_signed_operations {
/// # }
/// ```
#[inline]
- #[unstable(feature = "nonzero_negation_ops", issue = "102443")]
+ #[stable(feature = "nonzero_negation_ops", since = "1.71.0")]
+ #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")]
pub const fn wrapping_neg(self) -> $Ty {
let result = self.get().wrapping_neg();
// SAFETY: negation of nonzero cannot yield zero values.
unsafe { $Ty::new_unchecked(result) }
}
}
+
+ #[stable(feature = "signed_nonzero_neg", since = "1.71.0")]
+ impl Neg for $Ty {
+ type Output = $Ty;
+
+ #[inline]
+ fn neg(self) -> $Ty {
+ // SAFETY: negation of nonzero cannot yield zero values.
+ unsafe { $Ty::new_unchecked(self.get().neg()) }
+ }
+ }
+
+ forward_ref_unop! { impl Neg, neg for $Ty,
+ #[stable(feature = "signed_nonzero_neg", since = "1.71.0")] }
)+
}
}
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 114deeea3..6f6b6dbb8 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -939,7 +939,7 @@ macro_rules! uint_impl {
// SAFETY: the caller must uphold the safety contract for
// `unchecked_shl`.
// Any legal shift amount is losslessly representable in the self type.
- unsafe { intrinsics::unchecked_shl(self, rhs.try_into().ok().unwrap_unchecked()) }
+ unsafe { intrinsics::unchecked_shl(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
}
/// Checked shift right. Computes `self >> rhs`, returning `None`
@@ -987,7 +987,7 @@ macro_rules! uint_impl {
// SAFETY: the caller must uphold the safety contract for
// `unchecked_shr`.
// Any legal shift amount is losslessly representable in the self type.
- unsafe { intrinsics::unchecked_shr(self, rhs.try_into().ok().unwrap_unchecked()) }
+ unsafe { intrinsics::unchecked_shr(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
}
/// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
diff --git a/library/core/src/num/wrapping.rs b/library/core/src/num/wrapping.rs
index 5353d900e..ed354a2e5 100644
--- a/library/core/src/num/wrapping.rs
+++ b/library/core/src/num/wrapping.rs
@@ -87,8 +87,7 @@ impl<T: fmt::UpperHex> fmt::UpperHex for Wrapping<T> {
macro_rules! sh_impl_signed {
($t:ident, $f:ident) => {
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const Shl<$f> for Wrapping<$t> {
+ impl Shl<$f> for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
@@ -100,22 +99,20 @@ macro_rules! sh_impl_signed {
}
}
}
- forward_ref_binop! { impl const Shl, shl for Wrapping<$t>, $f,
+ forward_ref_binop! { impl Shl, shl for Wrapping<$t>, $f,
#[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const ShlAssign<$f> for Wrapping<$t> {
+ impl ShlAssign<$f> for Wrapping<$t> {
#[inline]
fn shl_assign(&mut self, other: $f) {
*self = *self << other;
}
}
- forward_ref_op_assign! { impl const ShlAssign, shl_assign for Wrapping<$t>, $f }
+ forward_ref_op_assign! { impl ShlAssign, shl_assign for Wrapping<$t>, $f }
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const Shr<$f> for Wrapping<$t> {
+ impl Shr<$f> for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
@@ -127,26 +124,24 @@ macro_rules! sh_impl_signed {
}
}
}
- forward_ref_binop! { impl const Shr, shr for Wrapping<$t>, $f,
+ forward_ref_binop! { impl Shr, shr for Wrapping<$t>, $f,
#[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const ShrAssign<$f> for Wrapping<$t> {
+ impl ShrAssign<$f> for Wrapping<$t> {
#[inline]
fn shr_assign(&mut self, other: $f) {
*self = *self >> other;
}
}
- forward_ref_op_assign! { impl const ShrAssign, shr_assign for Wrapping<$t>, $f }
+ forward_ref_op_assign! { impl ShrAssign, shr_assign for Wrapping<$t>, $f }
};
}
macro_rules! sh_impl_unsigned {
($t:ident, $f:ident) => {
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const Shl<$f> for Wrapping<$t> {
+ impl Shl<$f> for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
@@ -154,22 +149,20 @@ macro_rules! sh_impl_unsigned {
Wrapping(self.0.wrapping_shl((other & self::shift_max::$t as $f) as u32))
}
}
- forward_ref_binop! { impl const Shl, shl for Wrapping<$t>, $f,
+ forward_ref_binop! { impl Shl, shl for Wrapping<$t>, $f,
#[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const ShlAssign<$f> for Wrapping<$t> {
+ impl ShlAssign<$f> for Wrapping<$t> {
#[inline]
fn shl_assign(&mut self, other: $f) {
*self = *self << other;
}
}
- forward_ref_op_assign! { impl const ShlAssign, shl_assign for Wrapping<$t>, $f }
+ forward_ref_op_assign! { impl ShlAssign, shl_assign for Wrapping<$t>, $f }
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const Shr<$f> for Wrapping<$t> {
+ impl Shr<$f> for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
@@ -177,18 +170,17 @@ macro_rules! sh_impl_unsigned {
Wrapping(self.0.wrapping_shr((other & self::shift_max::$t as $f) as u32))
}
}
- forward_ref_binop! { impl const Shr, shr for Wrapping<$t>, $f,
+ forward_ref_binop! { impl Shr, shr for Wrapping<$t>, $f,
#[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const ShrAssign<$f> for Wrapping<$t> {
+ impl ShrAssign<$f> for Wrapping<$t> {
#[inline]
fn shr_assign(&mut self, other: $f) {
*self = *self >> other;
}
}
- forward_ref_op_assign! { impl const ShrAssign, shr_assign for Wrapping<$t>, $f }
+ forward_ref_op_assign! { impl ShrAssign, shr_assign for Wrapping<$t>, $f }
};
}
@@ -217,8 +209,7 @@ sh_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
macro_rules! wrapping_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const Add for Wrapping<$t> {
+ impl Add for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
@@ -226,32 +217,29 @@ macro_rules! wrapping_impl {
Wrapping(self.0.wrapping_add(other.0))
}
}
- forward_ref_binop! { impl const Add, add for Wrapping<$t>, Wrapping<$t>,
+ forward_ref_binop! { impl Add, add for Wrapping<$t>, Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const AddAssign for Wrapping<$t> {
+ impl AddAssign for Wrapping<$t> {
#[inline]
fn add_assign(&mut self, other: Wrapping<$t>) {
*self = *self + other;
}
}
- forward_ref_op_assign! { impl const AddAssign, add_assign for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_op_assign! { impl AddAssign, add_assign for Wrapping<$t>, Wrapping<$t> }
#[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const AddAssign<$t> for Wrapping<$t> {
+ impl AddAssign<$t> for Wrapping<$t> {
#[inline]
fn add_assign(&mut self, other: $t) {
*self = *self + Wrapping(other);
}
}
- forward_ref_op_assign! { impl const AddAssign, add_assign for Wrapping<$t>, $t }
+ forward_ref_op_assign! { impl AddAssign, add_assign for Wrapping<$t>, $t }
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const Sub for Wrapping<$t> {
+ impl Sub for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
@@ -259,32 +247,29 @@ macro_rules! wrapping_impl {
Wrapping(self.0.wrapping_sub(other.0))
}
}
- forward_ref_binop! { impl const Sub, sub for Wrapping<$t>, Wrapping<$t>,
+ forward_ref_binop! { impl Sub, sub for Wrapping<$t>, Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const SubAssign for Wrapping<$t> {
+ impl SubAssign for Wrapping<$t> {
#[inline]
fn sub_assign(&mut self, other: Wrapping<$t>) {
*self = *self - other;
}
}
- forward_ref_op_assign! { impl const SubAssign, sub_assign for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_op_assign! { impl SubAssign, sub_assign for Wrapping<$t>, Wrapping<$t> }
#[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const SubAssign<$t> for Wrapping<$t> {
+ impl SubAssign<$t> for Wrapping<$t> {
#[inline]
fn sub_assign(&mut self, other: $t) {
*self = *self - Wrapping(other);
}
}
- forward_ref_op_assign! { impl const SubAssign, sub_assign for Wrapping<$t>, $t }
+ forward_ref_op_assign! { impl SubAssign, sub_assign for Wrapping<$t>, $t }
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const Mul for Wrapping<$t> {
+ impl Mul for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
@@ -296,28 +281,25 @@ macro_rules! wrapping_impl {
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const MulAssign for Wrapping<$t> {
+ impl MulAssign for Wrapping<$t> {
#[inline]
fn mul_assign(&mut self, other: Wrapping<$t>) {
*self = *self * other;
}
}
- forward_ref_op_assign! { impl const MulAssign, mul_assign for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_op_assign! { impl MulAssign, mul_assign for Wrapping<$t>, Wrapping<$t> }
#[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const MulAssign<$t> for Wrapping<$t> {
+ impl MulAssign<$t> for Wrapping<$t> {
#[inline]
fn mul_assign(&mut self, other: $t) {
*self = *self * Wrapping(other);
}
}
- forward_ref_op_assign! { impl const MulAssign, mul_assign for Wrapping<$t>, $t }
+ forward_ref_op_assign! { impl MulAssign, mul_assign for Wrapping<$t>, $t }
#[stable(feature = "wrapping_div", since = "1.3.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const Div for Wrapping<$t> {
+ impl Div for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
@@ -325,32 +307,29 @@ macro_rules! wrapping_impl {
Wrapping(self.0.wrapping_div(other.0))
}
}
- forward_ref_binop! { impl const Div, div for Wrapping<$t>, Wrapping<$t>,
+ forward_ref_binop! { impl Div, div for Wrapping<$t>, Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const DivAssign for Wrapping<$t> {
+ impl DivAssign for Wrapping<$t> {
#[inline]
fn div_assign(&mut self, other: Wrapping<$t>) {
*self = *self / other;
}
}
- forward_ref_op_assign! { impl const DivAssign, div_assign for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_op_assign! { impl DivAssign, div_assign for Wrapping<$t>, Wrapping<$t> }
#[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const DivAssign<$t> for Wrapping<$t> {
+ impl DivAssign<$t> for Wrapping<$t> {
#[inline]
fn div_assign(&mut self, other: $t) {
*self = *self / Wrapping(other);
}
}
- forward_ref_op_assign! { impl const DivAssign, div_assign for Wrapping<$t>, $t }
+ forward_ref_op_assign! { impl DivAssign, div_assign for Wrapping<$t>, $t }
#[stable(feature = "wrapping_impls", since = "1.7.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const Rem for Wrapping<$t> {
+ impl Rem for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
@@ -358,32 +337,29 @@ macro_rules! wrapping_impl {
Wrapping(self.0.wrapping_rem(other.0))
}
}
- forward_ref_binop! { impl const Rem, rem for Wrapping<$t>, Wrapping<$t>,
+ forward_ref_binop! { impl Rem, rem for Wrapping<$t>, Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const RemAssign for Wrapping<$t> {
+ impl RemAssign for Wrapping<$t> {
#[inline]
fn rem_assign(&mut self, other: Wrapping<$t>) {
*self = *self % other;
}
}
- forward_ref_op_assign! { impl const RemAssign, rem_assign for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_op_assign! { impl RemAssign, rem_assign for Wrapping<$t>, Wrapping<$t> }
#[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const RemAssign<$t> for Wrapping<$t> {
+ impl RemAssign<$t> for Wrapping<$t> {
#[inline]
fn rem_assign(&mut self, other: $t) {
*self = *self % Wrapping(other);
}
}
- forward_ref_op_assign! { impl const RemAssign, rem_assign for Wrapping<$t>, $t }
+ forward_ref_op_assign! { impl RemAssign, rem_assign for Wrapping<$t>, $t }
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const Not for Wrapping<$t> {
+ impl Not for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
@@ -391,12 +367,11 @@ macro_rules! wrapping_impl {
Wrapping(!self.0)
}
}
- forward_ref_unop! { impl const Not, not for Wrapping<$t>,
+ forward_ref_unop! { impl Not, not for Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const BitXor for Wrapping<$t> {
+ impl BitXor for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
@@ -404,32 +379,29 @@ macro_rules! wrapping_impl {
Wrapping(self.0 ^ other.0)
}
}
- forward_ref_binop! { impl const BitXor, bitxor for Wrapping<$t>, Wrapping<$t>,
+ forward_ref_binop! { impl BitXor, bitxor for Wrapping<$t>, Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const BitXorAssign for Wrapping<$t> {
+ impl BitXorAssign for Wrapping<$t> {
#[inline]
fn bitxor_assign(&mut self, other: Wrapping<$t>) {
*self = *self ^ other;
}
}
- forward_ref_op_assign! { impl const BitXorAssign, bitxor_assign for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Wrapping<$t>, Wrapping<$t> }
#[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const BitXorAssign<$t> for Wrapping<$t> {
+ impl BitXorAssign<$t> for Wrapping<$t> {
#[inline]
fn bitxor_assign(&mut self, other: $t) {
*self = *self ^ Wrapping(other);
}
}
- forward_ref_op_assign! { impl const BitXorAssign, bitxor_assign for Wrapping<$t>, $t }
+ forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Wrapping<$t>, $t }
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const BitOr for Wrapping<$t> {
+ impl BitOr for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
@@ -437,32 +409,29 @@ macro_rules! wrapping_impl {
Wrapping(self.0 | other.0)
}
}
- forward_ref_binop! { impl const BitOr, bitor for Wrapping<$t>, Wrapping<$t>,
+ forward_ref_binop! { impl BitOr, bitor for Wrapping<$t>, Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const BitOrAssign for Wrapping<$t> {
+ impl BitOrAssign for Wrapping<$t> {
#[inline]
fn bitor_assign(&mut self, other: Wrapping<$t>) {
*self = *self | other;
}
}
- forward_ref_op_assign! { impl const BitOrAssign, bitor_assign for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Wrapping<$t>, Wrapping<$t> }
#[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const BitOrAssign<$t> for Wrapping<$t> {
+ impl BitOrAssign<$t> for Wrapping<$t> {
#[inline]
fn bitor_assign(&mut self, other: $t) {
*self = *self | Wrapping(other);
}
}
- forward_ref_op_assign! { impl const BitOrAssign, bitor_assign for Wrapping<$t>, $t }
+ forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Wrapping<$t>, $t }
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const BitAnd for Wrapping<$t> {
+ impl BitAnd for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
@@ -470,39 +439,36 @@ macro_rules! wrapping_impl {
Wrapping(self.0 & other.0)
}
}
- forward_ref_binop! { impl const BitAnd, bitand for Wrapping<$t>, Wrapping<$t>,
+ forward_ref_binop! { impl BitAnd, bitand for Wrapping<$t>, Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const BitAndAssign for Wrapping<$t> {
+ impl BitAndAssign for Wrapping<$t> {
#[inline]
fn bitand_assign(&mut self, other: Wrapping<$t>) {
*self = *self & other;
}
}
- forward_ref_op_assign! { impl const BitAndAssign, bitand_assign for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Wrapping<$t>, Wrapping<$t> }
#[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const BitAndAssign<$t> for Wrapping<$t> {
+ impl BitAndAssign<$t> for Wrapping<$t> {
#[inline]
fn bitand_assign(&mut self, other: $t) {
*self = *self & Wrapping(other);
}
}
- forward_ref_op_assign! { impl const BitAndAssign, bitand_assign for Wrapping<$t>, $t }
+ forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Wrapping<$t>, $t }
#[stable(feature = "wrapping_neg", since = "1.10.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const Neg for Wrapping<$t> {
+ impl Neg for Wrapping<$t> {
type Output = Self;
#[inline]
fn neg(self) -> Self {
Wrapping(0) - self
}
}
- forward_ref_unop! { impl const Neg, neg for Wrapping<$t>,
+ forward_ref_unop! { impl Neg, neg for Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
)*)
diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs
index 0c7ee9630..840c8cd2f 100644
--- a/library/core/src/ops/arith.rs
+++ b/library/core/src/ops/arith.rs
@@ -73,7 +73,6 @@
append_const_msg
)]
#[doc(alias = "+")]
-#[const_trait]
pub trait Add<Rhs = Self> {
/// The resulting type after applying the `+` operator.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -95,8 +94,7 @@ pub trait Add<Rhs = Self> {
macro_rules! add_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const Add for $t {
+ impl Add for $t {
type Output = $t;
#[inline]
@@ -104,7 +102,7 @@ macro_rules! add_impl {
fn add(self, other: $t) -> $t { self + other }
}
- forward_ref_binop! { impl const Add, add for $t, $t }
+ forward_ref_binop! { impl Add, add for $t, $t }
)*)
}
@@ -183,7 +181,6 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
append_const_msg
)]
#[doc(alias = "-")]
-#[const_trait]
pub trait Sub<Rhs = Self> {
/// The resulting type after applying the `-` operator.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -205,8 +202,7 @@ pub trait Sub<Rhs = Self> {
macro_rules! sub_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const Sub for $t {
+ impl Sub for $t {
type Output = $t;
#[inline]
@@ -214,7 +210,7 @@ macro_rules! sub_impl {
fn sub(self, other: $t) -> $t { self - other }
}
- forward_ref_binop! { impl const Sub, sub for $t, $t }
+ forward_ref_binop! { impl Sub, sub for $t, $t }
)*)
}
@@ -314,7 +310,6 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
label = "no implementation for `{Self} * {Rhs}`"
)]
#[doc(alias = "*")]
-#[const_trait]
pub trait Mul<Rhs = Self> {
/// The resulting type after applying the `*` operator.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -336,8 +331,7 @@ pub trait Mul<Rhs = Self> {
macro_rules! mul_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const Mul for $t {
+ impl Mul for $t {
type Output = $t;
#[inline]
@@ -345,7 +339,7 @@ macro_rules! mul_impl {
fn mul(self, other: $t) -> $t { self * other }
}
- forward_ref_binop! { impl const Mul, mul for $t, $t }
+ forward_ref_binop! { impl Mul, mul for $t, $t }
)*)
}
@@ -449,7 +443,6 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
label = "no implementation for `{Self} / {Rhs}`"
)]
#[doc(alias = "/")]
-#[const_trait]
pub trait Div<Rhs = Self> {
/// The resulting type after applying the `/` operator.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -477,15 +470,14 @@ macro_rules! div_impl_integer {
///
#[doc = $panic]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const Div for $t {
+ impl Div for $t {
type Output = $t;
#[inline]
fn div(self, other: $t) -> $t { self / other }
}
- forward_ref_binop! { impl const Div, div for $t, $t }
+ forward_ref_binop! { impl Div, div for $t, $t }
)*)*)
}
@@ -497,15 +489,14 @@ div_impl_integer! {
macro_rules! div_impl_float {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const Div for $t {
+ impl Div for $t {
type Output = $t;
#[inline]
fn div(self, other: $t) -> $t { self / other }
}
- forward_ref_binop! { impl const Div, div for $t, $t }
+ forward_ref_binop! { impl Div, div for $t, $t }
)*)
}
@@ -526,7 +517,7 @@ div_impl_float! { f32 f64 }
/// use std::ops::Rem;
///
/// #[derive(PartialEq, Debug)]
-/// struct SplitSlice<'a, T: 'a> {
+/// struct SplitSlice<'a, T> {
/// slice: &'a [T],
/// }
///
@@ -553,7 +544,6 @@ div_impl_float! { f32 f64 }
label = "no implementation for `{Self} % {Rhs}`"
)]
#[doc(alias = "%")]
-#[const_trait]
pub trait Rem<Rhs = Self> {
/// The resulting type after applying the `%` operator.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -581,15 +571,14 @@ macro_rules! rem_impl_integer {
///
#[doc = $panic]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const Rem for $t {
+ impl Rem for $t {
type Output = $t;
#[inline]
fn rem(self, other: $t) -> $t { self % other }
}
- forward_ref_binop! { impl const Rem, rem for $t, $t }
+ forward_ref_binop! { impl Rem, rem for $t, $t }
)*)*)
}
@@ -616,15 +605,14 @@ macro_rules! rem_impl_float {
/// assert_eq!(x % y, remainder);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const Rem for $t {
+ impl Rem for $t {
type Output = $t;
#[inline]
fn rem(self, other: $t) -> $t { self % other }
}
- forward_ref_binop! { impl const Rem, rem for $t, $t }
+ forward_ref_binop! { impl Rem, rem for $t, $t }
)*)
}
@@ -669,7 +657,6 @@ rem_impl_float! { f32 f64 }
#[lang = "neg"]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(alias = "-")]
-#[const_trait]
pub trait Neg {
/// The resulting type after applying the `-` operator.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -692,8 +679,7 @@ pub trait Neg {
macro_rules! neg_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const Neg for $t {
+ impl Neg for $t {
type Output = $t;
#[inline]
@@ -701,7 +687,7 @@ macro_rules! neg_impl {
fn neg(self) -> $t { -self }
}
- forward_ref_unop! { impl const Neg, neg for $t }
+ forward_ref_unop! { impl Neg, neg for $t }
)*)
}
@@ -744,7 +730,6 @@ neg_impl! { isize i8 i16 i32 i64 i128 f32 f64 }
)]
#[doc(alias = "+")]
#[doc(alias = "+=")]
-#[const_trait]
pub trait AddAssign<Rhs = Self> {
/// Performs the `+=` operation.
///
@@ -762,14 +747,13 @@ pub trait AddAssign<Rhs = Self> {
macro_rules! add_assign_impl {
($($t:ty)+) => ($(
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const AddAssign for $t {
+ impl AddAssign for $t {
#[inline]
#[rustc_inherit_overflow_checks]
fn add_assign(&mut self, other: $t) { *self += other }
}
- forward_ref_op_assign! { impl const AddAssign, add_assign for $t, $t }
+ forward_ref_op_assign! { impl AddAssign, add_assign for $t, $t }
)+)
}
@@ -812,7 +796,6 @@ add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
)]
#[doc(alias = "-")]
#[doc(alias = "-=")]
-#[const_trait]
pub trait SubAssign<Rhs = Self> {
/// Performs the `-=` operation.
///
@@ -830,14 +813,13 @@ pub trait SubAssign<Rhs = Self> {
macro_rules! sub_assign_impl {
($($t:ty)+) => ($(
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const SubAssign for $t {
+ impl SubAssign for $t {
#[inline]
#[rustc_inherit_overflow_checks]
fn sub_assign(&mut self, other: $t) { *self -= other }
}
- forward_ref_op_assign! { impl const SubAssign, sub_assign for $t, $t }
+ forward_ref_op_assign! { impl SubAssign, sub_assign for $t, $t }
)+)
}
@@ -871,7 +853,6 @@ sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
)]
#[doc(alias = "*")]
#[doc(alias = "*=")]
-#[const_trait]
pub trait MulAssign<Rhs = Self> {
/// Performs the `*=` operation.
///
@@ -889,14 +870,13 @@ pub trait MulAssign<Rhs = Self> {
macro_rules! mul_assign_impl {
($($t:ty)+) => ($(
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const MulAssign for $t {
+ impl MulAssign for $t {
#[inline]
#[rustc_inherit_overflow_checks]
fn mul_assign(&mut self, other: $t) { *self *= other }
}
- forward_ref_op_assign! { impl const MulAssign, mul_assign for $t, $t }
+ forward_ref_op_assign! { impl MulAssign, mul_assign for $t, $t }
)+)
}
@@ -930,7 +910,6 @@ mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
)]
#[doc(alias = "/")]
#[doc(alias = "/=")]
-#[const_trait]
pub trait DivAssign<Rhs = Self> {
/// Performs the `/=` operation.
///
@@ -948,13 +927,12 @@ pub trait DivAssign<Rhs = Self> {
macro_rules! div_assign_impl {
($($t:ty)+) => ($(
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const DivAssign for $t {
+ impl DivAssign for $t {
#[inline]
fn div_assign(&mut self, other: $t) { *self /= other }
}
- forward_ref_op_assign! { impl const DivAssign, div_assign for $t, $t }
+ forward_ref_op_assign! { impl DivAssign, div_assign for $t, $t }
)+)
}
@@ -992,7 +970,6 @@ div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
)]
#[doc(alias = "%")]
#[doc(alias = "%=")]
-#[const_trait]
pub trait RemAssign<Rhs = Self> {
/// Performs the `%=` operation.
///
@@ -1010,13 +987,12 @@ pub trait RemAssign<Rhs = Self> {
macro_rules! rem_assign_impl {
($($t:ty)+) => ($(
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const RemAssign for $t {
+ impl RemAssign for $t {
#[inline]
fn rem_assign(&mut self, other: $t) { *self %= other }
}
- forward_ref_op_assign! { impl const RemAssign, rem_assign for $t, $t }
+ forward_ref_op_assign! { impl RemAssign, rem_assign for $t, $t }
)+)
}
diff --git a/library/core/src/ops/bit.rs b/library/core/src/ops/bit.rs
index 327009801..c70f4a3da 100644
--- a/library/core/src/ops/bit.rs
+++ b/library/core/src/ops/bit.rs
@@ -31,7 +31,6 @@
#[lang = "not"]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(alias = "!")]
-#[const_trait]
pub trait Not {
/// The resulting type after applying the `!` operator.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -55,23 +54,21 @@ pub trait Not {
macro_rules! not_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const Not for $t {
+ impl Not for $t {
type Output = $t;
#[inline]
fn not(self) -> $t { !self }
}
- forward_ref_unop! { impl const Not, not for $t }
+ forward_ref_unop! { impl Not, not for $t }
)*)
}
not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
#[stable(feature = "not_never", since = "1.60.0")]
-#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
-impl const Not for ! {
+impl Not for ! {
type Output = !;
#[inline]
@@ -144,7 +141,6 @@ impl const Not for ! {
message = "no implementation for `{Self} & {Rhs}`",
label = "no implementation for `{Self} & {Rhs}`"
)]
-#[const_trait]
pub trait BitAnd<Rhs = Self> {
/// The resulting type after applying the `&` operator.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -168,15 +164,14 @@ pub trait BitAnd<Rhs = Self> {
macro_rules! bitand_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const BitAnd for $t {
+ impl BitAnd for $t {
type Output = $t;
#[inline]
fn bitand(self, rhs: $t) -> $t { self & rhs }
}
- forward_ref_binop! { impl const BitAnd, bitand for $t, $t }
+ forward_ref_binop! { impl BitAnd, bitand for $t, $t }
)*)
}
@@ -246,7 +241,6 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
message = "no implementation for `{Self} | {Rhs}`",
label = "no implementation for `{Self} | {Rhs}`"
)]
-#[const_trait]
pub trait BitOr<Rhs = Self> {
/// The resulting type after applying the `|` operator.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -270,15 +264,14 @@ pub trait BitOr<Rhs = Self> {
macro_rules! bitor_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const BitOr for $t {
+ impl BitOr for $t {
type Output = $t;
#[inline]
fn bitor(self, rhs: $t) -> $t { self | rhs }
}
- forward_ref_binop! { impl const BitOr, bitor for $t, $t }
+ forward_ref_binop! { impl BitOr, bitor for $t, $t }
)*)
}
@@ -348,7 +341,6 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
message = "no implementation for `{Self} ^ {Rhs}`",
label = "no implementation for `{Self} ^ {Rhs}`"
)]
-#[const_trait]
pub trait BitXor<Rhs = Self> {
/// The resulting type after applying the `^` operator.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -372,15 +364,14 @@ pub trait BitXor<Rhs = Self> {
macro_rules! bitxor_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const BitXor for $t {
+ impl BitXor for $t {
type Output = $t;
#[inline]
fn bitxor(self, other: $t) -> $t { self ^ other }
}
- forward_ref_binop! { impl const BitXor, bitxor for $t, $t }
+ forward_ref_binop! { impl BitXor, bitxor for $t, $t }
)*)
}
@@ -449,7 +440,6 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
message = "no implementation for `{Self} << {Rhs}`",
label = "no implementation for `{Self} << {Rhs}`"
)]
-#[const_trait]
pub trait Shl<Rhs = Self> {
/// The resulting type after applying the `<<` operator.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -471,8 +461,7 @@ pub trait Shl<Rhs = Self> {
macro_rules! shl_impl {
($t:ty, $f:ty) => {
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const Shl<$f> for $t {
+ impl Shl<$f> for $t {
type Output = $t;
#[inline]
@@ -482,7 +471,7 @@ macro_rules! shl_impl {
}
}
- forward_ref_binop! { impl const Shl, shl for $t, $f }
+ forward_ref_binop! { impl Shl, shl for $t, $f }
};
}
@@ -569,7 +558,6 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 }
message = "no implementation for `{Self} >> {Rhs}`",
label = "no implementation for `{Self} >> {Rhs}`"
)]
-#[const_trait]
pub trait Shr<Rhs = Self> {
/// The resulting type after applying the `>>` operator.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -591,8 +579,7 @@ pub trait Shr<Rhs = Self> {
macro_rules! shr_impl {
($t:ty, $f:ty) => {
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const Shr<$f> for $t {
+ impl Shr<$f> for $t {
type Output = $t;
#[inline]
@@ -602,7 +589,7 @@ macro_rules! shr_impl {
}
}
- forward_ref_binop! { impl const Shr, shr for $t, $f }
+ forward_ref_binop! { impl Shr, shr for $t, $f }
};
}
@@ -698,7 +685,6 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
message = "no implementation for `{Self} &= {Rhs}`",
label = "no implementation for `{Self} &= {Rhs}`"
)]
-#[const_trait]
pub trait BitAndAssign<Rhs = Self> {
/// Performs the `&=` operation.
///
@@ -728,13 +714,12 @@ pub trait BitAndAssign<Rhs = Self> {
macro_rules! bitand_assign_impl {
($($t:ty)+) => ($(
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const BitAndAssign for $t {
+ impl BitAndAssign for $t {
#[inline]
fn bitand_assign(&mut self, other: $t) { *self &= other }
}
- forward_ref_op_assign! { impl const BitAndAssign, bitand_assign for $t, $t }
+ forward_ref_op_assign! { impl BitAndAssign, bitand_assign for $t, $t }
)+)
}
@@ -771,7 +756,6 @@ bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
message = "no implementation for `{Self} |= {Rhs}`",
label = "no implementation for `{Self} |= {Rhs}`"
)]
-#[const_trait]
pub trait BitOrAssign<Rhs = Self> {
/// Performs the `|=` operation.
///
@@ -801,13 +785,12 @@ pub trait BitOrAssign<Rhs = Self> {
macro_rules! bitor_assign_impl {
($($t:ty)+) => ($(
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const BitOrAssign for $t {
+ impl BitOrAssign for $t {
#[inline]
fn bitor_assign(&mut self, other: $t) { *self |= other }
}
- forward_ref_op_assign! { impl const BitOrAssign, bitor_assign for $t, $t }
+ forward_ref_op_assign! { impl BitOrAssign, bitor_assign for $t, $t }
)+)
}
@@ -844,7 +827,6 @@ bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
message = "no implementation for `{Self} ^= {Rhs}`",
label = "no implementation for `{Self} ^= {Rhs}`"
)]
-#[const_trait]
pub trait BitXorAssign<Rhs = Self> {
/// Performs the `^=` operation.
///
@@ -874,13 +856,12 @@ pub trait BitXorAssign<Rhs = Self> {
macro_rules! bitxor_assign_impl {
($($t:ty)+) => ($(
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const BitXorAssign for $t {
+ impl BitXorAssign for $t {
#[inline]
fn bitxor_assign(&mut self, other: $t) { *self ^= other }
}
- forward_ref_op_assign! { impl const BitXorAssign, bitxor_assign for $t, $t }
+ forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for $t, $t }
)+)
}
@@ -915,7 +896,6 @@ bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
message = "no implementation for `{Self} <<= {Rhs}`",
label = "no implementation for `{Self} <<= {Rhs}`"
)]
-#[const_trait]
pub trait ShlAssign<Rhs = Self> {
/// Performs the `<<=` operation.
///
@@ -937,8 +917,7 @@ pub trait ShlAssign<Rhs = Self> {
macro_rules! shl_assign_impl {
($t:ty, $f:ty) => {
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const ShlAssign<$f> for $t {
+ impl ShlAssign<$f> for $t {
#[inline]
#[rustc_inherit_overflow_checks]
fn shl_assign(&mut self, other: $f) {
@@ -946,7 +925,7 @@ macro_rules! shl_assign_impl {
}
}
- forward_ref_op_assign! { impl const ShlAssign, shl_assign for $t, $f }
+ forward_ref_op_assign! { impl ShlAssign, shl_assign for $t, $f }
};
}
@@ -999,7 +978,6 @@ shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
message = "no implementation for `{Self} >>= {Rhs}`",
label = "no implementation for `{Self} >>= {Rhs}`"
)]
-#[const_trait]
pub trait ShrAssign<Rhs = Self> {
/// Performs the `>>=` operation.
///
@@ -1021,8 +999,7 @@ pub trait ShrAssign<Rhs = Self> {
macro_rules! shr_assign_impl {
($t:ty, $f:ty) => {
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
- impl const ShrAssign<$f> for $t {
+ impl ShrAssign<$f> for $t {
#[inline]
#[rustc_inherit_overflow_checks]
fn shr_assign(&mut self, other: $f) {
@@ -1030,7 +1007,7 @@ macro_rules! shr_assign_impl {
}
}
- forward_ref_op_assign! { impl const ShrAssign, shr_assign for $t, $f }
+ forward_ref_op_assign! { impl ShrAssign, shr_assign for $t, $f }
};
}
diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs
index 117706fb4..e10c438ef 100644
--- a/library/core/src/ops/control_flow.rs
+++ b/library/core/src/ops/control_flow.rs
@@ -97,8 +97,7 @@ pub enum ControlFlow<B, C = ()> {
}
#[unstable(feature = "try_trait_v2", issue = "84277")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<B, C> const ops::Try for ControlFlow<B, C> {
+impl<B, C> ops::Try for ControlFlow<B, C> {
type Output = C;
type Residual = ControlFlow<B, convert::Infallible>;
@@ -117,8 +116,7 @@ impl<B, C> const ops::Try for ControlFlow<B, C> {
}
#[unstable(feature = "try_trait_v2", issue = "84277")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<B, C> const ops::FromResidual for ControlFlow<B, C> {
+impl<B, C> ops::FromResidual for ControlFlow<B, C> {
#[inline]
fn from_residual(residual: ControlFlow<B, convert::Infallible>) -> Self {
match residual {
@@ -128,8 +126,7 @@ impl<B, C> const ops::FromResidual for ControlFlow<B, C> {
}
#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
-#[rustc_const_unstable(feature = "const_try", issue = "74935")]
-impl<B, C> const ops::Residual<C> for ControlFlow<B, convert::Infallible> {
+impl<B, C> ops::Residual<C> for ControlFlow<B, convert::Infallible> {
type TryType = ControlFlow<B, C>;
}
diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs
index c67867f44..08c35b6da 100644
--- a/library/core/src/ops/deref.rs
+++ b/library/core/src/ops/deref.rs
@@ -61,7 +61,6 @@
#[doc(alias = "&*")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "Deref"]
-#[const_trait]
pub trait Deref {
/// The resulting type after dereferencing.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -77,8 +76,7 @@ pub trait Deref {
}
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_deref", issue = "88955")]
-impl<T: ?Sized> const Deref for &T {
+impl<T: ?Sized> Deref for &T {
type Target = T;
#[rustc_diagnostic_item = "noop_method_deref"]
@@ -91,8 +89,7 @@ impl<T: ?Sized> const Deref for &T {
impl<T: ?Sized> !DerefMut for &T {}
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_deref", issue = "88955")]
-impl<T: ?Sized> const Deref for &mut T {
+impl<T: ?Sized> Deref for &mut T {
type Target = T;
fn deref(&self) -> &T {
@@ -170,7 +167,6 @@ impl<T: ?Sized> const Deref for &mut T {
#[lang = "deref_mut"]
#[doc(alias = "*")]
#[stable(feature = "rust1", since = "1.0.0")]
-#[const_trait]
pub trait DerefMut: Deref {
/// Mutably dereferences the value.
#[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/ops/drop.rs b/library/core/src/ops/drop.rs
index a2c3d978c..9ebf426be 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/ops/function.rs b/library/core/src/ops/function.rs
index b7e1aee9d..67c8245f0 100644
--- a/library/core/src/ops/function.rs
+++ b/library/core/src/ops/function.rs
@@ -254,10 +254,9 @@ mod impls {
use crate::marker::Tuple;
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
- impl<A: Tuple, F: ?Sized> const Fn<A> for &F
+ impl<A: Tuple, F: ?Sized> Fn<A> for &F
where
- F: ~const Fn<A>,
+ F: Fn<A>,
{
extern "rust-call" fn call(&self, args: A) -> F::Output {
(**self).call(args)
@@ -265,10 +264,9 @@ mod impls {
}
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
- impl<A: Tuple, F: ?Sized> const FnMut<A> for &F
+ impl<A: Tuple, F: ?Sized> FnMut<A> for &F
where
- F: ~const Fn<A>,
+ F: Fn<A>,
{
extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
(**self).call(args)
@@ -276,10 +274,9 @@ mod impls {
}
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
- impl<A: Tuple, F: ?Sized> const FnOnce<A> for &F
+ impl<A: Tuple, F: ?Sized> FnOnce<A> for &F
where
- F: ~const Fn<A>,
+ F: Fn<A>,
{
type Output = F::Output;
@@ -289,10 +286,9 @@ mod impls {
}
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
- impl<A: Tuple, F: ?Sized> const FnMut<A> for &mut F
+ impl<A: Tuple, F: ?Sized> FnMut<A> for &mut F
where
- F: ~const FnMut<A>,
+ F: FnMut<A>,
{
extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
(*self).call_mut(args)
@@ -300,10 +296,9 @@ mod impls {
}
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
- impl<A: Tuple, F: ?Sized> const FnOnce<A> for &mut F
+ impl<A: Tuple, F: ?Sized> FnOnce<A> for &mut F
where
- F: ~const FnMut<A>,
+ F: FnMut<A>,
{
type Output = F::Output;
extern "rust-call" fn call_once(self, args: A) -> F::Output {
diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs
index 228efb0bc..1f1784ec9 100644
--- a/library/core/src/ops/index.rs
+++ b/library/core/src/ops/index.rs
@@ -55,10 +55,10 @@
#[doc(alias = "]")]
#[doc(alias = "[")]
#[doc(alias = "[]")]
-#[const_trait]
pub trait Index<Idx: ?Sized> {
/// The returned type after indexing.
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_diagnostic_item = "IndexOutput"]
type Output: ?Sized;
/// Performs the indexing (`container[index]`) operation.
@@ -164,8 +164,7 @@ see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#ind
#[doc(alias = "[")]
#[doc(alias = "]")]
#[doc(alias = "[]")]
-#[const_trait]
-pub trait IndexMut<Idx: ?Sized>: ~const Index<Idx> {
+pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
/// Performs the mutable indexing (`container[index]`) operation.
///
/// # Panics
diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs
index b8ab26564..ba5e6ddc7 100644
--- a/library/core/src/ops/range.rs
+++ b/library/core/src/ops/range.rs
@@ -96,7 +96,7 @@ impl<Idx: fmt::Debug> fmt::Debug for Range<Idx> {
}
}
-impl<Idx: ~const PartialOrd<Idx>> Range<Idx> {
+impl<Idx: PartialOrd<Idx>> Range<Idx> {
/// Returns `true` if `item` is contained in the range.
///
/// # Examples
@@ -116,11 +116,10 @@ impl<Idx: ~const PartialOrd<Idx>> Range<Idx> {
/// assert!(!(f32::NAN..1.0).contains(&0.5));
/// ```
#[stable(feature = "range_contains", since = "1.35.0")]
- #[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")]
- pub const fn contains<U>(&self, item: &U) -> bool
+ pub fn contains<U>(&self, item: &U) -> bool
where
- Idx: ~const PartialOrd<U>,
- U: ?Sized + ~const PartialOrd<Idx>,
+ Idx: PartialOrd<U>,
+ U: ?Sized + PartialOrd<Idx>,
{
<Self as RangeBounds<Idx>>::contains(self, item)
}
@@ -143,8 +142,7 @@ impl<Idx: ~const PartialOrd<Idx>> Range<Idx> {
/// assert!( (f32::NAN..5.0).is_empty());
/// ```
#[stable(feature = "range_is_empty", since = "1.47.0")]
- #[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")]
- pub const fn is_empty(&self) -> bool {
+ pub fn is_empty(&self) -> bool {
!(self.start < self.end)
}
}
@@ -201,7 +199,7 @@ impl<Idx: fmt::Debug> fmt::Debug for RangeFrom<Idx> {
}
}
-impl<Idx: ~const PartialOrd<Idx>> RangeFrom<Idx> {
+impl<Idx: PartialOrd<Idx>> RangeFrom<Idx> {
/// Returns `true` if `item` is contained in the range.
///
/// # Examples
@@ -216,11 +214,10 @@ impl<Idx: ~const PartialOrd<Idx>> RangeFrom<Idx> {
/// assert!(!(f32::NAN..).contains(&0.5));
/// ```
#[stable(feature = "range_contains", since = "1.35.0")]
- #[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")]
- pub const fn contains<U>(&self, item: &U) -> bool
+ pub fn contains<U>(&self, item: &U) -> bool
where
- Idx: ~const PartialOrd<U>,
- U: ?Sized + ~const PartialOrd<Idx>,
+ Idx: PartialOrd<U>,
+ U: ?Sized + PartialOrd<Idx>,
{
<Self as RangeBounds<Idx>>::contains(self, item)
}
@@ -283,7 +280,7 @@ impl<Idx: fmt::Debug> fmt::Debug for RangeTo<Idx> {
}
}
-impl<Idx: ~const PartialOrd<Idx>> RangeTo<Idx> {
+impl<Idx: PartialOrd<Idx>> RangeTo<Idx> {
/// Returns `true` if `item` is contained in the range.
///
/// # Examples
@@ -298,11 +295,10 @@ impl<Idx: ~const PartialOrd<Idx>> RangeTo<Idx> {
/// assert!(!(..f32::NAN).contains(&0.5));
/// ```
#[stable(feature = "range_contains", since = "1.35.0")]
- #[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")]
- pub const fn contains<U>(&self, item: &U) -> bool
+ pub fn contains<U>(&self, item: &U) -> bool
where
- Idx: ~const PartialOrd<U>,
- U: ?Sized + ~const PartialOrd<Idx>,
+ Idx: PartialOrd<U>,
+ U: ?Sized + PartialOrd<Idx>,
{
<Self as RangeBounds<Idx>>::contains(self, item)
}
@@ -474,7 +470,7 @@ impl<Idx: fmt::Debug> fmt::Debug for RangeInclusive<Idx> {
}
}
-impl<Idx: ~const PartialOrd<Idx>> RangeInclusive<Idx> {
+impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
/// Returns `true` if `item` is contained in the range.
///
/// # Examples
@@ -505,11 +501,10 @@ impl<Idx: ~const PartialOrd<Idx>> RangeInclusive<Idx> {
/// assert!(!r.contains(&3) && !r.contains(&5));
/// ```
#[stable(feature = "range_contains", since = "1.35.0")]
- #[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")]
- pub const fn contains<U>(&self, item: &U) -> bool
+ pub fn contains<U>(&self, item: &U) -> bool
where
- Idx: ~const PartialOrd<U>,
- U: ?Sized + ~const PartialOrd<Idx>,
+ Idx: PartialOrd<U>,
+ U: ?Sized + PartialOrd<Idx>,
{
<Self as RangeBounds<Idx>>::contains(self, item)
}
@@ -541,9 +536,8 @@ impl<Idx: ~const PartialOrd<Idx>> RangeInclusive<Idx> {
/// assert!(r.is_empty());
/// ```
#[stable(feature = "range_is_empty", since = "1.47.0")]
- #[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")]
#[inline]
- pub const fn is_empty(&self) -> bool {
+ pub fn is_empty(&self) -> bool {
self.exhausted || !(self.start <= self.end)
}
}
@@ -605,7 +599,7 @@ impl<Idx: fmt::Debug> fmt::Debug for RangeToInclusive<Idx> {
}
}
-impl<Idx: ~const PartialOrd<Idx>> RangeToInclusive<Idx> {
+impl<Idx: PartialOrd<Idx>> RangeToInclusive<Idx> {
/// Returns `true` if `item` is contained in the range.
///
/// # Examples
@@ -620,11 +614,10 @@ impl<Idx: ~const PartialOrd<Idx>> RangeToInclusive<Idx> {
/// assert!(!(..=f32::NAN).contains(&0.5));
/// ```
#[stable(feature = "range_contains", since = "1.35.0")]
- #[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")]
- pub const fn contains<U>(&self, item: &U) -> bool
+ pub fn contains<U>(&self, item: &U) -> bool
where
- Idx: ~const PartialOrd<U>,
- U: ?Sized + ~const PartialOrd<Idx>,
+ Idx: PartialOrd<U>,
+ U: ?Sized + PartialOrd<Idx>,
{
<Self as RangeBounds<Idx>>::contains(self, item)
}
@@ -765,7 +758,6 @@ impl<T: Clone> Bound<&T> {
/// `RangeBounds` is implemented by Rust's built-in range types, produced
/// by range syntax like `..`, `a..`, `..b`, `..=c`, `d..e`, or `f..=g`.
#[stable(feature = "collections_range", since = "1.28.0")]
-#[const_trait]
pub trait RangeBounds<T: ?Sized> {
/// Start index bound.
///
@@ -818,8 +810,8 @@ pub trait RangeBounds<T: ?Sized> {
#[stable(feature = "range_contains", since = "1.35.0")]
fn contains<U>(&self, item: &U) -> bool
where
- T: ~const PartialOrd<U>,
- U: ?Sized + ~const PartialOrd<T>,
+ T: PartialOrd<U>,
+ U: ?Sized + PartialOrd<T>,
{
(match self.start_bound() {
Included(start) => start <= item,
@@ -836,8 +828,7 @@ pub trait RangeBounds<T: ?Sized> {
use self::Bound::{Excluded, Included, Unbounded};
#[stable(feature = "collections_range", since = "1.28.0")]
-#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")]
-impl<T: ?Sized> const RangeBounds<T> for RangeFull {
+impl<T: ?Sized> RangeBounds<T> for RangeFull {
fn start_bound(&self) -> Bound<&T> {
Unbounded
}
@@ -847,8 +838,7 @@ impl<T: ?Sized> const RangeBounds<T> for RangeFull {
}
#[stable(feature = "collections_range", since = "1.28.0")]
-#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")]
-impl<T> const RangeBounds<T> for RangeFrom<T> {
+impl<T> RangeBounds<T> for RangeFrom<T> {
fn start_bound(&self) -> Bound<&T> {
Included(&self.start)
}
@@ -858,8 +848,7 @@ impl<T> const RangeBounds<T> for RangeFrom<T> {
}
#[stable(feature = "collections_range", since = "1.28.0")]
-#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")]
-impl<T> const RangeBounds<T> for RangeTo<T> {
+impl<T> RangeBounds<T> for RangeTo<T> {
fn start_bound(&self) -> Bound<&T> {
Unbounded
}
@@ -869,8 +858,7 @@ impl<T> const RangeBounds<T> for RangeTo<T> {
}
#[stable(feature = "collections_range", since = "1.28.0")]
-#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")]
-impl<T> const RangeBounds<T> for Range<T> {
+impl<T> RangeBounds<T> for Range<T> {
fn start_bound(&self) -> Bound<&T> {
Included(&self.start)
}
@@ -880,8 +868,7 @@ impl<T> const RangeBounds<T> for Range<T> {
}
#[stable(feature = "collections_range", since = "1.28.0")]
-#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")]
-impl<T> const RangeBounds<T> for RangeInclusive<T> {
+impl<T> RangeBounds<T> for RangeInclusive<T> {
fn start_bound(&self) -> Bound<&T> {
Included(&self.start)
}
@@ -897,8 +884,7 @@ impl<T> const RangeBounds<T> for RangeInclusive<T> {
}
#[stable(feature = "collections_range", since = "1.28.0")]
-#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")]
-impl<T> const RangeBounds<T> for RangeToInclusive<T> {
+impl<T> RangeBounds<T> for RangeToInclusive<T> {
fn start_bound(&self) -> Bound<&T> {
Unbounded
}
@@ -908,8 +894,7 @@ impl<T> const RangeBounds<T> for RangeToInclusive<T> {
}
#[stable(feature = "collections_range", since = "1.28.0")]
-#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")]
-impl<T> const RangeBounds<T> for (Bound<T>, Bound<T>) {
+impl<T> RangeBounds<T> for (Bound<T>, Bound<T>) {
fn start_bound(&self) -> Bound<&T> {
match *self {
(Included(ref start), _) => Included(start),
@@ -928,8 +913,7 @@ impl<T> const RangeBounds<T> for (Bound<T>, Bound<T>) {
}
#[stable(feature = "collections_range", since = "1.28.0")]
-#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")]
-impl<'a, T: ?Sized + 'a> const RangeBounds<T> for (Bound<&'a T>, Bound<&'a T>) {
+impl<'a, T: ?Sized + 'a> RangeBounds<T> for (Bound<&'a T>, Bound<&'a T>) {
fn start_bound(&self) -> Bound<&T> {
self.0
}
@@ -940,8 +924,7 @@ impl<'a, T: ?Sized + 'a> const RangeBounds<T> for (Bound<&'a T>, Bound<&'a T>) {
}
#[stable(feature = "collections_range", since = "1.28.0")]
-#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")]
-impl<T> const RangeBounds<T> for RangeFrom<&T> {
+impl<T> RangeBounds<T> for RangeFrom<&T> {
fn start_bound(&self) -> Bound<&T> {
Included(self.start)
}
@@ -951,8 +934,7 @@ impl<T> const RangeBounds<T> for RangeFrom<&T> {
}
#[stable(feature = "collections_range", since = "1.28.0")]
-#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")]
-impl<T> const RangeBounds<T> for RangeTo<&T> {
+impl<T> RangeBounds<T> for RangeTo<&T> {
fn start_bound(&self) -> Bound<&T> {
Unbounded
}
@@ -962,8 +944,7 @@ impl<T> const RangeBounds<T> for RangeTo<&T> {
}
#[stable(feature = "collections_range", since = "1.28.0")]
-#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")]
-impl<T> const RangeBounds<T> for Range<&T> {
+impl<T> RangeBounds<T> for Range<&T> {
fn start_bound(&self) -> Bound<&T> {
Included(self.start)
}
@@ -973,8 +954,7 @@ impl<T> const RangeBounds<T> for Range<&T> {
}
#[stable(feature = "collections_range", since = "1.28.0")]
-#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")]
-impl<T> const RangeBounds<T> for RangeInclusive<&T> {
+impl<T> RangeBounds<T> for RangeInclusive<&T> {
fn start_bound(&self) -> Bound<&T> {
Included(self.start)
}
@@ -984,8 +964,7 @@ impl<T> const RangeBounds<T> for RangeInclusive<&T> {
}
#[stable(feature = "collections_range", since = "1.28.0")]
-#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")]
-impl<T> const RangeBounds<T> for RangeToInclusive<&T> {
+impl<T> RangeBounds<T> for RangeToInclusive<&T> {
fn start_bound(&self) -> Bound<&T> {
Unbounded
}
diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs
index c254803fb..b4f69d0b2 100644
--- a/library/core/src/ops/try_trait.rs
+++ b/library/core/src/ops/try_trait.rs
@@ -128,8 +128,7 @@ use crate::ops::ControlFlow;
)]
#[doc(alias = "?")]
#[lang = "Try"]
-#[const_trait]
-pub trait Try: ~const FromResidual {
+pub trait Try: FromResidual {
/// The type of the value produced by `?` when *not* short-circuiting.
#[unstable(feature = "try_trait_v2", issue = "84277")]
type Output;
@@ -305,7 +304,6 @@ pub trait Try: ~const FromResidual {
)]
#[rustc_diagnostic_item = "FromResidual"]
#[unstable(feature = "try_trait_v2", issue = "84277")]
-#[const_trait]
pub trait FromResidual<R = <Self as Try>::Residual> {
/// Constructs the type from a compatible `Residual` type.
///
@@ -358,11 +356,10 @@ where
/// and in the other direction,
/// `<Result<Infallible, E> as Residual<T>>::TryType = Result<T, E>`.
#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
-#[const_trait]
pub trait Residual<O> {
/// The "return" type of this meta-function.
#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
- type TryType: ~const Try<Output = O, Residual = Self>;
+ type TryType: Try<Output = O, Residual = Self>;
}
#[unstable(feature = "pub_crate_should_not_need_unstable_attr", issue = "none")]
@@ -389,16 +386,14 @@ impl<T> NeverShortCircuit<T> {
}
#[inline]
- pub fn wrap_mut_2<A, B>(
- mut f: impl ~const FnMut(A, B) -> T,
- ) -> impl ~const FnMut(A, B) -> Self {
- const move |a, b| NeverShortCircuit(f(a, b))
+ pub fn wrap_mut_2<A, B>(mut f: impl FnMut(A, B) -> T) -> impl FnMut(A, B) -> Self {
+ move |a, b| NeverShortCircuit(f(a, b))
}
}
pub(crate) enum NeverShortCircuitResidual {}
-impl<T> const Try for NeverShortCircuit<T> {
+impl<T> Try for NeverShortCircuit<T> {
type Output = T;
type Residual = NeverShortCircuitResidual;
@@ -413,14 +408,14 @@ impl<T> const Try for NeverShortCircuit<T> {
}
}
-impl<T> const FromResidual for NeverShortCircuit<T> {
+impl<T> FromResidual for NeverShortCircuit<T> {
#[inline]
fn from_residual(never: NeverShortCircuitResidual) -> Self {
match never {}
}
}
-impl<T> const Residual<T> for NeverShortCircuitResidual {
+impl<T> Residual<T> for NeverShortCircuitResidual {
type TryType = NeverShortCircuit<T>;
}
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 6f7bc6ed2..ec1ef3cf4 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -547,7 +547,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
use crate::iter::{self, FromIterator, FusedIterator, TrustedLen};
-use crate::marker::Destruct;
use crate::panicking::{panic, panic_str};
use crate::pin::Pin;
use crate::{
@@ -559,7 +558,7 @@ use crate::{
/// The `Option` type. See [the module level documentation](self) for more.
#[derive(Copy, PartialOrd, Eq, Ord, Debug, Hash)]
#[rustc_diagnostic_item = "Option"]
-#[cfg_attr(not(bootstrap), lang = "Option")]
+#[lang = "Option"]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Option<T> {
/// No value.
@@ -766,13 +765,6 @@ impl<T> Option<T> {
#[must_use]
#[unstable(feature = "option_as_slice", issue = "108545")]
pub fn as_slice(&self) -> &[T] {
- #[cfg(bootstrap)]
- match self {
- Some(value) => slice::from_ref(value),
- None => &[],
- }
-
- #[cfg(not(bootstrap))]
// SAFETY: When the `Option` is `Some`, we're using the actual pointer
// to the payload, with a length of 1, so this is equivalent to
// `slice::from_ref`, and thus is safe.
@@ -833,13 +825,6 @@ impl<T> Option<T> {
#[must_use]
#[unstable(feature = "option_as_slice", issue = "108545")]
pub fn as_mut_slice(&mut self) -> &mut [T] {
- #[cfg(bootstrap)]
- match self {
- Some(value) => slice::from_mut(value),
- None => &mut [],
- }
-
- #[cfg(not(bootstrap))]
// SAFETY: When the `Option` is `Some`, we're using the actual pointer
// to the payload, with a length of 1, so this is equivalent to
// `slice::from_mut`, and thus is safe.
@@ -967,11 +952,7 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
- pub const fn unwrap_or(self, default: T) -> T
- where
- T: ~const Destruct,
- {
+ pub fn unwrap_or(self, default: T) -> T {
match self {
Some(x) => x,
None => default,
@@ -989,11 +970,9 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
- pub const fn unwrap_or_else<F>(self, f: F) -> T
+ pub fn unwrap_or_else<F>(self, f: F) -> T
where
- F: ~const FnOnce() -> T,
- F: ~const Destruct,
+ F: FnOnce() -> T,
{
match self {
Some(x) => x,
@@ -1022,14 +1001,13 @@ impl<T> Option<T> {
/// [`FromStr`]: crate::str::FromStr
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
- pub const fn unwrap_or_default(self) -> T
+ pub fn unwrap_or_default(self) -> T
where
- T: ~const Default,
+ T: Default,
{
match self {
Some(x) => x,
- None => Default::default(),
+ None => T::default(),
}
}
@@ -1089,11 +1067,9 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
- pub const fn map<U, F>(self, f: F) -> Option<U>
+ pub fn map<U, F>(self, f: F) -> Option<U>
where
- F: ~const FnOnce(T) -> U,
- F: ~const Destruct,
+ F: FnOnce(T) -> U,
{
match self {
Some(x) => Some(f(x)),
@@ -1118,11 +1094,9 @@ impl<T> Option<T> {
/// ```
#[inline]
#[unstable(feature = "result_option_inspect", issue = "91345")]
- #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
- pub const fn inspect<F>(self, f: F) -> Self
+ pub fn inspect<F>(self, f: F) -> Self
where
- F: ~const FnOnce(&T),
- F: ~const Destruct,
+ F: FnOnce(&T),
{
if let Some(ref x) = self {
f(x);
@@ -1151,12 +1125,9 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
- pub const fn map_or<U, F>(self, default: U, f: F) -> U
+ pub fn map_or<U, F>(self, default: U, f: F) -> U
where
- F: ~const FnOnce(T) -> U,
- F: ~const Destruct,
- U: ~const Destruct,
+ F: FnOnce(T) -> U,
{
match self {
Some(t) => f(t),
@@ -1180,13 +1151,10 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
- pub const fn map_or_else<U, D, F>(self, default: D, f: F) -> U
+ pub fn map_or_else<U, D, F>(self, default: D, f: F) -> U
where
- D: ~const FnOnce() -> U,
- D: ~const Destruct,
- F: ~const FnOnce(T) -> U,
- F: ~const Destruct,
+ D: FnOnce() -> U,
+ F: FnOnce(T) -> U,
{
match self {
Some(t) => f(t),
@@ -1217,11 +1185,7 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
- pub const fn ok_or<E>(self, err: E) -> Result<T, E>
- where
- E: ~const Destruct,
- {
+ pub fn ok_or<E>(self, err: E) -> Result<T, E> {
match self {
Some(v) => Ok(v),
None => Err(err),
@@ -1246,11 +1210,9 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
- pub const fn ok_or_else<E, F>(self, err: F) -> Result<T, E>
+ pub fn ok_or_else<E, F>(self, err: F) -> Result<T, E>
where
- F: ~const FnOnce() -> E,
- F: ~const Destruct,
+ F: FnOnce() -> E,
{
match self {
Some(v) => Ok(v),
@@ -1274,10 +1236,9 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "option_deref", since = "1.40.0")]
- #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
- pub const fn as_deref(&self) -> Option<&T::Target>
+ pub fn as_deref(&self) -> Option<&T::Target>
where
- T: ~const Deref,
+ T: Deref,
{
match self.as_ref() {
Some(t) => Some(t.deref()),
@@ -1301,10 +1262,9 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "option_deref", since = "1.40.0")]
- #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
- pub const fn as_deref_mut(&mut self) -> Option<&mut T::Target>
+ pub fn as_deref_mut(&mut self) -> Option<&mut T::Target>
where
- T: ~const DerefMut,
+ T: DerefMut,
{
match self.as_mut() {
Some(t) => Some(t.deref_mut()),
@@ -1388,12 +1348,7 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
- pub const fn and<U>(self, optb: Option<U>) -> Option<U>
- where
- T: ~const Destruct,
- U: ~const Destruct,
- {
+ pub fn and<U>(self, optb: Option<U>) -> Option<U> {
match self {
Some(_) => optb,
None => None,
@@ -1430,11 +1385,9 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
- pub const fn and_then<U, F>(self, f: F) -> Option<U>
+ pub fn and_then<U, F>(self, f: F) -> Option<U>
where
- F: ~const FnOnce(T) -> Option<U>,
- F: ~const Destruct,
+ F: FnOnce(T) -> Option<U>,
{
match self {
Some(x) => f(x),
@@ -1468,12 +1421,9 @@ impl<T> Option<T> {
/// [`Some(t)`]: Some
#[inline]
#[stable(feature = "option_filter", since = "1.27.0")]
- #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
- pub const fn filter<P>(self, predicate: P) -> Self
+ pub fn filter<P>(self, predicate: P) -> Self
where
- T: ~const Destruct,
- P: ~const FnOnce(&T) -> bool,
- P: ~const Destruct,
+ P: FnOnce(&T) -> bool,
{
if let Some(x) = self {
if predicate(&x) {
@@ -1512,11 +1462,7 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
- pub const fn or(self, optb: Option<T>) -> Option<T>
- where
- T: ~const Destruct,
- {
+ pub fn or(self, optb: Option<T>) -> Option<T> {
match self {
Some(x) => Some(x),
None => optb,
@@ -1538,11 +1484,9 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
- pub const fn or_else<F>(self, f: F) -> Option<T>
+ pub fn or_else<F>(self, f: F) -> Option<T>
where
- F: ~const FnOnce() -> Option<T>,
- F: ~const Destruct,
+ F: FnOnce() -> Option<T>,
{
match self {
Some(x) => Some(x),
@@ -1573,11 +1517,7 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "option_xor", since = "1.37.0")]
- #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
- pub const fn xor(self, optb: Option<T>) -> Option<T>
- where
- T: ~const Destruct,
- {
+ pub fn xor(self, optb: Option<T>) -> Option<T> {
match (self, optb) {
(Some(a), None) => Some(a),
(None, Some(b)) => Some(b),
@@ -1611,11 +1551,7 @@ impl<T> Option<T> {
#[must_use = "if you intended to set a value, consider assignment instead"]
#[inline]
#[stable(feature = "option_insert", since = "1.53.0")]
- #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
- pub const fn insert(&mut self, value: T) -> &mut T
- where
- T: ~const Destruct,
- {
+ pub fn insert(&mut self, value: T) -> &mut T {
*self = Some(value);
// SAFETY: the code above just filled the option
@@ -1644,11 +1580,7 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "option_entry", since = "1.20.0")]
- #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
- pub const fn get_or_insert(&mut self, value: T) -> &mut T
- where
- T: ~const Destruct,
- {
+ pub fn get_or_insert(&mut self, value: T) -> &mut T {
if let None = *self {
*self = Some(value);
}
@@ -1679,16 +1611,11 @@ impl<T> Option<T> {
/// ```
#[inline]
#[unstable(feature = "option_get_or_insert_default", issue = "82901")]
- #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
- pub const fn get_or_insert_default(&mut self) -> &mut T
+ pub fn get_or_insert_default(&mut self) -> &mut T
where
- T: ~const Default,
+ T: Default,
{
- const fn default<T: ~const Default>() -> T {
- T::default()
- }
-
- self.get_or_insert_with(default)
+ self.get_or_insert_with(T::default)
}
/// Inserts a value computed from `f` into the option if it is [`None`],
@@ -1710,16 +1637,12 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "option_entry", since = "1.20.0")]
- #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
- pub const fn get_or_insert_with<F>(&mut self, f: F) -> &mut T
+ pub fn get_or_insert_with<F>(&mut self, f: F) -> &mut T
where
- F: ~const FnOnce() -> T,
- F: ~const Destruct,
+ F: FnOnce() -> T,
{
- if let None = *self {
- // the compiler isn't smart enough to know that we are not dropping a `T`
- // here and wants us to ensure `T` can be dropped at compile time.
- mem::forget(mem::replace(self, Some(f())))
+ if let None = self {
+ *self = Some(f());
}
// SAFETY: a `None` variant for `self` would have been replaced by a `Some`
@@ -1794,12 +1717,7 @@ impl<T> Option<T> {
/// assert_eq!(x.zip(z), None);
/// ```
#[stable(feature = "option_zip_option", since = "1.46.0")]
- #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
- pub const fn zip<U>(self, other: Option<U>) -> Option<(T, U)>
- where
- T: ~const Destruct,
- U: ~const Destruct,
- {
+ pub fn zip<U>(self, other: Option<U>) -> Option<(T, U)> {
match (self, other) {
(Some(a), Some(b)) => Some((a, b)),
_ => None,
@@ -1835,13 +1753,9 @@ impl<T> Option<T> {
/// assert_eq!(x.zip_with(None, Point::new), None);
/// ```
#[unstable(feature = "option_zip", issue = "70086")]
- #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
- pub const fn zip_with<U, F, R>(self, other: Option<U>, f: F) -> Option<R>
+ pub fn zip_with<U, F, R>(self, other: Option<U>, f: F) -> Option<R>
where
- F: ~const FnOnce(T, U) -> R,
- F: ~const Destruct,
- T: ~const Destruct,
- U: ~const Destruct,
+ F: FnOnce(T, U) -> R,
{
match (self, other) {
(Some(a), Some(b)) => Some(f(a, b)),
@@ -1867,12 +1781,7 @@ impl<T, U> Option<(T, U)> {
/// ```
#[inline]
#[stable(feature = "unzip_option", since = "1.66.0")]
- #[rustc_const_unstable(feature = "const_option", issue = "67441")]
- pub const fn unzip(self) -> (Option<T>, Option<U>)
- where
- T: ~const Destruct,
- U: ~const Destruct,
- {
+ pub fn unzip(self) -> (Option<T>, Option<U>) {
match self {
Some((a, b)) => (Some(a), Some(b)),
None => (None, None),
@@ -1922,10 +1831,9 @@ impl<T> Option<&T> {
/// ```
#[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_option_cloned", issue = "91582")]
- pub const fn cloned(self) -> Option<T>
+ pub fn cloned(self) -> Option<T>
where
- T: ~const Clone,
+ T: Clone,
{
match self {
Some(t) => Some(t.clone()),
@@ -1974,10 +1882,9 @@ impl<T> Option<&mut T> {
/// ```
#[must_use = "`self` will be dropped if the result is not used"]
#[stable(since = "1.26.0", feature = "option_ref_mut_cloned")]
- #[rustc_const_unstable(feature = "const_option_cloned", issue = "91582")]
- pub const fn cloned(self) -> Option<T>
+ pub fn cloned(self) -> Option<T>
where
- T: ~const Clone,
+ T: Clone,
{
match self {
Some(t) => Some(t.clone()),
@@ -2030,10 +1937,9 @@ const fn expect_failed(msg: &str) -> ! {
/////////////////////////////////////////////////////////////////////////////
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_clone", issue = "91805")]
-impl<T> const Clone for Option<T>
+impl<T> Clone for Option<T>
where
- T: ~const Clone + ~const Destruct,
+ T: Clone,
{
#[inline]
fn clone(&self) -> Self {
@@ -2053,8 +1959,7 @@ where
}
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
-impl<T> const Default for Option<T> {
+impl<T> Default for Option<T> {
/// Returns [`None`][Option::None].
///
/// # Examples
@@ -2114,8 +2019,7 @@ impl<'a, T> IntoIterator for &'a mut Option<T> {
}
#[stable(since = "1.12.0", feature = "option_from")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<T> const From<T> for Option<T> {
+impl<T> From<T> for Option<T> {
/// Moves `val` into a new [`Some`].
///
/// # Examples
@@ -2131,8 +2035,7 @@ impl<T> const From<T> for Option<T> {
}
#[stable(feature = "option_ref_from_ref_option", since = "1.30.0")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<'a, T> const From<&'a Option<T>> for Option<&'a T> {
+impl<'a, T> From<&'a Option<T>> for Option<&'a T> {
/// Converts from `&Option<T>` to `Option<&T>`.
///
/// # Examples
@@ -2159,8 +2062,7 @@ impl<'a, T> const From<&'a Option<T>> for Option<&'a T> {
}
#[stable(feature = "option_ref_from_ref_option", since = "1.30.0")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<'a, T> const From<&'a mut Option<T>> for Option<&'a mut T> {
+impl<'a, T> From<&'a mut Option<T>> for Option<&'a mut T> {
/// Converts from `&mut Option<T>` to `Option<&mut T>`
///
/// # Examples
@@ -2507,8 +2409,7 @@ impl<A, V: FromIterator<A>> FromIterator<Option<A>> for Option<V> {
}
#[unstable(feature = "try_trait_v2", issue = "84277")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<T> const ops::Try for Option<T> {
+impl<T> ops::Try for Option<T> {
type Output = T;
type Residual = Option<convert::Infallible>;
@@ -2527,8 +2428,7 @@ impl<T> const ops::Try for Option<T> {
}
#[unstable(feature = "try_trait_v2", issue = "84277")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<T> const ops::FromResidual for Option<T> {
+impl<T> ops::FromResidual for Option<T> {
#[inline]
fn from_residual(residual: Option<convert::Infallible>) -> Self {
match residual {
@@ -2546,8 +2446,7 @@ impl<T> ops::FromResidual<ops::Yeet<()>> for Option<T> {
}
#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
-#[rustc_const_unstable(feature = "const_try", issue = "74935")]
-impl<T> const ops::Residual<T> for Option<convert::Infallible> {
+impl<T> ops::Residual<T> for Option<convert::Infallible> {
type TryType = Option<T>;
}
diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs
index 8338a5d7e..20be60d35 100644
--- a/library/core/src/panic.rs
+++ b/library/core/src/panic.rs
@@ -28,16 +28,18 @@ pub macro panic_2015 {
$crate::panicking::panic($msg)
),
// Use `panic_str` instead of `panic_display::<&str>` for non_fmt_panic lint.
- ($msg:expr $(,)?) => (
- $crate::panicking::panic_str($msg)
- ),
+ ($msg:expr $(,)?) => ({
+ $crate::panicking::panic_str($msg);
+ }),
// Special-case the single-argument case for const_panic.
- ("{}", $arg:expr $(,)?) => (
- $crate::panicking::panic_display(&$arg)
- ),
- ($fmt:expr, $($arg:tt)+) => (
- $crate::panicking::panic_fmt($crate::const_format_args!($fmt, $($arg)+))
- ),
+ ("{}", $arg:expr $(,)?) => ({
+ $crate::panicking::panic_display(&$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)]
@@ -50,12 +52,14 @@ pub macro panic_2021 {
$crate::panicking::panic("explicit panic")
),
// Special-case the single-argument case for const_panic.
- ("{}", $arg:expr $(,)?) => (
- $crate::panicking::panic_display(&$arg)
- ),
- ($($t:tt)+) => (
- $crate::panicking::panic_fmt($crate::const_format_args!($($t)+))
- ),
+ ("{}", $arg:expr $(,)?) => ({
+ $crate::panicking::panic_display(&$arg);
+ }),
+ ($($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)]
@@ -69,9 +73,9 @@ pub macro unreachable_2015 {
),
// Use of `unreachable_display` for non_fmt_panic lint.
// NOTE: the message ("internal error ...") is embedded directly in unreachable_display
- ($msg:expr $(,)?) => (
- $crate::panicking::unreachable_display(&$msg)
- ),
+ ($msg:expr $(,)?) => ({
+ $crate::panicking::unreachable_display(&$msg);
+ }),
($fmt:expr, $($arg:tt)*) => (
$crate::panic!($crate::concat!("internal error: entered unreachable code: ", $fmt), $($arg)*)
),
diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs
index 06fbe083c..5576adde8 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/panicking.rs b/library/core/src/panicking.rs
index efeb726ab..81be3fb22 100644
--- a/library/core/src/panicking.rs
+++ b/library/core/src/panicking.rs
@@ -165,7 +165,7 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
#[cold]
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
#[track_caller]
-#[cfg_attr(not(bootstrap), lang = "panic_misaligned_pointer_dereference")] // needed by codegen for panic on misaligned pointer deref
+#[lang = "panic_misaligned_pointer_dereference"] // needed by codegen for panic on misaligned pointer deref
fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! {
if cfg!(feature = "panic_immediate_abort") {
super::intrinsics::abort()
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index c4b89a630..6b319b435 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -393,6 +393,8 @@ use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Receiver};
/// value in place, preventing the value referenced by that pointer from being moved
/// unless it implements [`Unpin`].
///
+/// `Pin<P>` is guaranteed to have the same memory layout and ABI as `P`.
+///
/// *See the [`pin` module] documentation for an explanation of pinning.*
///
/// [`pin` module]: self
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index 3df990e5d..8266e8990 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -1,8 +1,7 @@
// `library/{std,core}/src/primitive_docs.rs` should have the same contents.
// These are different files so that relative links work properly without
// having to have `CARGO_PKG_NAME` set, but conceptually they should always be the same.
-#[cfg_attr(bootstrap, doc(primitive = "bool"))]
-#[cfg_attr(not(bootstrap), rustc_doc_primitive = "bool")]
+#[rustc_doc_primitive = "bool"]
#[doc(alias = "true")]
#[doc(alias = "false")]
/// The boolean type.
@@ -64,8 +63,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_bool {}
-#[cfg_attr(bootstrap, doc(primitive = "never"))]
-#[cfg_attr(not(bootstrap), rustc_doc_primitive = "never")]
+#[rustc_doc_primitive = "never"]
#[doc(alias = "!")]
//
/// The `!` type, also called "never".
@@ -276,8 +274,7 @@ mod prim_bool {}
#[unstable(feature = "never_type", issue = "35121")]
mod prim_never {}
-#[cfg_attr(bootstrap, doc(primitive = "char"))]
-#[cfg_attr(not(bootstrap), rustc_doc_primitive = "char")]
+#[rustc_doc_primitive = "char"]
#[allow(rustdoc::invalid_rust_codeblocks)]
/// A character type.
///
@@ -401,8 +398,7 @@ mod prim_never {}
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_char {}
-#[cfg_attr(bootstrap, doc(primitive = "unit"))]
-#[cfg_attr(not(bootstrap), rustc_doc_primitive = "unit")]
+#[rustc_doc_primitive = "unit"]
#[doc(alias = "(")]
#[doc(alias = ")")]
#[doc(alias = "()")]
@@ -464,8 +460,7 @@ impl Copy for () {
// empty
}
-#[cfg_attr(bootstrap, doc(primitive = "pointer"))]
-#[cfg_attr(not(bootstrap), rustc_doc_primitive = "pointer")]
+#[rustc_doc_primitive = "pointer"]
#[doc(alias = "ptr")]
#[doc(alias = "*")]
#[doc(alias = "*const")]
@@ -555,6 +550,7 @@ impl Copy for () {
///
/// ```
/// # #![feature(rustc_private)]
+/// #[allow(unused_extern_crates)]
/// extern crate libc;
///
/// use std::mem;
@@ -581,8 +577,7 @@ impl Copy for () {
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_pointer {}
-#[cfg_attr(bootstrap, doc(primitive = "array"))]
-#[cfg_attr(not(bootstrap), rustc_doc_primitive = "array")]
+#[rustc_doc_primitive = "array"]
#[doc(alias = "[]")]
#[doc(alias = "[T;N]")] // unfortunately, rustdoc doesn't have fuzzy search for aliases
#[doc(alias = "[T; N]")]
@@ -616,6 +611,9 @@ mod prim_pointer {}
/// if the element type allows it. As a stopgap, trait implementations are
/// statically generated up to size 32.
///
+/// Arrays of sizes from 1 to 12 (inclusive) implement [`From<Tuple>`], where `Tuple`
+/// is a homogenous [prim@tuple] of appropriate length.
+///
/// Arrays coerce to [slices (`[T]`)][slice], so a slice method may be called on
/// an array. Indeed, this provides most of the API for working with arrays.
///
@@ -678,6 +676,13 @@ mod prim_pointer {}
/// move_away(roa);
/// ```
///
+/// Arrays can be created from homogenous tuples of appropriate length:
+///
+/// ```
+/// let tuple: (u32, u32, u32) = (1, 2, 3);
+/// let array: [u32; 3] = tuple.into();
+/// ```
+///
/// # Editions
///
/// Prior to Rust 1.53, arrays did not implement [`IntoIterator`] by value, so the method call
@@ -780,11 +785,11 @@ mod prim_pointer {}
/// [`Borrow`]: borrow::Borrow
/// [`BorrowMut`]: borrow::BorrowMut
/// [slice pattern]: ../reference/patterns.html#slice-patterns
+/// [`From<Tuple>`]: convert::From
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_array {}
-#[cfg_attr(bootstrap, doc(primitive = "slice"))]
-#[cfg_attr(not(bootstrap), rustc_doc_primitive = "slice")]
+#[rustc_doc_primitive = "slice"]
#[doc(alias = "[")]
#[doc(alias = "]")]
#[doc(alias = "[]")]
@@ -876,8 +881,7 @@ mod prim_array {}
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_slice {}
-#[cfg_attr(bootstrap, doc(primitive = "str"))]
-#[cfg_attr(not(bootstrap), rustc_doc_primitive = "str")]
+#[rustc_doc_primitive = "str"]
/// String slices.
///
/// *[See also the `std::str` module](crate::str).*
@@ -944,8 +948,7 @@ mod prim_slice {}
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_str {}
-#[cfg_attr(bootstrap, doc(primitive = "tuple"))]
-#[cfg_attr(not(bootstrap), rustc_doc_primitive = "tuple")]
+#[rustc_doc_primitive = "tuple"]
#[doc(alias = "(")]
#[doc(alias = ")")]
#[doc(alias = "()")]
@@ -1009,7 +1012,9 @@ mod prim_str {}
/// * [`Debug`]
/// * [`Default`]
/// * [`Hash`]
+/// * [`From<[T; N]>`][from]
///
+/// [from]: convert::From
/// [`Debug`]: fmt::Debug
/// [`Hash`]: hash::Hash
///
@@ -1060,6 +1065,13 @@ mod prim_str {}
/// assert_eq!(y, 5);
/// ```
///
+/// Homogenous tuples can be created from arrays of appropriate length:
+///
+/// ```
+/// let array: [u32; 3] = [1, 2, 3];
+/// let tuple: (u32, u32, u32) = array.into();
+/// ```
+///
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_tuple {}
@@ -1088,8 +1100,7 @@ impl<T: Copy> Copy for (T,) {
// empty
}
-#[cfg_attr(bootstrap, doc(primitive = "f32"))]
-#[cfg_attr(not(bootstrap), rustc_doc_primitive = "f32")]
+#[rustc_doc_primitive = "f32"]
/// A 32-bit floating point type (specifically, the "binary32" type defined in IEEE 754-2008).
///
/// This type can represent a wide range of decimal numbers, like `3.5`, `27`,
@@ -1155,8 +1166,7 @@ impl<T: Copy> Copy for (T,) {
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_f32 {}
-#[cfg_attr(bootstrap, doc(primitive = "f64"))]
-#[cfg_attr(not(bootstrap), rustc_doc_primitive = "f64")]
+#[rustc_doc_primitive = "f64"]
/// A 64-bit floating point type (specifically, the "binary64" type defined in IEEE 754-2008).
///
/// This type is very similar to [`f32`], but has increased
@@ -1171,78 +1181,67 @@ mod prim_f32 {}
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_f64 {}
-#[cfg_attr(bootstrap, doc(primitive = "i8"))]
-#[cfg_attr(not(bootstrap), rustc_doc_primitive = "i8")]
+#[rustc_doc_primitive = "i8"]
//
/// The 8-bit signed integer type.
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_i8 {}
-#[cfg_attr(bootstrap, doc(primitive = "i16"))]
-#[cfg_attr(not(bootstrap), rustc_doc_primitive = "i16")]
+#[rustc_doc_primitive = "i16"]
//
/// The 16-bit signed integer type.
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_i16 {}
-#[cfg_attr(bootstrap, doc(primitive = "i32"))]
-#[cfg_attr(not(bootstrap), rustc_doc_primitive = "i32")]
+#[rustc_doc_primitive = "i32"]
//
/// The 32-bit signed integer type.
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_i32 {}
-#[cfg_attr(bootstrap, doc(primitive = "i64"))]
-#[cfg_attr(not(bootstrap), rustc_doc_primitive = "i64")]
+#[rustc_doc_primitive = "i64"]
//
/// The 64-bit signed integer type.
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_i64 {}
-#[cfg_attr(bootstrap, doc(primitive = "i128"))]
-#[cfg_attr(not(bootstrap), rustc_doc_primitive = "i128")]
+#[rustc_doc_primitive = "i128"]
//
/// The 128-bit signed integer type.
#[stable(feature = "i128", since = "1.26.0")]
mod prim_i128 {}
-#[cfg_attr(bootstrap, doc(primitive = "u8"))]
-#[cfg_attr(not(bootstrap), rustc_doc_primitive = "u8")]
+#[rustc_doc_primitive = "u8"]
//
/// The 8-bit unsigned integer type.
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_u8 {}
-#[cfg_attr(bootstrap, doc(primitive = "u16"))]
-#[cfg_attr(not(bootstrap), rustc_doc_primitive = "u16")]
+#[rustc_doc_primitive = "u16"]
//
/// The 16-bit unsigned integer type.
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_u16 {}
-#[cfg_attr(bootstrap, doc(primitive = "u32"))]
-#[cfg_attr(not(bootstrap), rustc_doc_primitive = "u32")]
+#[rustc_doc_primitive = "u32"]
//
/// The 32-bit unsigned integer type.
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_u32 {}
-#[cfg_attr(bootstrap, doc(primitive = "u64"))]
-#[cfg_attr(not(bootstrap), rustc_doc_primitive = "u64")]
+#[rustc_doc_primitive = "u64"]
//
/// The 64-bit unsigned integer type.
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_u64 {}
-#[cfg_attr(bootstrap, doc(primitive = "u128"))]
-#[cfg_attr(not(bootstrap), rustc_doc_primitive = "u128")]
+#[rustc_doc_primitive = "u128"]
//
/// The 128-bit unsigned integer type.
#[stable(feature = "i128", since = "1.26.0")]
mod prim_u128 {}
-#[cfg_attr(bootstrap, doc(primitive = "isize"))]
-#[cfg_attr(not(bootstrap), rustc_doc_primitive = "isize")]
+#[rustc_doc_primitive = "isize"]
//
/// The pointer-sized signed integer type.
///
@@ -1252,8 +1251,7 @@ mod prim_u128 {}
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_isize {}
-#[cfg_attr(bootstrap, doc(primitive = "usize"))]
-#[cfg_attr(not(bootstrap), rustc_doc_primitive = "usize")]
+#[rustc_doc_primitive = "usize"]
//
/// The pointer-sized unsigned integer type.
///
@@ -1263,8 +1261,7 @@ mod prim_isize {}
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_usize {}
-#[cfg_attr(bootstrap, doc(primitive = "reference"))]
-#[cfg_attr(not(bootstrap), rustc_doc_primitive = "reference")]
+#[rustc_doc_primitive = "reference"]
#[doc(alias = "&")]
#[doc(alias = "&mut")]
//
@@ -1396,8 +1393,7 @@ mod prim_usize {}
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_ref {}
-#[cfg_attr(bootstrap, doc(primitive = "fn"))]
-#[cfg_attr(not(bootstrap), rustc_doc_primitive = "fn")]
+#[rustc_doc_primitive = "fn"]
//
/// Function pointers, like `fn(usize) -> bool`.
///
diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs
index efe6d4183..bbf7199ff 100644
--- a/library/core/src/ptr/alignment.rs
+++ b/library/core/src/ptr/alignment.rs
@@ -9,8 +9,7 @@ use crate::{cmp, fmt, hash, mem, num};
/// Note that particularly large alignments, while representable in this type,
/// are likely not to be supported by actual allocators and linkers.
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
-#[derive(Copy, Clone, Eq)]
-#[derive_const(PartialEq)]
+#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(transparent)]
pub struct Alignment(AlignmentEnum);
@@ -170,7 +169,7 @@ impl From<Alignment> for usize {
#[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
-impl const cmp::Ord for Alignment {
+impl cmp::Ord for Alignment {
#[inline]
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.as_nonzero().get().cmp(&other.as_nonzero().get())
@@ -179,7 +178,7 @@ impl const cmp::Ord for Alignment {
#[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
-impl const cmp::PartialOrd for Alignment {
+impl cmp::PartialOrd for Alignment {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
@@ -201,8 +200,7 @@ type AlignmentEnum = AlignmentEnum32;
#[cfg(target_pointer_width = "64")]
type AlignmentEnum = AlignmentEnum64;
-#[derive(Copy, Clone, Eq)]
-#[derive_const(PartialEq)]
+#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(u16)]
enum AlignmentEnum16 {
_Align1Shl0 = 1 << 0,
@@ -223,8 +221,7 @@ enum AlignmentEnum16 {
_Align1Shl15 = 1 << 15,
}
-#[derive(Copy, Clone, Eq)]
-#[derive_const(PartialEq)]
+#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
enum AlignmentEnum32 {
_Align1Shl0 = 1 << 0,
@@ -261,8 +258,7 @@ enum AlignmentEnum32 {
_Align1Shl31 = 1 << 31,
}
-#[derive(Copy, Clone, Eq)]
-#[derive_const(PartialEq)]
+#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(u64)]
enum AlignmentEnum64 {
_Align1Shl0 = 1 << 0,
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 839afc57f..6e1e862d3 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -132,8 +132,8 @@ impl<T: ?Sized> *const T {
/// ```
#[unstable(feature = "ptr_to_from_bits", issue = "91126")]
#[deprecated(
- since = "1.67",
- note = "replaced by the `exposed_addr` method, or update your code \
+ since = "1.67.0",
+ note = "replaced by the `expose_addr` method, or update your code \
to follow the strict provenance rules using its APIs"
)]
#[inline(always)]
@@ -161,7 +161,7 @@ impl<T: ?Sized> *const T {
/// ```
#[unstable(feature = "ptr_to_from_bits", issue = "91126")]
#[deprecated(
- since = "1.67",
+ since = "1.67.0",
note = "replaced by the `ptr::from_exposed_addr` function, or update \
your code to follow the strict provenance rules using its APIs"
)]
@@ -264,7 +264,7 @@ impl<T: ?Sized> *const T {
let dest_addr = addr as isize;
let offset = dest_addr.wrapping_sub(self_addr);
- // This is the canonical desugarring of this operation
+ // This is the canonical desugaring of this operation
self.wrapping_byte_offset(offset)
}
@@ -916,8 +916,16 @@ impl<T: ?Sized> *const T {
where
T: Sized,
{
+ #[cfg(bootstrap)]
// SAFETY: the caller must uphold the safety contract for `offset`.
- unsafe { self.offset(count as isize) }
+ unsafe {
+ self.offset(count as isize)
+ }
+ #[cfg(not(bootstrap))]
+ // SAFETY: the caller must uphold the safety contract for `offset`.
+ unsafe {
+ intrinsics::offset(self, count)
+ }
}
/// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`).
@@ -1187,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 = "1.71.0")]
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn read(self) -> T
@@ -1228,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 = "1.71.0")]
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn read_unaligned(self) -> T
@@ -1650,11 +1658,10 @@ impl<T> *const [T] {
/// }
/// ```
#[unstable(feature = "slice_ptr_get", issue = "74265")]
- #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
#[inline]
- pub const unsafe fn get_unchecked<I>(self, index: I) -> *const I::Output
+ pub unsafe fn get_unchecked<I>(self, index: I) -> *const I::Output
where
- I: ~const SliceIndex<[T]>,
+ I: SliceIndex<[T]>,
{
// SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds.
unsafe { index.get_unchecked(self) }
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 818f1a919..d0cb2f715 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -374,6 +374,7 @@ use crate::hash;
use crate::intrinsics::{
self, assert_unsafe_precondition, is_aligned_and_not_null, is_nonoverlapping,
};
+use crate::marker::FnPtr;
use crate::mem::{self, MaybeUninit};
@@ -440,10 +441,18 @@ mod mut_ptr;
///
/// * `to_drop` must be [valid] for both reads and writes.
///
-/// * `to_drop` must be properly aligned.
+/// * `to_drop` must be properly aligned, even if `T` has size 0.
///
-/// * The value `to_drop` points to must be valid for dropping, which may mean it must uphold
-/// additional invariants - this is type-dependent.
+/// * `to_drop` must be nonnull, even if `T` has size 0.
+///
+/// * The value `to_drop` points to must be valid for dropping, which may mean
+/// it must uphold additional invariants. These invariants depend on the type
+/// of the value being dropped. For instance, when dropping a Box, the box's
+/// pointer to the heap must be valid.
+///
+/// * While `drop_in_place` is executing, the only way to access parts of
+/// `to_drop` is through the `&mut self` references supplied to the
+/// `Drop::drop` methods that `drop_in_place` invokes.
///
/// Additionally, if `T` is not [`Copy`], using the pointed-to value after
/// calling `drop_in_place` can cause undefined behavior. Note that `*to_drop =
@@ -451,8 +460,6 @@ mod mut_ptr;
/// again. [`write()`] can be used to overwrite data without causing it to be
/// dropped.
///
-/// Note that even if `T` has size `0`, the pointer must be non-null and properly aligned.
-///
/// [valid]: self#safety
///
/// # Examples
@@ -1132,7 +1139,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 = "1.71.0")]
+#[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`
@@ -1167,26 +1175,7 @@ pub const unsafe fn read<T>(src: *const T) -> T {
"ptr::read requires that the pointer argument is aligned and non-null",
[T](src: *const T) => is_aligned_and_not_null(src)
);
-
- #[cfg(bootstrap)]
- {
- // We are calling the intrinsics directly to avoid function calls in the
- // generated code as `intrinsics::copy_nonoverlapping` is a wrapper function.
- extern "rust-intrinsic" {
- #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
- fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
- }
-
- // `src` cannot overlap `tmp` because `tmp` was just allocated on
- // the stack as a separate allocated object.
- let mut tmp = MaybeUninit::<T>::uninit();
- copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
- tmp.assume_init()
- }
- #[cfg(not(bootstrap))]
- {
- crate::intrinsics::read_via_copy(src)
- }
+ crate::intrinsics::read_via_copy(src)
}
}
@@ -1267,7 +1256,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 = "1.71.0")]
+#[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();
@@ -1367,13 +1357,13 @@ pub const unsafe fn read_unaligned<T>(src: *const T) -> T {
#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn write<T>(dst: *mut T, src: T) {
- // We are calling the intrinsics directly to avoid function calls in the generated code
- // as `intrinsics::copy_nonoverlapping` is a wrapper function.
- extern "rust-intrinsic" {
- #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
- #[rustc_nounwind]
- fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
- }
+ // Semantically, it would be fine for this to be implemented as a
+ // `copy_nonoverlapping` and appropriate drop suppression of `src`.
+
+ // However, implementing via that currently produces more MIR than is ideal.
+ // Using an intrinsic keeps it down to just the simple `*dst = move src` in
+ // MIR (11 statements shorter, at the time of writing), and also allows
+ // `src` to stay an SSA value in codegen_ssa, rather than a memory one.
// SAFETY: the caller must guarantee that `dst` is valid for writes.
// `dst` cannot overlap `src` because the caller has mutable access
@@ -1383,8 +1373,7 @@ pub const unsafe fn write<T>(dst: *mut T, src: T) {
"ptr::write requires that the pointer argument is aligned and non-null",
[T](dst: *mut T) => is_aligned_and_not_null(dst)
);
- copy_nonoverlapping(&src as *const T, dst, 1);
- intrinsics::forget(src);
+ intrinsics::write_via_move(dst, src)
}
}
@@ -1651,8 +1640,8 @@ pub(crate) const unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usiz
// FIXME(#75598): Direct use of these intrinsics improves codegen significantly at opt-level <=
// 1, where the method versions of these operations are not inlined.
use intrinsics::{
- cttz_nonzero, exact_div, mul_with_overflow, unchecked_rem, unchecked_shl, unchecked_shr,
- unchecked_sub, wrapping_add, wrapping_mul, wrapping_sub,
+ assume, cttz_nonzero, exact_div, mul_with_overflow, unchecked_rem, unchecked_shl,
+ unchecked_shr, unchecked_sub, wrapping_add, wrapping_mul, wrapping_sub,
};
/// Calculate multiplicative modular inverse of `x` modulo `m`.
@@ -1743,12 +1732,18 @@ pub(crate) const unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usiz
// in a branch-free way and then bitwise-OR it with whatever result the `-p mod a`
// computation produces.
+ let aligned_address = wrapping_add(addr, a_minus_one) & wrapping_sub(0, a);
+ let byte_offset = wrapping_sub(aligned_address, addr);
+ // FIXME: Remove the assume after <https://github.com/llvm/llvm-project/issues/62502>
+ // SAFETY: Masking by `-a` can only affect the low bits, and thus cannot have reduced
+ // the value by more than `a-1`, so even though the intermediate values might have
+ // wrapped, the byte_offset is always in `[0, a)`.
+ unsafe { assume(byte_offset < a) };
+
// SAFETY: `stride == 0` case has been handled by the special case above.
let addr_mod_stride = unsafe { unchecked_rem(addr, stride) };
return if addr_mod_stride == 0 {
- let aligned_address = wrapping_add(addr, a_minus_one) & wrapping_sub(0, a);
- let byte_offset = wrapping_sub(aligned_address, addr);
// SAFETY: `stride` is non-zero. This is guaranteed to divide exactly as well, because
// addr has been verified to be aligned to the original type’s alignment requirements.
unsafe { exact_div(byte_offset, stride) }
@@ -1764,7 +1759,12 @@ pub(crate) const unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usiz
// miracles, given the situations this case has to deal with.
// SAFETY: a is power-of-two hence non-zero. stride == 0 case is handled above.
- let gcdpow = unsafe { cttz_nonzero(stride).min(cttz_nonzero(a)) };
+ // FIXME(const-hack) replace with min
+ let gcdpow = unsafe {
+ let x = cttz_nonzero(stride);
+ let y = cttz_nonzero(a);
+ if x < y { x } else { y }
+ };
// SAFETY: gcdpow has an upper-bound that’s at most the number of bits in a usize.
let gcd = unsafe { unchecked_shl(1usize, gcdpow) };
// SAFETY: gcd is always greater or equal to 1.
@@ -1892,205 +1892,52 @@ pub fn hash<T: ?Sized, S: hash::Hasher>(hashee: *const T, into: &mut S) {
hashee.hash(into);
}
-#[cfg(bootstrap)]
-mod old_fn_ptr_impl {
- use super::*;
- // If this is a unary fn pointer, it adds a doc comment.
- // Otherwise, it hides the docs entirely.
- macro_rules! maybe_fnptr_doc {
- (@ #[$meta:meta] $item:item) => {
- #[doc(hidden)]
- #[$meta]
- $item
- };
- ($a:ident @ #[$meta:meta] $item:item) => {
- #[doc(fake_variadic)]
- #[doc = "This trait is implemented for function pointers with up to twelve arguments."]
- #[$meta]
- $item
- };
- ($a:ident $($rest_a:ident)+ @ #[$meta:meta] $item:item) => {
- #[doc(hidden)]
- #[$meta]
- $item
- };
- }
-
- // FIXME(strict_provenance_magic): function pointers have buggy codegen that
- // necessitates casting to a usize to get the backend to do the right thing.
- // for now I will break AVR to silence *a billion* lints. We should probably
- // have a proper "opaque function pointer type" to handle this kind of thing.
-
- // Impls for function pointers
- macro_rules! fnptr_impls_safety_abi {
- ($FnTy: ty, $($Arg: ident),*) => {
- fnptr_impls_safety_abi! { #[stable(feature = "fnptr_impls", since = "1.4.0")] $FnTy, $($Arg),* }
- };
- (@c_unwind $FnTy: ty, $($Arg: ident),*) => {
- fnptr_impls_safety_abi! { #[unstable(feature = "c_unwind", issue = "74990")] $FnTy, $($Arg),* }
- };
- (#[$meta:meta] $FnTy: ty, $($Arg: ident),*) => {
- maybe_fnptr_doc! {
- $($Arg)* @
- #[$meta]
- impl<Ret, $($Arg),*> PartialEq for $FnTy {
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- *self as usize == *other as usize
- }
- }
- }
-
- maybe_fnptr_doc! {
- $($Arg)* @
- #[$meta]
- impl<Ret, $($Arg),*> Eq for $FnTy {}
- }
-
- maybe_fnptr_doc! {
- $($Arg)* @
- #[$meta]
- impl<Ret, $($Arg),*> PartialOrd for $FnTy {
- #[inline]
- fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
- (*self as usize).partial_cmp(&(*other as usize))
- }
- }
- }
-
- maybe_fnptr_doc! {
- $($Arg)* @
- #[$meta]
- impl<Ret, $($Arg),*> Ord for $FnTy {
- #[inline]
- fn cmp(&self, other: &Self) -> Ordering {
- (*self as usize).cmp(&(*other as usize))
- }
- }
- }
-
- maybe_fnptr_doc! {
- $($Arg)* @
- #[$meta]
- impl<Ret, $($Arg),*> hash::Hash for $FnTy {
- fn hash<HH: hash::Hasher>(&self, state: &mut HH) {
- state.write_usize(*self as usize)
- }
- }
- }
-
- maybe_fnptr_doc! {
- $($Arg)* @
- #[$meta]
- impl<Ret, $($Arg),*> fmt::Pointer for $FnTy {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::pointer_fmt_inner(*self as usize, f)
- }
- }
- }
-
- maybe_fnptr_doc! {
- $($Arg)* @
- #[$meta]
- impl<Ret, $($Arg),*> fmt::Debug for $FnTy {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::pointer_fmt_inner(*self as usize, f)
- }
- }
- }
- }
- }
-
- macro_rules! fnptr_impls_args {
- ($($Arg: ident),+) => {
- fnptr_impls_safety_abi! { extern "Rust" fn($($Arg),+) -> Ret, $($Arg),+ }
- fnptr_impls_safety_abi! { extern "C" fn($($Arg),+) -> Ret, $($Arg),+ }
- fnptr_impls_safety_abi! { extern "C" fn($($Arg),+ , ...) -> Ret, $($Arg),+ }
- fnptr_impls_safety_abi! { @c_unwind extern "C-unwind" fn($($Arg),+) -> Ret, $($Arg),+ }
- fnptr_impls_safety_abi! { @c_unwind extern "C-unwind" fn($($Arg),+ , ...) -> Ret, $($Arg),+ }
- fnptr_impls_safety_abi! { unsafe extern "Rust" fn($($Arg),+) -> Ret, $($Arg),+ }
- fnptr_impls_safety_abi! { unsafe extern "C" fn($($Arg),+) -> Ret, $($Arg),+ }
- fnptr_impls_safety_abi! { unsafe extern "C" fn($($Arg),+ , ...) -> Ret, $($Arg),+ }
- fnptr_impls_safety_abi! { @c_unwind unsafe extern "C-unwind" fn($($Arg),+) -> Ret, $($Arg),+ }
- fnptr_impls_safety_abi! { @c_unwind unsafe extern "C-unwind" fn($($Arg),+ , ...) -> Ret, $($Arg),+ }
- };
- () => {
- // No variadic functions with 0 parameters
- fnptr_impls_safety_abi! { extern "Rust" fn() -> Ret, }
- fnptr_impls_safety_abi! { extern "C" fn() -> Ret, }
- fnptr_impls_safety_abi! { @c_unwind extern "C-unwind" fn() -> Ret, }
- fnptr_impls_safety_abi! { unsafe extern "Rust" fn() -> Ret, }
- fnptr_impls_safety_abi! { unsafe extern "C" fn() -> Ret, }
- fnptr_impls_safety_abi! { @c_unwind unsafe extern "C-unwind" fn() -> Ret, }
- };
+#[stable(feature = "fnptr_impls", since = "1.4.0")]
+impl<F: FnPtr> PartialEq for F {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ self.addr() == other.addr()
}
-
- fnptr_impls_args! {}
- fnptr_impls_args! { T }
- fnptr_impls_args! { A, B }
- fnptr_impls_args! { A, B, C }
- fnptr_impls_args! { A, B, C, D }
- fnptr_impls_args! { A, B, C, D, E }
- fnptr_impls_args! { A, B, C, D, E, F }
- fnptr_impls_args! { A, B, C, D, E, F, G }
- fnptr_impls_args! { A, B, C, D, E, F, G, H }
- fnptr_impls_args! { A, B, C, D, E, F, G, H, I }
- fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J }
- fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K }
- fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K, L }
}
+#[stable(feature = "fnptr_impls", since = "1.4.0")]
+impl<F: FnPtr> Eq for F {}
-#[cfg(not(bootstrap))]
-mod new_fn_ptr_impl {
- use super::*;
- use crate::marker::FnPtr;
-
- #[stable(feature = "fnptr_impls", since = "1.4.0")]
- impl<F: FnPtr> PartialEq for F {
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- self.addr() == other.addr()
- }
- }
- #[stable(feature = "fnptr_impls", since = "1.4.0")]
- impl<F: FnPtr> Eq for F {}
-
- #[stable(feature = "fnptr_impls", since = "1.4.0")]
- impl<F: FnPtr> PartialOrd for F {
- #[inline]
- fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
- self.addr().partial_cmp(&other.addr())
- }
+#[stable(feature = "fnptr_impls", since = "1.4.0")]
+impl<F: FnPtr> PartialOrd for F {
+ #[inline]
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ self.addr().partial_cmp(&other.addr())
}
- #[stable(feature = "fnptr_impls", since = "1.4.0")]
- impl<F: FnPtr> Ord for F {
- #[inline]
- fn cmp(&self, other: &Self) -> Ordering {
- self.addr().cmp(&other.addr())
- }
+}
+#[stable(feature = "fnptr_impls", since = "1.4.0")]
+impl<F: FnPtr> Ord for F {
+ #[inline]
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.addr().cmp(&other.addr())
}
+}
- #[stable(feature = "fnptr_impls", since = "1.4.0")]
- impl<F: FnPtr> hash::Hash for F {
- fn hash<HH: hash::Hasher>(&self, state: &mut HH) {
- state.write_usize(self.addr() as _)
- }
+#[stable(feature = "fnptr_impls", since = "1.4.0")]
+impl<F: FnPtr> hash::Hash for F {
+ fn hash<HH: hash::Hasher>(&self, state: &mut HH) {
+ state.write_usize(self.addr() as _)
}
+}
- #[stable(feature = "fnptr_impls", since = "1.4.0")]
- impl<F: FnPtr> fmt::Pointer for F {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::pointer_fmt_inner(self.addr() as _, f)
- }
+#[stable(feature = "fnptr_impls", since = "1.4.0")]
+impl<F: FnPtr> fmt::Pointer for F {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::pointer_fmt_inner(self.addr() as _, f)
}
+}
- #[stable(feature = "fnptr_impls", since = "1.4.0")]
- impl<F: FnPtr> fmt::Debug for F {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::pointer_fmt_inner(self.addr() as _, f)
- }
+#[stable(feature = "fnptr_impls", since = "1.4.0")]
+impl<F: FnPtr> fmt::Debug for F {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::pointer_fmt_inner(self.addr() as _, f)
}
}
+
/// Create a `const` raw pointer to a place, without creating an intermediate reference.
///
/// Creating a reference with `&`/`&mut` is only allowed if the pointer is properly aligned
@@ -2121,7 +1968,7 @@ mod new_fn_ptr_impl {
/// assert_eq!(unsafe { raw_f2.read_unaligned() }, 2);
/// ```
///
-/// See [`addr_of_mut`] for how to create a pointer to unininitialized data.
+/// See [`addr_of_mut`] for how to create a pointer to uninitialized data.
/// Doing that with `addr_of` would not make much sense since one could only
/// read the data, and that would be Undefined Behavior.
#[stable(feature = "raw_ref_macros", since = "1.51.0")]
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index ece5244e9..2fe5164c3 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -138,8 +138,8 @@ impl<T: ?Sized> *mut T {
/// ```
#[unstable(feature = "ptr_to_from_bits", issue = "91126")]
#[deprecated(
- since = "1.67",
- note = "replaced by the `exposed_addr` method, or update your code \
+ since = "1.67.0",
+ note = "replaced by the `expose_addr` method, or update your code \
to follow the strict provenance rules using its APIs"
)]
#[inline(always)]
@@ -167,7 +167,7 @@ impl<T: ?Sized> *mut T {
/// ```
#[unstable(feature = "ptr_to_from_bits", issue = "91126")]
#[deprecated(
- since = "1.67",
+ since = "1.67.0",
note = "replaced by the `ptr::from_exposed_addr_mut` function, or \
update your code to follow the strict provenance rules using its APIs"
)]
@@ -270,7 +270,7 @@ impl<T: ?Sized> *mut T {
let dest_addr = addr as isize;
let offset = dest_addr.wrapping_sub(self_addr);
- // This is the canonical desugarring of this operation
+ // This is the canonical desugaring of this operation
self.wrapping_byte_offset(offset)
}
@@ -473,10 +473,20 @@ impl<T: ?Sized> *mut T {
where
T: Sized,
{
+ #[cfg(bootstrap)]
// SAFETY: the caller must uphold the safety contract for `offset`.
// The obtained pointer is valid for writes since the caller must
// guarantee that it points to the same allocated object as `self`.
- unsafe { intrinsics::offset(self, count) as *mut T }
+ unsafe {
+ intrinsics::offset(self, count) as *mut T
+ }
+ #[cfg(not(bootstrap))]
+ // SAFETY: the caller must uphold the safety contract for `offset`.
+ // The obtained pointer is valid for writes since the caller must
+ // guarantee that it points to the same allocated object as `self`.
+ unsafe {
+ intrinsics::offset(self, count)
+ }
}
/// Calculates the offset from a pointer in bytes.
@@ -1016,8 +1026,16 @@ impl<T: ?Sized> *mut T {
where
T: Sized,
{
+ #[cfg(bootstrap)]
+ // SAFETY: the caller must uphold the safety contract for `offset`.
+ unsafe {
+ self.offset(count as isize)
+ }
+ #[cfg(not(bootstrap))]
// SAFETY: the caller must uphold the safety contract for `offset`.
- unsafe { self.offset(count as isize) }
+ unsafe {
+ intrinsics::offset(self, count)
+ }
}
/// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`).
@@ -1287,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 = "1.71.0")]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn read(self) -> T
@@ -1328,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 = "1.71.0")]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn read_unaligned(self) -> T
@@ -2036,11 +2054,10 @@ impl<T> *mut [T] {
/// }
/// ```
#[unstable(feature = "slice_ptr_get", issue = "74265")]
- #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
#[inline(always)]
- pub const unsafe fn get_unchecked_mut<I>(self, index: I) -> *mut I::Output
+ pub unsafe fn get_unchecked_mut<I>(self, index: I) -> *mut I::Output
where
- I: ~const SliceIndex<[T]>,
+ I: SliceIndex<[T]>,
{
// SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds.
unsafe { index.get_unchecked_mut(self) }
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 13f56c0ce..b492d2f07 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]> {
@@ -676,11 +689,10 @@ impl<T> NonNull<[T]> {
/// }
/// ```
#[unstable(feature = "slice_ptr_get", issue = "74265")]
- #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
#[inline]
- pub const unsafe fn get_unchecked_mut<I>(self, index: I) -> NonNull<I::Output>
+ pub unsafe fn get_unchecked_mut<I>(self, index: I) -> NonNull<I::Output>
where
- I: ~const SliceIndex<[T]>,
+ I: SliceIndex<[T]>,
{
// SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds.
// As a consequence, the resulting pointer cannot be null.
@@ -689,8 +701,7 @@ impl<T> NonNull<[T]> {
}
#[stable(feature = "nonnull", since = "1.25.0")]
-#[rustc_const_unstable(feature = "const_clone", issue = "91805")]
-impl<T: ?Sized> const Clone for NonNull<T> {
+impl<T: ?Sized> Clone for NonNull<T> {
#[inline(always)]
fn clone(&self) -> Self {
*self
@@ -756,8 +767,7 @@ impl<T: ?Sized> hash::Hash for NonNull<T> {
}
#[unstable(feature = "ptr_internals", issue = "none")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<T: ?Sized> const From<Unique<T>> for NonNull<T> {
+impl<T: ?Sized> From<Unique<T>> for NonNull<T> {
#[inline]
fn from(unique: Unique<T>) -> Self {
// SAFETY: A Unique pointer cannot be null, so the conditions for
@@ -767,8 +777,7 @@ impl<T: ?Sized> const From<Unique<T>> for NonNull<T> {
}
#[stable(feature = "nonnull", since = "1.25.0")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<T: ?Sized> const From<&mut T> for NonNull<T> {
+impl<T: ?Sized> From<&mut T> for NonNull<T> {
/// Converts a `&mut T` to a `NonNull<T>`.
///
/// This conversion is safe and infallible since references cannot be null.
@@ -780,8 +789,7 @@ impl<T: ?Sized> const From<&mut T> for NonNull<T> {
}
#[stable(feature = "nonnull", since = "1.25.0")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<T: ?Sized> const From<&T> for NonNull<T> {
+impl<T: ?Sized> From<&T> for NonNull<T> {
/// Converts a `&T` to a `NonNull<T>`.
///
/// This conversion is safe and infallible since references cannot be null.
diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs
index 64616142b..a853f15ed 100644
--- a/library/core/src/ptr/unique.rs
+++ b/library/core/src/ptr/unique.rs
@@ -70,7 +70,8 @@ impl<T: Sized> Unique<T> {
#[must_use]
#[inline]
pub const fn dangling() -> Self {
- Self::from(NonNull::dangling())
+ // FIXME(const-hack) replace with `From`
+ Unique { pointer: NonNull::dangling(), _marker: PhantomData }
}
}
@@ -134,13 +135,14 @@ impl<T: ?Sized> Unique<T> {
#[must_use = "`self` will be dropped if the result is not used"]
#[inline]
pub const fn cast<U>(self) -> Unique<U> {
- Unique::from(self.pointer.cast())
+ // FIXME(const-hack): replace with `From`
+ // SAFETY: is `NonNull`
+ unsafe { Unique::new_unchecked(self.pointer.cast().as_ptr()) }
}
}
#[unstable(feature = "ptr_internals", issue = "none")]
-#[rustc_const_unstable(feature = "const_clone", issue = "91805")]
-impl<T: ?Sized> const Clone for Unique<T> {
+impl<T: ?Sized> Clone for Unique<T> {
#[inline]
fn clone(&self) -> Self {
*self
@@ -171,7 +173,7 @@ impl<T: ?Sized> fmt::Pointer for Unique<T> {
}
#[unstable(feature = "ptr_internals", issue = "none")]
-impl<T: ?Sized> const From<&mut T> for Unique<T> {
+impl<T: ?Sized> From<&mut T> for Unique<T> {
/// Converts a `&mut T` to a `Unique<T>`.
///
/// This conversion is infallible since references cannot be null.
@@ -182,7 +184,7 @@ impl<T: ?Sized> const From<&mut T> for Unique<T> {
}
#[unstable(feature = "ptr_internals", issue = "none")]
-impl<T: ?Sized> const From<NonNull<T>> for Unique<T> {
+impl<T: ?Sized> From<NonNull<T>> for Unique<T> {
/// Converts a `NonNull<T>` to a `Unique<T>`.
///
/// This conversion is infallible since `NonNull` cannot be null.
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index c48230fb8..1ee270f4c 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -489,7 +489,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
use crate::iter::{self, FromIterator, FusedIterator, TrustedLen};
-use crate::marker::Destruct;
use crate::ops::{self, ControlFlow, Deref, DerefMut};
use crate::{convert, fmt, hint};
@@ -629,16 +628,10 @@ impl<T, E> Result<T, E> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_result_drop", issue = "92384")]
- pub const fn ok(self) -> Option<T>
- where
- E: ~const Destruct,
- {
+ pub fn ok(self) -> Option<T> {
match self {
Ok(x) => Some(x),
- // FIXME: ~const Drop doesn't quite work right yet
- #[allow(unused_variables)]
- Err(x) => None,
+ Err(_) => None,
}
}
@@ -658,15 +651,9 @@ impl<T, E> Result<T, E> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_result_drop", issue = "92384")]
- pub const fn err(self) -> Option<E>
- where
- T: ~const Destruct,
- {
+ pub fn err(self) -> Option<E> {
match self {
- // FIXME: ~const Drop doesn't quite work right yet
- #[allow(unused_variables)]
- Ok(x) => None,
+ Ok(_) => None,
Err(x) => Some(x),
}
}
@@ -1287,18 +1274,10 @@ impl<T, E> Result<T, E> {
/// assert_eq!(x.and(y), Ok("different result type"));
/// ```
#[inline]
- #[rustc_const_unstable(feature = "const_result_drop", issue = "92384")]
#[stable(feature = "rust1", since = "1.0.0")]
- pub const fn and<U>(self, res: Result<U, E>) -> Result<U, E>
- where
- T: ~const Destruct,
- U: ~const Destruct,
- E: ~const Destruct,
- {
+ pub fn and<U>(self, res: Result<U, E>) -> Result<U, E> {
match self {
- // FIXME: ~const Drop doesn't quite work right yet
- #[allow(unused_variables)]
- Ok(x) => res,
+ Ok(_) => res,
Err(e) => Err(e),
}
}
@@ -1370,19 +1349,11 @@ impl<T, E> Result<T, E> {
/// assert_eq!(x.or(y), Ok(2));
/// ```
#[inline]
- #[rustc_const_unstable(feature = "const_result_drop", issue = "92384")]
#[stable(feature = "rust1", since = "1.0.0")]
- pub const fn or<F>(self, res: Result<T, F>) -> Result<T, F>
- where
- T: ~const Destruct,
- E: ~const Destruct,
- F: ~const Destruct,
- {
+ pub fn or<F>(self, res: Result<T, F>) -> Result<T, F> {
match self {
Ok(v) => Ok(v),
- // FIXME: ~const Drop doesn't quite work right yet
- #[allow(unused_variables)]
- Err(e) => res,
+ Err(_) => res,
}
}
@@ -1430,18 +1401,11 @@ impl<T, E> Result<T, E> {
/// assert_eq!(x.unwrap_or(default), default);
/// ```
#[inline]
- #[rustc_const_unstable(feature = "const_result_drop", issue = "92384")]
#[stable(feature = "rust1", since = "1.0.0")]
- pub const fn unwrap_or(self, default: T) -> T
- where
- T: ~const Destruct,
- E: ~const Destruct,
- {
+ pub fn unwrap_or(self, default: T) -> T {
match self {
Ok(t) => t,
- // FIXME: ~const Drop doesn't quite work right yet
- #[allow(unused_variables)]
- Err(e) => default,
+ Err(_) => default,
}
}
@@ -1704,11 +1668,10 @@ fn unwrap_failed<T>(_msg: &str, _error: &T) -> ! {
/////////////////////////////////////////////////////////////////////////////
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_clone", issue = "91805")]
-impl<T, E> const Clone for Result<T, E>
+impl<T, E> Clone for Result<T, E>
where
- T: ~const Clone + ~const Destruct,
- E: ~const Clone + ~const Destruct,
+ T: Clone,
+ E: Clone,
{
#[inline]
fn clone(&self) -> Self {
@@ -1971,8 +1934,7 @@ impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E> {
}
#[unstable(feature = "try_trait_v2", issue = "84277")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<T, E> const ops::Try for Result<T, E> {
+impl<T, E> ops::Try for Result<T, E> {
type Output = T;
type Residual = Result<convert::Infallible, E>;
@@ -1991,10 +1953,7 @@ impl<T, E> const ops::Try for Result<T, E> {
}
#[unstable(feature = "try_trait_v2", issue = "84277")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<T, E, F: ~const From<E>> const ops::FromResidual<Result<convert::Infallible, E>>
- for Result<T, F>
-{
+impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Result<T, F> {
#[inline]
#[track_caller]
fn from_residual(residual: Result<convert::Infallible, E>) -> Self {
@@ -2013,7 +1972,6 @@ impl<T, E, F: From<E>> ops::FromResidual<ops::Yeet<E>> for Result<T, F> {
}
#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
-#[rustc_const_unstable(feature = "const_try", issue = "74935")]
-impl<T, E> const ops::Residual<T> for Result<convert::Infallible, E> {
+impl<T, E> ops::Residual<T> for Result<convert::Infallible, E> {
type TryType = Result<T, E>;
}
diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs
index 5e5399acc..f3311f76a 100644
--- a/library/core/src/slice/ascii.rs
+++ b/library/core/src/slice/ascii.rs
@@ -10,12 +10,43 @@ use crate::ops;
impl [u8] {
/// Checks if all bytes in this slice are within the ASCII range.
#[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ #[rustc_const_unstable(feature = "const_slice_is_ascii", issue = "111090")]
#[must_use]
#[inline]
- pub fn is_ascii(&self) -> bool {
+ pub const fn is_ascii(&self) -> bool {
is_ascii(self)
}
+ /// If this slice [`is_ascii`](Self::is_ascii), returns it as a slice of
+ /// [ASCII characters](`ascii::Char`), otherwise returns `None`.
+ #[unstable(feature = "ascii_char", issue = "110998")]
+ #[must_use]
+ #[inline]
+ pub const fn as_ascii(&self) -> Option<&[ascii::Char]> {
+ if self.is_ascii() {
+ // SAFETY: Just checked that it's ASCII
+ Some(unsafe { self.as_ascii_unchecked() })
+ } else {
+ None
+ }
+ }
+
+ /// Converts this slice of bytes into a slice of ASCII characters,
+ /// without checking whether they're valid.
+ ///
+ /// # Safety
+ ///
+ /// Every byte in the slice must be in `0..=127`, or else this is UB.
+ #[unstable(feature = "ascii_char", issue = "110998")]
+ #[must_use]
+ #[inline]
+ pub const unsafe fn as_ascii_unchecked(&self) -> &[ascii::Char] {
+ let byte_ptr: *const [u8] = self;
+ let ascii_ptr = byte_ptr as *const [ascii::Char];
+ // SAFETY: The caller promised all the bytes are ASCII
+ unsafe { &*ascii_ptr }
+ }
+
/// Checks that two slices are an ASCII case-insensitive match.
///
/// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
@@ -232,11 +263,29 @@ impl<'a> fmt::Debug for EscapeAscii<'a> {
/// Returns `true` if any byte in the word `v` is nonascii (>= 128). Snarfed
/// from `../str/mod.rs`, which does something similar for utf8 validation.
#[inline]
-fn contains_nonascii(v: usize) -> bool {
+const fn contains_nonascii(v: usize) -> bool {
const NONASCII_MASK: usize = usize::repeat_u8(0x80);
(NONASCII_MASK & v) != 0
}
+/// ASCII test *without* the chunk-at-a-time optimizations.
+///
+/// This is carefully structured to produce nice small code -- it's smaller in
+/// `-O` than what the "obvious" ways produces under `-C opt-level=s`. If you
+/// touch it, be sure to run (and update if needed) the assembly test.
+#[unstable(feature = "str_internals", issue = "none")]
+#[doc(hidden)]
+#[inline]
+pub const fn is_ascii_simple(mut bytes: &[u8]) -> bool {
+ while let [rest @ .., last] = bytes {
+ if !last.is_ascii() {
+ break;
+ }
+ bytes = rest;
+ }
+ bytes.is_empty()
+}
+
/// Optimized ASCII test that will use usize-at-a-time operations instead of
/// byte-at-a-time operations (when possible).
///
@@ -250,7 +299,7 @@ fn contains_nonascii(v: usize) -> bool {
/// If any of these loads produces something for which `contains_nonascii`
/// (above) returns true, then we know the answer is false.
#[inline]
-fn is_ascii(s: &[u8]) -> bool {
+const fn is_ascii(s: &[u8]) -> bool {
const USIZE_SIZE: usize = mem::size_of::<usize>();
let len = s.len();
@@ -262,7 +311,7 @@ fn is_ascii(s: &[u8]) -> bool {
// We also do this for architectures where `size_of::<usize>()` isn't
// sufficient alignment for `usize`, because it's a weird edge case.
if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < mem::align_of::<usize>() {
- return s.iter().all(|b| b.is_ascii());
+ return is_ascii_simple(s);
}
// We always read the first word unaligned, which means `align_offset` is
@@ -291,18 +340,26 @@ fn is_ascii(s: &[u8]) -> bool {
// Paranoia check about alignment, since we're about to do a bunch of
// unaligned loads. In practice this should be impossible barring a bug in
// `align_offset` though.
- debug_assert_eq!(word_ptr.addr() % mem::align_of::<usize>(), 0);
+ // While this method is allowed to spuriously fail in CTFE, if it doesn't
+ // have alignment information it should have given a `usize::MAX` for
+ // `align_offset` earlier, sending things through the scalar path instead of
+ // this one, so this check should pass if it's reachable.
+ debug_assert!(word_ptr.is_aligned_to(mem::align_of::<usize>()));
// Read subsequent words until the last aligned word, excluding the last
// aligned word by itself to be done in tail check later, to ensure that
// tail is always one `usize` at most to extra branch `byte_pos == len`.
while byte_pos < len - USIZE_SIZE {
- debug_assert!(
- // Sanity check that the read is in bounds
- (word_ptr.addr() + USIZE_SIZE) <= start.addr().wrapping_add(len) &&
- // And that our assumptions about `byte_pos` hold.
- (word_ptr.addr() - start.addr()) == byte_pos
- );
+ // Sanity check that the read is in bounds
+ debug_assert!(byte_pos + USIZE_SIZE <= len);
+ // And that our assumptions about `byte_pos` hold.
+ debug_assert!(matches!(
+ word_ptr.cast::<u8>().guaranteed_eq(start.wrapping_add(byte_pos)),
+ // These are from the same allocation, so will hopefully always be
+ // known to match even in CTFE, but if it refuses to compare them
+ // that's ok since it's just a debug check anyway.
+ None | Some(true),
+ ));
// SAFETY: We know `word_ptr` is properly aligned (because of
// `align_offset`), and we know that we have enough bytes between `word_ptr` and the end
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
index 353935324..6ef9f9c95 100644
--- a/library/core/src/slice/index.rs
+++ b/library/core/src/slice/index.rs
@@ -7,10 +7,9 @@ use crate::ops;
use crate::ptr;
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
-impl<T, I> const ops::Index<I> for [T]
+impl<T, I> ops::Index<I> for [T]
where
- I: ~const SliceIndex<[T]>,
+ I: SliceIndex<[T]>,
{
type Output = I::Output;
@@ -21,10 +20,9 @@ where
}
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
-impl<T, I> const ops::IndexMut<I> for [T]
+impl<T, I> ops::IndexMut<I> for [T]
where
- I: ~const SliceIndex<[T]>,
+ I: SliceIndex<[T]>,
{
#[inline]
fn index_mut(&mut self, index: I) -> &mut I::Output {
@@ -162,7 +160,6 @@ mod private_slice_index {
message = "the type `{T}` cannot be indexed by `{Self}`",
label = "slice indices are of type `usize` or ranges of `usize`"
)]
-#[const_trait]
pub unsafe trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
/// The output type returned by methods.
#[stable(feature = "slice_get_slice", since = "1.28.0")]
@@ -211,7 +208,7 @@ pub unsafe trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
-unsafe impl<T> const SliceIndex<[T]> for usize {
+unsafe impl<T> SliceIndex<[T]> for usize {
type Output = T;
#[inline]
@@ -271,7 +268,7 @@ unsafe impl<T> const SliceIndex<[T]> for usize {
/// Because `IndexRange` guarantees `start <= end`, fewer checks are needed here
/// than there are for a general `Range<usize>` (which might be `100..3`).
#[rustc_const_unstable(feature = "const_index_range_slice_index", issue = "none")]
-unsafe impl<T> const SliceIndex<[T]> for ops::IndexRange {
+unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
type Output = [T];
#[inline]
@@ -347,7 +344,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::IndexRange {
#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
-unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> {
+unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
type Output = [T];
#[inline]
@@ -428,7 +425,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> {
#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
-unsafe impl<T> const SliceIndex<[T]> for ops::RangeTo<usize> {
+unsafe impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
type Output = [T];
#[inline]
@@ -466,7 +463,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeTo<usize> {
#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
-unsafe impl<T> const SliceIndex<[T]> for ops::RangeFrom<usize> {
+unsafe impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
type Output = [T];
#[inline]
@@ -512,7 +509,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeFrom<usize> {
#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
-unsafe impl<T> const SliceIndex<[T]> for ops::RangeFull {
+unsafe impl<T> SliceIndex<[T]> for ops::RangeFull {
type Output = [T];
#[inline]
@@ -548,7 +545,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeFull {
#[stable(feature = "inclusive_range", since = "1.26.0")]
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
-unsafe impl<T> const SliceIndex<[T]> for ops::RangeInclusive<usize> {
+unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
type Output = [T];
#[inline]
@@ -592,7 +589,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeInclusive<usize> {
#[stable(feature = "inclusive_range", since = "1.26.0")]
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
-unsafe impl<T> const SliceIndex<[T]> for ops::RangeToInclusive<usize> {
+unsafe impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
type Output = [T];
#[inline]
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
index 88b84bd13..5369fe0a9 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};
@@ -60,10 +60,15 @@ impl<'a, T> IntoIterator for &'a mut [T] {
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct Iter<'a, T: 'a> {
+ /// The pointer to the next element to return, or the past-the-end location
+ /// if the iterator is empty.
+ ///
+ /// This address will be used for all ZST elements, never changed.
ptr: NonNull<T>,
- end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
- // ptr == end is a quick test for the Iterator being empty, that works
- // for both ZST and non-ZST.
+ /// For non-ZSTs, the non-null pointer to the past-the-end element.
+ ///
+ /// For ZSTs, this is `ptr::invalid(len)`.
+ end: *const T,
_marker: PhantomData<&'a T>,
}
@@ -85,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 }
}
@@ -179,10 +181,15 @@ impl<T> AsRef<[T]> for Iter<'_, T> {
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct IterMut<'a, T: 'a> {
+ /// The pointer to the next element to return, or the past-the-end location
+ /// if the iterator is empty.
+ ///
+ /// This address will be used for all ZST elements, never changed.
ptr: NonNull<T>,
- end: *mut T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
- // ptr == end is a quick test for the Iterator being empty, that works
- // for both ZST and non-ZST.
+ /// For non-ZSTs, the non-null pointer to the past-the-end element.
+ ///
+ /// For ZSTs, this is `ptr::invalid_mut(len)`.
+ end: *mut T,
_marker: PhantomData<&'a mut T>,
}
@@ -219,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 }
}
@@ -685,7 +689,7 @@ where
None
} else {
self.finished = true;
- Some(mem::replace(&mut self.v, &mut []))
+ Some(mem::take(&mut self.v))
}
}
}
@@ -749,7 +753,7 @@ where
match idx_opt {
None => self.finish(),
Some(idx) => {
- let tmp = mem::replace(&mut self.v, &mut []);
+ let tmp = mem::take(&mut self.v);
let (head, tail) = tmp.split_at_mut(idx);
self.v = head;
Some(&mut tail[1..])
@@ -830,7 +834,7 @@ where
if idx == self.v.len() {
self.finished = true;
}
- let tmp = mem::replace(&mut self.v, &mut []);
+ let tmp = mem::take(&mut self.v);
let (head, tail) = tmp.split_at_mut(idx);
self.v = tail;
Some(head)
@@ -876,7 +880,7 @@ where
if idx == 0 {
self.finished = true;
}
- let tmp = mem::replace(&mut self.v, &mut []);
+ let tmp = mem::take(&mut self.v);
let (head, tail) = tmp.split_at_mut(idx);
self.v = head;
Some(tail)
diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs
index 392752f2a..3462c0e02 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 {
- if mem::size_of::<T>() == 0 {
+ 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/memchr.rs b/library/core/src/slice/memchr.rs
index 98c8349eb..3a8b59d72 100644
--- a/library/core/src/slice/memchr.rs
+++ b/library/core/src/slice/memchr.rs
@@ -1,7 +1,6 @@
// Original implementation taken from rust-memchr.
// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
-use crate::cmp;
use crate::mem;
const LO_USIZE: usize = usize::repeat_u8(0x01);
@@ -83,8 +82,12 @@ const fn memchr_aligned(x: u8, text: &[u8]) -> Option<usize> {
let mut offset = ptr.align_offset(USIZE_BYTES);
if offset > 0 {
- offset = cmp::min(offset, len);
- if let Some(index) = memchr_naive(x, &text[..offset]) {
+ // FIXME(const-hack, fee1-dead): replace with min
+ offset = if offset < len { offset } else { len };
+ // FIXME(const-hack, fee1-dead): replace with range slicing
+ // SAFETY: offset is within bounds
+ let slice = unsafe { super::from_raw_parts(text.as_ptr(), offset) };
+ if let Some(index) = memchr_naive(x, slice) {
return Some(index);
}
}
@@ -110,7 +113,10 @@ const fn memchr_aligned(x: u8, text: &[u8]) -> Option<usize> {
// Find the byte after the point the body loop stopped.
// FIXME(const-hack): Use `?` instead.
- if let Some(i) = memchr_naive(x, &text[offset..]) { Some(offset + i) } else { None }
+ // FIXME(const-hack, fee1-dead): use range slicing
+ // SAFETY: offset is within bounds
+ let slice = unsafe { super::from_raw_parts(text.as_ptr().add(offset), text.len() - offset) };
+ if let Some(i) = memchr_naive(x, slice) { Some(offset + i) } else { None }
}
/// Returns the last index matching the byte `x` in `text`.
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index f541808a6..ea0181e35 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -42,8 +42,13 @@ mod index;
mod iter;
mod raw;
mod rotate;
+mod select;
mod specialize;
+#[unstable(feature = "str_internals", issue = "none")]
+#[doc(hidden)]
+pub use ascii::is_ascii_simple;
+
#[stable(feature = "rust1", since = "1.0.0")]
pub use iter::{Chunks, ChunksMut, Windows};
#[stable(feature = "rust1", since = "1.0.0")]
@@ -315,6 +320,264 @@ impl<T> [T] {
if let [.., last] = self { Some(last) } else { None }
}
+ /// Returns the first `N` elements of the slice, or `None` if it has fewer than `N` elements.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(slice_first_last_chunk)]
+ ///
+ /// let u = [10, 40, 30];
+ /// assert_eq!(Some(&[10, 40]), u.first_chunk::<2>());
+ ///
+ /// let v: &[i32] = &[10];
+ /// assert_eq!(None, v.first_chunk::<2>());
+ ///
+ /// let w: &[i32] = &[];
+ /// assert_eq!(Some(&[]), w.first_chunk::<0>());
+ /// ```
+ #[unstable(feature = "slice_first_last_chunk", issue = "111774")]
+ #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")]
+ #[inline]
+ pub const fn first_chunk<const N: usize>(&self) -> Option<&[T; N]> {
+ if self.len() < N {
+ None
+ } else {
+ // SAFETY: We explicitly check for the correct number of elements,
+ // and do not let the reference outlive the slice.
+ Some(unsafe { &*(self.as_ptr() as *const [T; N]) })
+ }
+ }
+
+ /// Returns a mutable reference to the first `N` elements of the slice,
+ /// or `None` if it has fewer than `N` elements.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(slice_first_last_chunk)]
+ ///
+ /// let x = &mut [0, 1, 2];
+ ///
+ /// if let Some(first) = x.first_chunk_mut::<2>() {
+ /// first[0] = 5;
+ /// first[1] = 4;
+ /// }
+ /// assert_eq!(x, &[5, 4, 2]);
+ /// ```
+ #[unstable(feature = "slice_first_last_chunk", issue = "111774")]
+ #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")]
+ #[inline]
+ pub const fn first_chunk_mut<const N: usize>(&mut self) -> Option<&mut [T; N]> {
+ if self.len() < N {
+ None
+ } else {
+ // SAFETY: We explicitly check for the correct number of elements,
+ // do not let the reference outlive the slice,
+ // and require exclusive access to the entire slice to mutate the chunk.
+ Some(unsafe { &mut *(self.as_mut_ptr() as *mut [T; N]) })
+ }
+ }
+
+ /// Returns the first `N` elements of the slice and the remainder,
+ /// or `None` if it has fewer than `N` elements.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(slice_first_last_chunk)]
+ ///
+ /// let x = &[0, 1, 2];
+ ///
+ /// if let Some((first, elements)) = x.split_first_chunk::<2>() {
+ /// assert_eq!(first, &[0, 1]);
+ /// assert_eq!(elements, &[2]);
+ /// }
+ /// ```
+ #[unstable(feature = "slice_first_last_chunk", issue = "111774")]
+ #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")]
+ #[inline]
+ pub const fn split_first_chunk<const N: usize>(&self) -> Option<(&[T; N], &[T])> {
+ if self.len() < N {
+ None
+ } else {
+ // SAFETY: We manually verified the bounds of the split.
+ let (first, tail) = unsafe { self.split_at_unchecked(N) };
+
+ // SAFETY: We explicitly check for the correct number of elements,
+ // and do not let the references outlive the slice.
+ Some((unsafe { &*(first.as_ptr() as *const [T; N]) }, tail))
+ }
+ }
+
+ /// Returns a mutable reference to the first `N` elements of the slice and the remainder,
+ /// or `None` if it has fewer than `N` elements.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(slice_first_last_chunk)]
+ ///
+ /// let x = &mut [0, 1, 2];
+ ///
+ /// if let Some((first, elements)) = x.split_first_chunk_mut::<2>() {
+ /// first[0] = 3;
+ /// first[1] = 4;
+ /// elements[0] = 5;
+ /// }
+ /// assert_eq!(x, &[3, 4, 5]);
+ /// ```
+ #[unstable(feature = "slice_first_last_chunk", issue = "111774")]
+ #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")]
+ #[inline]
+ pub const fn split_first_chunk_mut<const N: usize>(
+ &mut self,
+ ) -> Option<(&mut [T; N], &mut [T])> {
+ if self.len() < N {
+ None
+ } else {
+ // SAFETY: We manually verified the bounds of the split.
+ let (first, tail) = unsafe { self.split_at_mut_unchecked(N) };
+
+ // SAFETY: We explicitly check for the correct number of elements,
+ // do not let the reference outlive the slice,
+ // and enforce exclusive mutability of the chunk by the split.
+ Some((unsafe { &mut *(first.as_mut_ptr() as *mut [T; N]) }, tail))
+ }
+ }
+
+ /// Returns the last `N` elements of the slice and the remainder,
+ /// or `None` if it has fewer than `N` elements.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(slice_first_last_chunk)]
+ ///
+ /// let x = &[0, 1, 2];
+ ///
+ /// if let Some((last, elements)) = x.split_last_chunk::<2>() {
+ /// assert_eq!(last, &[1, 2]);
+ /// assert_eq!(elements, &[0]);
+ /// }
+ /// ```
+ #[unstable(feature = "slice_first_last_chunk", issue = "111774")]
+ #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")]
+ #[inline]
+ pub const fn split_last_chunk<const N: usize>(&self) -> Option<(&[T; N], &[T])> {
+ if self.len() < N {
+ None
+ } else {
+ // SAFETY: We manually verified the bounds of the split.
+ let (init, last) = unsafe { self.split_at_unchecked(self.len() - N) };
+
+ // SAFETY: We explicitly check for the correct number of elements,
+ // and do not let the references outlive the slice.
+ Some((unsafe { &*(last.as_ptr() as *const [T; N]) }, init))
+ }
+ }
+
+ /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(slice_first_last_chunk)]
+ ///
+ /// let x = &mut [0, 1, 2];
+ ///
+ /// if let Some((last, elements)) = x.split_last_chunk_mut::<2>() {
+ /// last[0] = 3;
+ /// last[1] = 4;
+ /// elements[0] = 5;
+ /// }
+ /// assert_eq!(x, &[5, 3, 4]);
+ /// ```
+ #[unstable(feature = "slice_first_last_chunk", issue = "111774")]
+ #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")]
+ #[inline]
+ pub const fn split_last_chunk_mut<const N: usize>(
+ &mut self,
+ ) -> Option<(&mut [T; N], &mut [T])> {
+ if self.len() < N {
+ None
+ } else {
+ // SAFETY: We manually verified the bounds of the split.
+ let (init, last) = unsafe { self.split_at_mut_unchecked(self.len() - N) };
+
+ // SAFETY: We explicitly check for the correct number of elements,
+ // do not let the reference outlive the slice,
+ // and enforce exclusive mutability of the chunk by the split.
+ Some((unsafe { &mut *(last.as_mut_ptr() as *mut [T; N]) }, init))
+ }
+ }
+
+ /// Returns the last element of the slice, or `None` if it is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(slice_first_last_chunk)]
+ ///
+ /// let u = [10, 40, 30];
+ /// assert_eq!(Some(&[40, 30]), u.last_chunk::<2>());
+ ///
+ /// let v: &[i32] = &[10];
+ /// assert_eq!(None, v.last_chunk::<2>());
+ ///
+ /// let w: &[i32] = &[];
+ /// assert_eq!(Some(&[]), w.last_chunk::<0>());
+ /// ```
+ #[unstable(feature = "slice_first_last_chunk", issue = "111774")]
+ #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")]
+ #[inline]
+ pub const fn last_chunk<const N: usize>(&self) -> Option<&[T; N]> {
+ if self.len() < N {
+ None
+ } else {
+ // SAFETY: We manually verified the bounds of the slice.
+ // FIXME: Without const traits, we need this instead of `get_unchecked`.
+ let last = unsafe { self.split_at_unchecked(self.len() - N).1 };
+
+ // SAFETY: We explicitly check for the correct number of elements,
+ // and do not let the references outlive the slice.
+ Some(unsafe { &*(last.as_ptr() as *const [T; N]) })
+ }
+ }
+
+ /// Returns a mutable pointer to the last item in the slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(slice_first_last_chunk)]
+ ///
+ /// let x = &mut [0, 1, 2];
+ ///
+ /// if let Some(last) = x.last_chunk_mut::<2>() {
+ /// last[0] = 10;
+ /// last[1] = 20;
+ /// }
+ /// assert_eq!(x, &[0, 10, 20]);
+ /// ```
+ #[unstable(feature = "slice_first_last_chunk", issue = "111774")]
+ #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")]
+ #[inline]
+ pub const fn last_chunk_mut<const N: usize>(&mut self) -> Option<&mut [T; N]> {
+ if self.len() < N {
+ None
+ } else {
+ // SAFETY: We manually verified the bounds of the slice.
+ // FIXME: Without const traits, we need this instead of `get_unchecked`.
+ let last = unsafe { self.split_at_mut_unchecked(self.len() - N).1 };
+
+ // SAFETY: We explicitly check for the correct number of elements,
+ // do not let the reference outlive the slice,
+ // and require exclusive access to the entire slice to mutate the chunk.
+ Some(unsafe { &mut *(last.as_mut_ptr() as *mut [T; N]) })
+ }
+ }
+
/// Returns a reference to an element or subslice depending on the type of
/// index.
///
@@ -333,12 +596,11 @@ impl<T> [T] {
/// assert_eq!(None, v.get(0..4));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
#[inline]
#[must_use]
- pub const fn get<I>(&self, index: I) -> Option<&I::Output>
+ pub fn get<I>(&self, index: I) -> Option<&I::Output>
where
- I: ~const SliceIndex<Self>,
+ I: SliceIndex<Self>,
{
index.get(self)
}
@@ -359,12 +621,11 @@ impl<T> [T] {
/// assert_eq!(x, &[0, 42, 2]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
#[inline]
#[must_use]
- pub const fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
+ pub fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
where
- I: ~const SliceIndex<Self>,
+ I: SliceIndex<Self>,
{
index.get_mut(self)
}
@@ -392,12 +653,11 @@ impl<T> [T] {
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
#[inline]
#[must_use]
- pub const unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
+ pub unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
where
- I: ~const SliceIndex<Self>,
+ I: SliceIndex<Self>,
{
// SAFETY: the caller must uphold most of the safety requirements for `get_unchecked`;
// the slice is dereferenceable because `self` is a safe reference.
@@ -430,12 +690,11 @@ impl<T> [T] {
/// assert_eq!(x, &[1, 13, 4]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
#[inline]
#[must_use]
- pub const unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
+ pub unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
where
- I: ~const SliceIndex<Self>,
+ I: SliceIndex<Self>,
{
// SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`;
// the slice is dereferenceable because `self` is a safe reference.
@@ -678,9 +937,8 @@ impl<T> [T] {
/// assert!(v == [3, 2, 1]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_reverse", issue = "100784")]
#[inline]
- pub const fn reverse(&mut self) {
+ pub fn reverse(&mut self) {
let half_len = self.len() / 2;
let Range { start, end } = self.as_mut_ptr_range();
@@ -703,7 +961,7 @@ impl<T> [T] {
revswap(front_half, back_half, half_len);
#[inline]
- const fn revswap<T>(a: &mut [T], b: &mut [T], n: usize) {
+ fn revswap<T>(a: &mut [T], b: &mut [T], n: usize) {
debug_assert!(a.len() == n);
debug_assert!(b.len() == n);
@@ -996,7 +1254,7 @@ impl<T> [T] {
#[unstable(feature = "slice_as_chunks", issue = "74985")]
#[inline]
#[must_use]
- pub unsafe fn as_chunks_unchecked<const N: usize>(&self) -> &[[T; N]] {
+ pub const unsafe fn as_chunks_unchecked<const N: usize>(&self) -> &[[T; N]] {
let this = self;
// SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length
let new_len = unsafe {
@@ -1044,7 +1302,7 @@ impl<T> [T] {
#[inline]
#[track_caller]
#[must_use]
- pub fn as_chunks<const N: usize>(&self) -> (&[[T; N]], &[T]) {
+ pub const fn as_chunks<const N: usize>(&self) -> (&[[T; N]], &[T]) {
assert!(N != 0, "chunk size must be non-zero");
let len = self.len() / N;
let (multiple_of_n, remainder) = self.split_at(len * N);
@@ -1076,7 +1334,7 @@ impl<T> [T] {
#[inline]
#[track_caller]
#[must_use]
- pub fn as_rchunks<const N: usize>(&self) -> (&[T], &[[T; N]]) {
+ pub const fn as_rchunks<const N: usize>(&self) -> (&[T], &[[T; N]]) {
assert!(N != 0, "chunk size must be non-zero");
let len = self.len() / N;
let (remainder, multiple_of_n) = self.split_at(self.len() - len * N);
@@ -1153,7 +1411,7 @@ impl<T> [T] {
#[unstable(feature = "slice_as_chunks", issue = "74985")]
#[inline]
#[must_use]
- pub unsafe fn as_chunks_unchecked_mut<const N: usize>(&mut self) -> &mut [[T; N]] {
+ pub const unsafe fn as_chunks_unchecked_mut<const N: usize>(&mut self) -> &mut [[T; N]] {
let this = &*self;
// SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length
let new_len = unsafe {
@@ -1196,7 +1454,7 @@ impl<T> [T] {
#[inline]
#[track_caller]
#[must_use]
- pub fn as_chunks_mut<const N: usize>(&mut self) -> (&mut [[T; N]], &mut [T]) {
+ pub const fn as_chunks_mut<const N: usize>(&mut self) -> (&mut [[T; N]], &mut [T]) {
assert!(N != 0, "chunk size must be non-zero");
let len = self.len() / N;
let (multiple_of_n, remainder) = self.split_at_mut(len * N);
@@ -1234,7 +1492,7 @@ impl<T> [T] {
#[inline]
#[track_caller]
#[must_use]
- pub fn as_rchunks_mut<const N: usize>(&mut self) -> (&mut [T], &mut [[T; N]]) {
+ pub const fn as_rchunks_mut<const N: usize>(&mut self) -> (&mut [T], &mut [[T; N]]) {
assert!(N != 0, "chunk size must be non-zero");
let len = self.len() / N;
let (remainder, multiple_of_n) = self.split_at_mut(self.len() - len * N);
@@ -1596,7 +1854,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 = "1.71.0")]
+ #[rustc_allow_const_fn_unstable(slice_split_at_unchecked)]
#[inline]
#[track_caller]
#[must_use]
@@ -2746,8 +3005,9 @@ impl<T> [T] {
///
/// # Current implementation
///
- /// The current algorithm is based on the quickselect portion of the same quicksort algorithm
- /// used for [`sort_unstable`].
+ /// The current algorithm is an introselect implementation based on Pattern Defeating Quicksort, which is also
+ /// the basis for [`sort_unstable`]. The fallback algorithm is Median of Medians using Tukey's Ninther for
+ /// pivot selection, which guarantees linear runtime for all inputs.
///
/// [`sort_unstable`]: slice::sort_unstable
///
@@ -2776,7 +3036,7 @@ impl<T> [T] {
where
T: Ord,
{
- sort::partition_at_index(self, index, T::lt)
+ select::partition_at_index(self, index, T::lt)
}
/// Reorder the slice with a comparator function such that the element at `index` is at its
@@ -2797,8 +3057,9 @@ impl<T> [T] {
///
/// # Current implementation
///
- /// The current algorithm is based on the quickselect portion of the same quicksort algorithm
- /// used for [`sort_unstable`].
+ /// The current algorithm is an introselect implementation based on Pattern Defeating Quicksort, which is also
+ /// the basis for [`sort_unstable`]. The fallback algorithm is Median of Medians using Tukey's Ninther for
+ /// pivot selection, which guarantees linear runtime for all inputs.
///
/// [`sort_unstable`]: slice::sort_unstable
///
@@ -2831,7 +3092,7 @@ impl<T> [T] {
where
F: FnMut(&T, &T) -> Ordering,
{
- sort::partition_at_index(self, index, |a: &T, b: &T| compare(a, b) == Less)
+ select::partition_at_index(self, index, |a: &T, b: &T| compare(a, b) == Less)
}
/// Reorder the slice with a key extraction function such that the element at `index` is at its
@@ -2887,7 +3148,7 @@ impl<T> [T] {
F: FnMut(&T) -> K,
K: Ord,
{
- sort::partition_at_index(self, index, |a: &T, b: &T| f(a).lt(&f(b)))
+ select::partition_at_index(self, index, |a: &T, b: &T| f(a).lt(&f(b)))
}
/// Moves all consecutive repeated elements to the end of the slice according to the
@@ -3479,44 +3740,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;
@@ -4262,7 +4492,7 @@ impl<T, const N: usize> [[T; N]] {
/// assert!(empty_slice_of_arrays.flatten().is_empty());
/// ```
#[unstable(feature = "slice_flatten", issue = "95629")]
- pub fn flatten(&self) -> &[T] {
+ pub const fn flatten(&self) -> &[T] {
let len = if T::IS_ZST {
self.len().checked_mul(N).expect("slice len overflow")
} else {
@@ -4404,8 +4634,7 @@ where
}
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
-impl<T> const Default for &[T] {
+impl<T> Default for &[T] {
/// Creates an empty slice.
fn default() -> Self {
&[]
@@ -4413,8 +4642,7 @@ impl<T> const Default for &[T] {
}
#[stable(feature = "mut_slice_default", since = "1.5.0")]
-#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
-impl<T> const Default for &mut [T] {
+impl<T> Default for &mut [T] {
/// Creates a mutable empty slice.
fn default() -> Self {
&mut []
@@ -4458,7 +4686,7 @@ impl<T, const N: usize> SlicePattern for [T; N] {
/// This will do `binomial(N + 1, 2) = N * (N + 1) / 2 = 0, 1, 3, 6, 10, ..`
/// comparison operations.
fn get_many_check_valid<const N: usize>(indices: &[usize; N], len: usize) -> bool {
- // NB: The optimzer should inline the loops into a sequence
+ // NB: The optimizer should inline the loops into a sequence
// of instructions without additional branching.
let mut valid = true;
for (i, &idx) in indices.iter().enumerate() {
diff --git a/library/core/src/slice/select.rs b/library/core/src/slice/select.rs
new file mode 100644
index 000000000..ffc193578
--- /dev/null
+++ b/library/core/src/slice/select.rs
@@ -0,0 +1,302 @@
+//! Slice selection
+//!
+//! This module contains the implementation for `slice::select_nth_unstable`.
+//! It uses an introselect algorithm based on Orson Peters' pattern-defeating quicksort,
+//! published at: <https://github.com/orlp/pdqsort>
+//!
+//! The fallback algorithm used for introselect is Median of Medians using Tukey's Ninther
+//! for pivot selection. Using this as a fallback ensures O(n) worst case running time with
+//! better performance than one would get using heapsort as fallback.
+
+use crate::cmp;
+use crate::mem::{self, SizedTypeProperties};
+use crate::slice::sort::{
+ break_patterns, choose_pivot, insertion_sort_shift_left, partition, partition_equal,
+};
+
+// For slices of up to this length it's probably faster to simply sort them.
+// Defined at the module scope because it's used in multiple functions.
+const MAX_INSERTION: usize = 10;
+
+fn partition_at_index_loop<'a, T, F>(
+ mut v: &'a mut [T],
+ mut index: usize,
+ is_less: &mut F,
+ mut pred: Option<&'a T>,
+) where
+ F: FnMut(&T, &T) -> bool,
+{
+ // Limit the amount of iterations and fall back to fast deterministic selection
+ // to ensure O(n) worst case running time. This limit needs to be constant, because
+ // using `ilog2(len)` like in `sort` would result in O(n log n) time complexity.
+ // The exact value of the limit is chosen somewhat arbitrarily, but for most inputs bad pivot
+ // selections should be relatively rare, so the limit usually shouldn't be reached
+ // anyways.
+ let mut limit = 16;
+
+ // True if the last partitioning was reasonably balanced.
+ let mut was_balanced = true;
+
+ loop {
+ if v.len() <= MAX_INSERTION {
+ if v.len() > 1 {
+ insertion_sort_shift_left(v, 1, is_less);
+ }
+ return;
+ }
+
+ if limit == 0 {
+ median_of_medians(v, is_less, index);
+ return;
+ }
+
+ // If the last partitioning was imbalanced, try breaking patterns in the slice by shuffling
+ // some elements around. Hopefully we'll choose a better pivot this time.
+ if !was_balanced {
+ break_patterns(v);
+ limit -= 1;
+ }
+
+ // Choose a pivot
+ let (pivot, _) = choose_pivot(v, is_less);
+
+ // If the chosen pivot is equal to the predecessor, then it's the smallest element in the
+ // slice. Partition the slice into elements equal to and elements greater than the pivot.
+ // This case is usually hit when the slice contains many duplicate elements.
+ if let Some(p) = pred {
+ if !is_less(p, &v[pivot]) {
+ let mid = partition_equal(v, pivot, is_less);
+
+ // If we've passed our index, then we're good.
+ if mid > index {
+ return;
+ }
+
+ // Otherwise, continue sorting elements greater than the pivot.
+ v = &mut v[mid..];
+ index = index - mid;
+ pred = None;
+ continue;
+ }
+ }
+
+ let (mid, _) = partition(v, pivot, is_less);
+ was_balanced = cmp::min(mid, v.len() - mid) >= v.len() / 8;
+
+ // Split the slice into `left`, `pivot`, and `right`.
+ let (left, right) = v.split_at_mut(mid);
+ let (pivot, right) = right.split_at_mut(1);
+ let pivot = &pivot[0];
+
+ if mid < index {
+ v = right;
+ index = index - mid - 1;
+ pred = Some(pivot);
+ } else if mid > index {
+ v = left;
+ } else {
+ // If mid == index, then we're done, since partition() guaranteed that all elements
+ // after mid are greater than or equal to mid.
+ return;
+ }
+ }
+}
+
+/// Helper function that returns the index of the minimum element in the slice using the given
+/// comparator function
+fn min_index<T, F: FnMut(&T, &T) -> bool>(slice: &[T], is_less: &mut F) -> Option<usize> {
+ slice
+ .iter()
+ .enumerate()
+ .reduce(|acc, t| if is_less(t.1, acc.1) { t } else { acc })
+ .map(|(i, _)| i)
+}
+
+/// Helper function that returns the index of the maximum element in the slice using the given
+/// comparator function
+fn max_index<T, F: FnMut(&T, &T) -> bool>(slice: &[T], is_less: &mut F) -> Option<usize> {
+ slice
+ .iter()
+ .enumerate()
+ .reduce(|acc, t| if is_less(acc.1, t.1) { t } else { acc })
+ .map(|(i, _)| i)
+}
+
+/// Reorder the slice such that the element at `index` is at its final sorted position.
+pub fn partition_at_index<T, F>(
+ v: &mut [T],
+ index: usize,
+ mut is_less: F,
+) -> (&mut [T], &mut T, &mut [T])
+where
+ F: FnMut(&T, &T) -> bool,
+{
+ if index >= v.len() {
+ panic!("partition_at_index index {} greater than length of slice {}", index, v.len());
+ }
+
+ if T::IS_ZST {
+ // Sorting has no meaningful behavior on zero-sized types. Do nothing.
+ } else if index == v.len() - 1 {
+ // Find max element and place it in the last position of the array. We're free to use
+ // `unwrap()` here because we know v must not be empty.
+ let max_idx = max_index(v, &mut is_less).unwrap();
+ v.swap(max_idx, index);
+ } else if index == 0 {
+ // Find min element and place it in the first position of the array. We're free to use
+ // `unwrap()` here because we know v must not be empty.
+ let min_idx = min_index(v, &mut is_less).unwrap();
+ v.swap(min_idx, index);
+ } else {
+ partition_at_index_loop(v, index, &mut is_less, None);
+ }
+
+ let (left, right) = v.split_at_mut(index);
+ let (pivot, right) = right.split_at_mut(1);
+ let pivot = &mut pivot[0];
+ (left, pivot, right)
+}
+
+/// Selection algorithm to select the k-th element from the slice in guaranteed O(n) time.
+/// This is essentially a quickselect that uses Tukey's Ninther for pivot selection
+fn median_of_medians<T, F: FnMut(&T, &T) -> bool>(mut v: &mut [T], is_less: &mut F, mut k: usize) {
+ // Since this function isn't public, it should never be called with an out-of-bounds index.
+ debug_assert!(k < v.len());
+
+ // If T is as ZST, `partition_at_index` will already return early.
+ debug_assert!(!T::IS_ZST);
+
+ // We now know that `k < v.len() <= isize::MAX`
+ loop {
+ if v.len() <= MAX_INSERTION {
+ if v.len() > 1 {
+ insertion_sort_shift_left(v, 1, is_less);
+ }
+ return;
+ }
+
+ // `median_of_{minima,maxima}` can't handle the extreme cases of the first/last element,
+ // so we catch them here and just do a linear search.
+ if k == v.len() - 1 {
+ // Find max element and place it in the last position of the array. We're free to use
+ // `unwrap()` here because we know v must not be empty.
+ let max_idx = max_index(v, is_less).unwrap();
+ v.swap(max_idx, k);
+ return;
+ } else if k == 0 {
+ // Find min element and place it in the first position of the array. We're free to use
+ // `unwrap()` here because we know v must not be empty.
+ let min_idx = min_index(v, is_less).unwrap();
+ v.swap(min_idx, k);
+ return;
+ }
+
+ let p = median_of_ninthers(v, is_less);
+
+ if p == k {
+ return;
+ } else if p > k {
+ v = &mut v[..p];
+ } else {
+ // Since `p < k < v.len()`, `p + 1` doesn't overflow and is
+ // a valid index into the slice.
+ v = &mut v[p + 1..];
+ k -= p + 1;
+ }
+ }
+}
+
+// Optimized for when `k` lies somewhere in the middle of the slice. Selects a pivot
+// as close as possible to the median of the slice. For more details on how the algorithm
+// operates, refer to the paper <https://drops.dagstuhl.de/opus/volltexte/2017/7612/pdf/LIPIcs-SEA-2017-24.pdf>.
+fn median_of_ninthers<T, F: FnMut(&T, &T) -> bool>(v: &mut [T], is_less: &mut F) -> usize {
+ // use `saturating_mul` so the multiplication doesn't overflow on 16-bit platforms.
+ let frac = if v.len() <= 1024 {
+ v.len() / 12
+ } else if v.len() <= 128_usize.saturating_mul(1024) {
+ v.len() / 64
+ } else {
+ v.len() / 1024
+ };
+
+ let pivot = frac / 2;
+ let lo = v.len() / 2 - pivot;
+ let hi = frac + lo;
+ let gap = (v.len() - 9 * frac) / 4;
+ let mut a = lo - 4 * frac - gap;
+ let mut b = hi + gap;
+ for i in lo..hi {
+ ninther(v, is_less, a, i - frac, b, a + 1, i, b + 1, a + 2, i + frac, b + 2);
+ a += 3;
+ b += 3;
+ }
+
+ median_of_medians(&mut v[lo..lo + frac], is_less, pivot);
+ partition(v, lo + pivot, is_less).0
+}
+
+/// Moves around the 9 elements at the indices a..i, such that
+/// `v[d]` contains the median of the 9 elements and the other
+/// elements are partitioned around it.
+fn ninther<T, F: FnMut(&T, &T) -> bool>(
+ v: &mut [T],
+ is_less: &mut F,
+ a: usize,
+ mut b: usize,
+ c: usize,
+ mut d: usize,
+ e: usize,
+ mut f: usize,
+ g: usize,
+ mut h: usize,
+ i: usize,
+) {
+ b = median_idx(v, is_less, a, b, c);
+ h = median_idx(v, is_less, g, h, i);
+ if is_less(&v[h], &v[b]) {
+ mem::swap(&mut b, &mut h);
+ }
+ if is_less(&v[f], &v[d]) {
+ mem::swap(&mut d, &mut f);
+ }
+ if is_less(&v[e], &v[d]) {
+ // do nothing
+ } else if is_less(&v[f], &v[e]) {
+ d = f;
+ } else {
+ if is_less(&v[e], &v[b]) {
+ v.swap(e, b);
+ } else if is_less(&v[h], &v[e]) {
+ v.swap(e, h);
+ }
+ return;
+ }
+ if is_less(&v[d], &v[b]) {
+ d = b;
+ } else if is_less(&v[h], &v[d]) {
+ d = h;
+ }
+
+ v.swap(d, e);
+}
+
+/// returns the index pointing to the median of the 3
+/// elements `v[a]`, `v[b]` and `v[c]`
+fn median_idx<T, F: FnMut(&T, &T) -> bool>(
+ v: &[T],
+ is_less: &mut F,
+ mut a: usize,
+ b: usize,
+ mut c: usize,
+) -> usize {
+ if is_less(&v[c], &v[a]) {
+ mem::swap(&mut a, &mut c);
+ }
+ if is_less(&v[c], &v[b]) {
+ return c;
+ }
+ if is_less(&v[b], &v[a]) {
+ return a;
+ }
+ b
+}
diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs
index 07fd96f92..db76d2625 100644
--- a/library/core/src/slice/sort.rs
+++ b/library/core/src/slice/sort.rs
@@ -145,7 +145,7 @@ where
/// Never inline this function to avoid code bloat. It still optimizes nicely and has practically no
/// performance impact. Even improving performance in some cases.
#[inline(never)]
-fn insertion_sort_shift_left<T, F>(v: &mut [T], offset: usize, is_less: &mut F)
+pub(super) fn insertion_sort_shift_left<T, F>(v: &mut [T], offset: usize, is_less: &mut F)
where
F: FnMut(&T, &T) -> bool,
{
@@ -557,7 +557,7 @@ where
///
/// 1. Number of elements smaller than `v[pivot]`.
/// 2. True if `v` was already partitioned.
-fn partition<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> (usize, bool)
+pub(super) fn partition<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> (usize, bool)
where
F: FnMut(&T, &T) -> bool,
{
@@ -612,7 +612,7 @@ where
///
/// Returns the number of elements equal to the pivot. It is assumed that `v` does not contain
/// elements smaller than the pivot.
-fn partition_equal<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> usize
+pub(super) fn partition_equal<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> usize
where
F: FnMut(&T, &T) -> bool,
{
@@ -670,7 +670,7 @@ where
/// Scatters some elements around in an attempt to break patterns that might cause imbalanced
/// partitions in quicksort.
#[cold]
-fn break_patterns<T>(v: &mut [T]) {
+pub(super) fn break_patterns<T>(v: &mut [T]) {
let len = v.len();
if len >= 8 {
let mut seed = len;
@@ -719,7 +719,7 @@ fn break_patterns<T>(v: &mut [T]) {
/// Chooses a pivot in `v` and returns the index and `true` if the slice is likely already sorted.
///
/// Elements in `v` might be reordered in the process.
-fn choose_pivot<T, F>(v: &mut [T], is_less: &mut F) -> (usize, bool)
+pub(super) fn choose_pivot<T, F>(v: &mut [T], is_less: &mut F) -> (usize, bool)
where
F: FnMut(&T, &T) -> bool,
{
@@ -897,138 +897,6 @@ where
recurse(v, &mut is_less, None, limit);
}
-fn partition_at_index_loop<'a, T, F>(
- mut v: &'a mut [T],
- mut index: usize,
- is_less: &mut F,
- mut pred: Option<&'a T>,
-) where
- F: FnMut(&T, &T) -> bool,
-{
- // Limit the amount of iterations and fall back to heapsort, similarly to `slice::sort_unstable`.
- // This lowers the worst case running time from O(n^2) to O(n log n).
- // FIXME: Investigate whether it would be better to use something like Median of Medians
- // or Fast Deterministic Selection to guarantee O(n) worst case.
- let mut limit = usize::BITS - v.len().leading_zeros();
-
- // True if the last partitioning was reasonably balanced.
- let mut was_balanced = true;
-
- loop {
- let len = v.len();
-
- // For slices of up to this length it's probably faster to simply sort them.
- const MAX_INSERTION: usize = 10;
- if len <= MAX_INSERTION {
- if len >= 2 {
- insertion_sort_shift_left(v, 1, is_less);
- }
- return;
- }
-
- if limit == 0 {
- heapsort(v, is_less);
- return;
- }
-
- // If the last partitioning was imbalanced, try breaking patterns in the slice by shuffling
- // some elements around. Hopefully we'll choose a better pivot this time.
- if !was_balanced {
- break_patterns(v);
- limit -= 1;
- }
-
- // Choose a pivot
- let (pivot, _) = choose_pivot(v, is_less);
-
- // If the chosen pivot is equal to the predecessor, then it's the smallest element in the
- // slice. Partition the slice into elements equal to and elements greater than the pivot.
- // This case is usually hit when the slice contains many duplicate elements.
- if let Some(p) = pred {
- if !is_less(p, &v[pivot]) {
- let mid = partition_equal(v, pivot, is_less);
-
- // If we've passed our index, then we're good.
- if mid > index {
- return;
- }
-
- // Otherwise, continue sorting elements greater than the pivot.
- v = &mut v[mid..];
- index = index - mid;
- pred = None;
- continue;
- }
- }
-
- let (mid, _) = partition(v, pivot, is_less);
- was_balanced = cmp::min(mid, len - mid) >= len / 8;
-
- // Split the slice into `left`, `pivot`, and `right`.
- let (left, right) = v.split_at_mut(mid);
- let (pivot, right) = right.split_at_mut(1);
- let pivot = &pivot[0];
-
- if mid < index {
- v = right;
- index = index - mid - 1;
- pred = Some(pivot);
- } else if mid > index {
- v = left;
- } else {
- // If mid == index, then we're done, since partition() guaranteed that all elements
- // after mid are greater than or equal to mid.
- return;
- }
- }
-}
-
-/// Reorder the slice such that the element at `index` is at its final sorted position.
-pub fn partition_at_index<T, F>(
- v: &mut [T],
- index: usize,
- mut is_less: F,
-) -> (&mut [T], &mut T, &mut [T])
-where
- F: FnMut(&T, &T) -> bool,
-{
- use cmp::Ordering::Greater;
- use cmp::Ordering::Less;
-
- if index >= v.len() {
- panic!("partition_at_index index {} greater than length of slice {}", index, v.len());
- }
-
- if T::IS_ZST {
- // Sorting has no meaningful behavior on zero-sized types. Do nothing.
- } else if index == v.len() - 1 {
- // Find max element and place it in the last position of the array. We're free to use
- // `unwrap()` here because we know v must not be empty.
- let (max_index, _) = v
- .iter()
- .enumerate()
- .max_by(|&(_, x), &(_, y)| if is_less(x, y) { Less } else { Greater })
- .unwrap();
- v.swap(max_index, index);
- } else if index == 0 {
- // Find min element and place it in the first position of the array. We're free to use
- // `unwrap()` here because we know v must not be empty.
- let (min_index, _) = v
- .iter()
- .enumerate()
- .min_by(|&(_, x), &(_, y)| if is_less(x, y) { Less } else { Greater })
- .unwrap();
- v.swap(min_index, index);
- } else {
- partition_at_index_loop(v, index, &mut is_less, None);
- }
-
- let (left, right) = v.split_at_mut(index);
- let (pivot, right) = right.split_at_mut(1);
- let pivot = &mut pivot[0];
- (left, pivot, right)
-}
-
/// Merges non-decreasing runs `v[..mid]` and `v[mid..]` using `buf` as temporary storage, and
/// stores the result into `v[..]`.
///
@@ -1085,12 +953,12 @@ where
// SAFETY: left and right must be valid and part of v same for out.
unsafe {
- let to_copy = if is_less(&*right, &**left) {
- get_and_increment(&mut right)
- } else {
- get_and_increment(left)
- };
- ptr::copy_nonoverlapping(to_copy, get_and_increment(out), 1);
+ let is_l = is_less(&*right, &**left);
+ let to_copy = if is_l { right } else { *left };
+ ptr::copy_nonoverlapping(to_copy, *out, 1);
+ *out = out.add(1);
+ right = right.add(is_l as usize);
+ *left = left.add(!is_l as usize);
}
}
} else {
@@ -1113,32 +981,18 @@ where
// SAFETY: left and right must be valid and part of v same for out.
unsafe {
- let to_copy = if is_less(&*right.sub(1), &*left.sub(1)) {
- decrement_and_get(left)
- } else {
- decrement_and_get(right)
- };
- ptr::copy_nonoverlapping(to_copy, decrement_and_get(&mut out), 1);
+ let is_l = is_less(&*right.sub(1), &*left.sub(1));
+ *left = left.sub(is_l as usize);
+ *right = right.sub(!is_l as usize);
+ let to_copy = if is_l { *left } else { *right };
+ out = out.sub(1);
+ ptr::copy_nonoverlapping(to_copy, out, 1);
}
}
}
// Finally, `hole` gets dropped. If the shorter run was not fully consumed, whatever remains of
// it will now be copied into the hole in `v`.
- unsafe fn get_and_increment<T>(ptr: &mut *mut T) -> *mut T {
- let old = *ptr;
-
- // SAFETY: ptr.add(1) must still be a valid pointer and part of `v`.
- *ptr = unsafe { ptr.add(1) };
- old
- }
-
- unsafe fn decrement_and_get<T>(ptr: &mut *mut T) -> *mut T {
- // SAFETY: ptr.sub(1) must still be a valid pointer and part of `v`.
- *ptr = unsafe { ptr.sub(1) };
- *ptr
- }
-
// When dropped, copies the range `start..end` into `dest..`.
struct MergeHole<T> {
start: *mut T,
@@ -1456,7 +1310,6 @@ pub struct TimSortRun {
/// Takes a range as denoted by start and end, that is already sorted and extends it to the right if
/// necessary with sorts optimized for smaller ranges such as insertion sort.
-#[cfg(not(no_global_oom_handling))]
fn provide_sorted_batch<T, F>(v: &mut [T], start: usize, mut end: usize, is_less: &mut F) -> usize
where
F: FnMut(&T, &T) -> bool,
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index 041694299..ef05b25fd 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -16,6 +16,7 @@ mod validations;
use self::pattern::Pattern;
use self::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher};
+use crate::ascii;
use crate::char::{self, EscapeDebugExtArgs};
use crate::mem;
use crate::slice::{self, SliceIndex};
@@ -206,9 +207,8 @@ impl str {
/// ```
#[must_use]
#[stable(feature = "is_char_boundary", since = "1.9.0")]
- #[rustc_const_unstable(feature = "const_is_char_boundary", issue = "none")]
#[inline]
- pub const fn is_char_boundary(&self, index: usize) -> bool {
+ pub fn is_char_boundary(&self, index: usize) -> bool {
// 0 is always ok.
// Test for 0 explicitly so that it can optimize out the check
// easily and skip reading string data for that case.
@@ -436,9 +436,8 @@ impl str {
/// assert!(v.get(..42).is_none());
/// ```
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
- #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
#[inline]
- pub const fn get<I: ~const SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
+ pub fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
i.get(self)
}
@@ -469,9 +468,8 @@ impl str {
/// assert_eq!("HEllo", v);
/// ```
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
- #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
#[inline]
- pub const fn get_mut<I: ~const SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
+ pub fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
i.get_mut(self)
}
@@ -502,9 +500,8 @@ impl str {
/// }
/// ```
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
- #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
#[inline]
- pub const unsafe fn get_unchecked<I: ~const SliceIndex<str>>(&self, i: I) -> &I::Output {
+ pub unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output {
// SAFETY: the caller must uphold the safety contract for `get_unchecked`;
// the slice is dereferenceable because `self` is a safe reference.
// The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
@@ -538,12 +535,8 @@ impl str {
/// }
/// ```
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
- #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
#[inline]
- pub const unsafe fn get_unchecked_mut<I: ~const SliceIndex<str>>(
- &mut self,
- i: I,
- ) -> &mut I::Output {
+ pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output {
// SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`;
// the slice is dereferenceable because `self` is a safe reference.
// The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
@@ -2365,15 +2358,26 @@ impl str {
/// assert!(!non_ascii.is_ascii());
/// ```
#[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ #[rustc_const_unstable(feature = "const_slice_is_ascii", issue = "111090")]
#[must_use]
#[inline]
- pub fn is_ascii(&self) -> bool {
+ pub const fn is_ascii(&self) -> bool {
// We can treat each byte as character here: all multibyte characters
// start with a byte that is not in the ASCII range, so we will stop
// there already.
self.as_bytes().is_ascii()
}
+ /// If this string slice [`is_ascii`](Self::is_ascii), returns it as a slice
+ /// of [ASCII characters](`ascii::Char`), otherwise returns `None`.
+ #[unstable(feature = "ascii_char", issue = "110998")]
+ #[must_use]
+ #[inline]
+ pub const fn as_ascii(&self) -> Option<&[ascii::Char]> {
+ // Like in `is_ascii`, we can work on the bytes directly.
+ self.as_bytes().as_ascii()
+ }
+
/// Checks that two strings are an ASCII case-insensitive match.
///
/// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
@@ -2582,8 +2586,7 @@ impl AsRef<[u8]> for str {
}
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
-impl const Default for &str {
+impl Default for &str {
/// Creates an empty str
#[inline]
fn default() -> Self {
diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs
index e3a464a1c..91ee2903a 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/str/traits.rs b/library/core/src/str/traits.rs
index 41c097b55..1d52335f2 100644
--- a/library/core/src/str/traits.rs
+++ b/library/core/src/str/traits.rs
@@ -50,10 +50,9 @@ impl PartialOrd for str {
}
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
-impl<I> const ops::Index<I> for str
+impl<I> ops::Index<I> for str
where
- I: ~const SliceIndex<str>,
+ I: SliceIndex<str>,
{
type Output = I::Output;
@@ -64,10 +63,9 @@ where
}
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
-impl<I> const ops::IndexMut<I> for str
+impl<I> ops::IndexMut<I> for str
where
- I: ~const SliceIndex<str>,
+ I: SliceIndex<str>,
{
#[inline]
fn index_mut(&mut self, index: I) -> &mut I::Output {
@@ -96,7 +94,7 @@ const fn str_index_overflow_fail() -> ! {
/// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`.
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
-unsafe impl const SliceIndex<str> for ops::RangeFull {
+unsafe impl SliceIndex<str> for ops::RangeFull {
type Output = str;
#[inline]
fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -161,7 +159,7 @@ unsafe impl const SliceIndex<str> for ops::RangeFull {
/// ```
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
-unsafe impl const SliceIndex<str> for ops::Range<usize> {
+unsafe impl SliceIndex<str> for ops::Range<usize> {
type Output = str;
#[inline]
fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -271,7 +269,7 @@ unsafe impl const SliceIndex<str> for ops::Range<usize> {
/// character (as defined by `is_char_boundary`), or if `end > len`.
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
-unsafe impl const SliceIndex<str> for ops::RangeTo<usize> {
+unsafe impl SliceIndex<str> for ops::RangeTo<usize> {
type Output = str;
#[inline]
fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -340,7 +338,7 @@ unsafe impl const SliceIndex<str> for ops::RangeTo<usize> {
/// a character (as defined by `is_char_boundary`), or if `begin > len`.
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
-unsafe impl const SliceIndex<str> for ops::RangeFrom<usize> {
+unsafe impl SliceIndex<str> for ops::RangeFrom<usize> {
type Output = str;
#[inline]
fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -412,7 +410,7 @@ unsafe impl const SliceIndex<str> for ops::RangeFrom<usize> {
/// byte offset or equal to `len`), if `begin > end`, or if `end >= len`.
#[stable(feature = "inclusive_range", since = "1.26.0")]
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
-unsafe impl const SliceIndex<str> for ops::RangeInclusive<usize> {
+unsafe impl SliceIndex<str> for ops::RangeInclusive<usize> {
type Output = str;
#[inline]
fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -464,7 +462,7 @@ unsafe impl const SliceIndex<str> for ops::RangeInclusive<usize> {
/// `is_char_boundary`, or equal to `len`), or if `end >= len`.
#[stable(feature = "inclusive_range", since = "1.26.0")]
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
-unsafe impl const SliceIndex<str> for ops::RangeToInclusive<usize> {
+unsafe impl SliceIndex<str> for ops::RangeToInclusive<usize> {
type Output = str;
#[inline]
fn get(self, slice: &str) -> Option<&Self::Output> {
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index f1ed68d72..236b7f423 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -147,8 +147,7 @@ pub struct AtomicBool {
#[cfg(target_has_atomic_load_store = "8")]
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
-impl const Default for AtomicBool {
+impl Default for AtomicBool {
/// Creates an `AtomicBool` initialized to `false`.
#[inline]
fn default() -> Self {
@@ -179,8 +178,7 @@ pub struct AtomicPtr<T> {
#[cfg(target_has_atomic_load_store = "ptr")]
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
-impl<T> const Default for AtomicPtr<T> {
+impl<T> Default for AtomicPtr<T> {
/// Creates a null `AtomicPtr<T>`.
fn default() -> AtomicPtr<T> {
AtomicPtr::new(crate::ptr::null_mut())
@@ -1916,8 +1914,7 @@ impl<T> AtomicPtr<T> {
#[cfg(target_has_atomic_load_store = "8")]
#[stable(feature = "atomic_bool_from", since = "1.24.0")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl const From<bool> for AtomicBool {
+impl From<bool> for AtomicBool {
/// Converts a `bool` into an `AtomicBool`.
///
/// # Examples
@@ -1935,8 +1932,7 @@ impl const From<bool> for AtomicBool {
#[cfg(target_has_atomic_load_store = "ptr")]
#[stable(feature = "atomic_from", since = "1.23.0")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<T> const From<*mut T> for AtomicPtr<T> {
+impl<T> From<*mut T> for AtomicPtr<T> {
/// Converts a `*mut T` into an `AtomicPtr<T>`.
#[inline]
fn from(p: *mut T) -> Self {
@@ -2002,8 +1998,7 @@ macro_rules! atomic_int {
pub const $atomic_init: $atomic_type = $atomic_type::new(0);
#[$stable]
- #[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
- impl const Default for $atomic_type {
+ impl Default for $atomic_type {
#[inline]
fn default() -> Self {
Self::new(Default::default())
@@ -2011,8 +2006,7 @@ macro_rules! atomic_int {
}
#[$stable_from]
- #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")]
- impl const From<$int_type> for $atomic_type {
+ impl From<$int_type> for $atomic_type {
#[doc = concat!("Converts an `", stringify!($int_type), "` into an `", stringify!($atomic_type), "`.")]
#[inline]
fn from(v: $int_type) -> Self { Self::new(v) }
diff --git a/library/core/src/task/mod.rs b/library/core/src/task/mod.rs
index c5f89b9a2..3f0080e38 100644
--- a/library/core/src/task/mod.rs
+++ b/library/core/src/task/mod.rs
@@ -13,5 +13,3 @@ pub use self::wake::{Context, RawWaker, RawWakerVTable, Waker};
mod ready;
#[stable(feature = "ready_macro", since = "1.64.0")]
pub use ready::ready;
-#[unstable(feature = "poll_ready", issue = "89780")]
-pub use ready::Ready;
diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs
index af5bf441b..0a0f702f6 100644
--- a/library/core/src/task/poll.rs
+++ b/library/core/src/task/poll.rs
@@ -3,7 +3,6 @@
use crate::convert;
use crate::ops::{self, ControlFlow};
use crate::result::Result;
-use crate::task::Ready;
/// Indicates whether a value is available or if the current task has been
/// scheduled to receive a wakeup instead.
@@ -95,38 +94,6 @@ impl<T> Poll<T> {
pub const fn is_pending(&self) -> bool {
!self.is_ready()
}
-
- /// Extracts the successful type of a [`Poll<T>`].
- ///
- /// When combined with the `?` operator, this function will
- /// propagate any [`Poll::Pending`] values to the caller, and
- /// extract the `T` from [`Poll::Ready`].
- ///
- /// # Examples
- ///
- /// ```rust
- /// #![feature(poll_ready)]
- ///
- /// use std::task::{Context, Poll};
- /// use std::future::{self, Future};
- /// use std::pin::Pin;
- ///
- /// pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> {
- /// let mut fut = future::ready(42);
- /// let fut = Pin::new(&mut fut);
- ///
- /// let num = fut.poll(cx).ready()?;
- /// # drop(num);
- /// // ... use num
- ///
- /// Poll::Ready(())
- /// }
- /// ```
- #[inline]
- #[unstable(feature = "poll_ready", issue = "89780")]
- pub fn ready(self) -> Ready<T> {
- Ready(self)
- }
}
impl<T, E> Poll<Result<T, E>> {
@@ -247,8 +214,7 @@ impl<T, E> Poll<Option<Result<T, E>>> {
}
#[stable(feature = "futures_api", since = "1.36.0")]
-#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
-impl<T> const From<T> for Poll<T> {
+impl<T> From<T> for Poll<T> {
/// Moves the value into a [`Poll::Ready`] to make a `Poll<T>`.
///
/// # Example
diff --git a/library/core/src/task/ready.rs b/library/core/src/task/ready.rs
index b1daf545f..495d72fd1 100644
--- a/library/core/src/task/ready.rs
+++ b/library/core/src/task/ready.rs
@@ -1,8 +1,3 @@
-use core::convert;
-use core::fmt;
-use core::ops::{ControlFlow, FromResidual, Try};
-use core::task::Poll;
-
/// Extracts the successful type of a [`Poll<T>`].
///
/// This macro bakes in propagation of [`Pending`] signals by returning early.
@@ -22,7 +17,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 +39,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(())
@@ -60,55 +55,3 @@ pub macro ready($e:expr) {
}
}
}
-
-/// Extracts the successful type of a [`Poll<T>`].
-///
-/// See [`Poll::ready`] for details.
-#[unstable(feature = "poll_ready", issue = "89780")]
-pub struct Ready<T>(pub(crate) Poll<T>);
-
-#[unstable(feature = "poll_ready", issue = "89780")]
-impl<T> Try for Ready<T> {
- type Output = T;
- type Residual = Ready<convert::Infallible>;
-
- #[inline]
- fn from_output(output: Self::Output) -> Self {
- Ready(Poll::Ready(output))
- }
-
- #[inline]
- fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
- match self.0 {
- Poll::Ready(v) => ControlFlow::Continue(v),
- Poll::Pending => ControlFlow::Break(Ready(Poll::Pending)),
- }
- }
-}
-
-#[unstable(feature = "poll_ready", issue = "89780")]
-impl<T> FromResidual for Ready<T> {
- #[inline]
- fn from_residual(residual: Ready<convert::Infallible>) -> Self {
- match residual.0 {
- Poll::Pending => Ready(Poll::Pending),
- }
- }
-}
-
-#[unstable(feature = "poll_ready", issue = "89780")]
-impl<T> FromResidual<Ready<convert::Infallible>> for Poll<T> {
- #[inline]
- fn from_residual(residual: Ready<convert::Infallible>) -> Self {
- match residual.0 {
- Poll::Pending => Poll::Pending,
- }
- }
-}
-
-#[unstable(feature = "poll_ready", issue = "89780")]
-impl<T> fmt::Debug for Ready<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_tuple("Ready").finish()
- }
-}
diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs
index 808825326..7043ab5ff 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/src/time.rs b/library/core/src/time.rs
index ba1cb6efa..b08d5782a 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -735,8 +735,7 @@ impl Duration {
#[stable(feature = "duration_float", since = "1.38.0")]
#[must_use]
#[inline]
- #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
- pub const fn from_secs_f64(secs: f64) -> Duration {
+ pub fn from_secs_f64(secs: f64) -> Duration {
match Duration::try_from_secs_f64(secs) {
Ok(v) => v,
Err(e) => panic!("{}", e.description()),
@@ -773,8 +772,7 @@ impl Duration {
#[stable(feature = "duration_float", since = "1.38.0")]
#[must_use]
#[inline]
- #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
- pub const fn from_secs_f32(secs: f32) -> Duration {
+ pub fn from_secs_f32(secs: f32) -> Duration {
match Duration::try_from_secs_f32(secs) {
Ok(v) => v,
Err(e) => panic!("{}", e.description()),
@@ -798,8 +796,7 @@ impl Duration {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
- pub const fn mul_f64(self, rhs: f64) -> Duration {
+ pub fn mul_f64(self, rhs: f64) -> Duration {
Duration::from_secs_f64(rhs * self.as_secs_f64())
}
@@ -820,8 +817,7 @@ impl Duration {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
- pub const fn mul_f32(self, rhs: f32) -> Duration {
+ pub fn mul_f32(self, rhs: f32) -> Duration {
Duration::from_secs_f32(rhs * self.as_secs_f32())
}
@@ -842,8 +838,7 @@ impl Duration {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
- pub const fn div_f64(self, rhs: f64) -> Duration {
+ pub fn div_f64(self, rhs: f64) -> Duration {
Duration::from_secs_f64(self.as_secs_f64() / rhs)
}
@@ -866,8 +861,7 @@ impl Duration {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
- pub const fn div_f32(self, rhs: f32) -> Duration {
+ pub fn div_f32(self, rhs: f32) -> Duration {
Duration::from_secs_f32(self.as_secs_f32() / rhs)
}
@@ -1178,7 +1172,7 @@ impl fmt::Debug for Duration {
emit_without_padding(f)
} else {
// We need to add padding. Use the `Formatter::padding` helper function.
- let default_align = crate::fmt::rt::v1::Alignment::Left;
+ let default_align = fmt::Alignment::Left;
let post_padding = f.padding(requested_w - actual_w, default_align)?;
emit_without_padding(f)?;
post_padding.write(f)
@@ -1402,9 +1396,8 @@ impl Duration {
/// assert_eq!(res, Ok(Duration::new(1, 2_929_688)));
/// ```
#[stable(feature = "duration_checked_float", since = "1.66.0")]
- #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
#[inline]
- pub const fn try_from_secs_f32(secs: f32) -> Result<Duration, TryFromFloatSecsError> {
+ pub fn try_from_secs_f32(secs: f32) -> Result<Duration, TryFromFloatSecsError> {
try_from_secs!(
secs = secs,
mantissa_bits = 23,
@@ -1479,9 +1472,8 @@ impl Duration {
/// assert_eq!(res, Ok(Duration::new(1, 2_929_688)));
/// ```
#[stable(feature = "duration_checked_float", since = "1.66.0")]
- #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
#[inline]
- pub const fn try_from_secs_f64(secs: f64) -> Result<Duration, TryFromFloatSecsError> {
+ pub fn try_from_secs_f64(secs: f64) -> Result<Duration, TryFromFloatSecsError> {
try_from_secs!(
secs = secs,
mantissa_bits = 52,
diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs
index 0620e7173..a1388dfee 100644
--- a/library/core/src/tuple.rs
+++ b/library/core/src/tuple.rs
@@ -1,7 +1,6 @@
// See src/libstd/primitive_docs.rs for documentation.
use crate::cmp::Ordering::{self, *};
-use crate::mem::transmute;
// Recursive macro for implementing n-ary tuple functions and operations
//
@@ -22,8 +21,7 @@ macro_rules! tuple_impls {
maybe_tuple_doc! {
$($T)+ @
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
- impl<$($T: ~const PartialEq),+> const PartialEq for ($($T,)+)
+ impl<$($T: PartialEq),+> PartialEq for ($($T,)+)
where
last_type!($($T,)+): ?Sized
{
@@ -50,8 +48,7 @@ macro_rules! tuple_impls {
maybe_tuple_doc! {
$($T)+ @
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
- impl<$($T: ~const PartialOrd + ~const PartialEq),+> const PartialOrd for ($($T,)+)
+ impl<$($T: PartialOrd),+> PartialOrd for ($($T,)+)
where
last_type!($($T,)+): ?Sized
{
@@ -81,8 +78,7 @@ macro_rules! tuple_impls {
maybe_tuple_doc! {
$($T)+ @
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
- impl<$($T: ~const Ord),+> const Ord for ($($T,)+)
+ impl<$($T: Ord),+> Ord for ($($T,)+)
where
last_type!($($T,)+): ?Sized
{
@@ -96,14 +92,33 @@ macro_rules! tuple_impls {
maybe_tuple_doc! {
$($T)+ @
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
- impl<$($T: ~const Default),+> const Default for ($($T,)+) {
+ impl<$($T: Default),+> Default for ($($T,)+) {
#[inline]
fn default() -> ($($T,)+) {
($({ let x: $T = Default::default(); x},)+)
}
}
}
+
+ #[stable(feature = "array_tuple_conv", since = "1.71.0")]
+ impl<T> From<[T; ${count(T)}]> for ($(${ignore(T)} T,)+) {
+ #[inline]
+ #[allow(non_snake_case)]
+ fn from(array: [T; ${count(T)}]) -> Self {
+ let [$($T,)+] = array;
+ ($($T,)+)
+ }
+ }
+
+ #[stable(feature = "array_tuple_conv", since = "1.71.0")]
+ impl<T> From<($(${ignore(T)} T,)+)> for [T; ${count(T)}] {
+ #[inline]
+ #[allow(non_snake_case)]
+ fn from(tuple: ($(${ignore(T)} T,)+)) -> Self {
+ let ($($T,)+) = tuple;
+ [$($T,)+]
+ }
+ }
}
}
@@ -126,16 +141,13 @@ macro_rules! maybe_tuple_doc {
#[inline]
const fn ordering_is_some(c: Option<Ordering>, x: Ordering) -> bool {
// FIXME: Just use `==` once that's const-stable on `Option`s.
- // This isn't using `match` because that optimizes worse due to
- // making a two-step check (`Some` *then* the inner value).
-
- // SAFETY: There's no public guarantee for `Option<Ordering>`,
- // but we're core so we know that it's definitely a byte.
- unsafe {
- let c: i8 = transmute(c);
- let x: i8 = transmute(Some(x));
- c == x
- }
+ // This is mapping `None` to 2 and then doing the comparison afterwards
+ // because it optimizes better (`None::<Ordering>` is represented as 2).
+ x as i8
+ == match c {
+ Some(c) => c as i8,
+ None => 2,
+ }
}
// Constructs an expression that performs a lexical ordering using method `$rel`.
diff --git a/library/core/tests/asserting.rs b/library/core/tests/asserting.rs
index 4b626ba6f..1d9670886 100644
--- a/library/core/tests/asserting.rs
+++ b/library/core/tests/asserting.rs
@@ -24,7 +24,7 @@ struct NoCopyNoDebug;
struct NoDebug;
test!(
- capture_with_non_copyable_and_non_debugabble_elem_has_correct_params,
+ capture_with_non_copyable_and_non_debuggable_elem_has_correct_params,
NoCopyNoDebug,
None,
"N/A"
@@ -32,6 +32,6 @@ test!(
test!(capture_with_non_copyable_elem_has_correct_params, NoCopy, None, "N/A");
-test!(capture_with_non_debugabble_elem_has_correct_params, NoDebug, None, "N/A");
+test!(capture_with_non_debuggable_elem_has_correct_params, NoDebug, None, "N/A");
-test!(capture_with_copyable_and_debugabble_elem_has_correct_params, 1i32, Some(1i32), "1");
+test!(capture_with_copyable_and_debuggable_elem_has_correct_params, 1i32, Some(1i32), "1");
diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs
index 94b031060..a67a842d3 100644
--- a/library/core/tests/atomic.rs
+++ b/library/core/tests/atomic.rs
@@ -306,9 +306,11 @@ fn atomic_compare_exchange() {
ATOMIC.compare_exchange_weak(0, 1, SeqCst, SeqCst).ok();
}
+/* FIXME(#110395)
#[test]
fn atomic_const_from() {
const _ATOMIC_U8: AtomicU8 = AtomicU8::from(1);
const _ATOMIC_BOOL: AtomicBool = AtomicBool::from(true);
const _ATOMIC_PTR: AtomicPtr<u32> = AtomicPtr::from(core::ptr::null_mut());
}
+*/
diff --git a/library/core/tests/bool.rs b/library/core/tests/bool.rs
index 4819ce911..47f645991 100644
--- a/library/core/tests/bool.rs
+++ b/library/core/tests/bool.rs
@@ -89,6 +89,7 @@ fn test_bool_to_option() {
assert_eq!(false.then(|| 0), None);
assert_eq!(true.then(|| 0), Some(0));
+ /* FIXME(#110395)
const fn zero() -> i32 {
0
}
@@ -102,4 +103,5 @@ fn test_bool_to_option() {
assert_eq!(B, Some(0));
assert_eq!(C, None);
assert_eq!(D, Some(0));
+ */
}
diff --git a/library/core/tests/cell.rs b/library/core/tests/cell.rs
index 7b77b2134..e084f8679 100644
--- a/library/core/tests/cell.rs
+++ b/library/core/tests/cell.rs
@@ -468,6 +468,7 @@ fn const_cells() {
const CELL: Cell<i32> = Cell::new(3);
const _: i32 = CELL.into_inner();
+/* FIXME(#110395)
const UNSAFE_CELL_FROM: UnsafeCell<i32> = UnsafeCell::from(3);
const _: i32 = UNSAFE_CELL.into_inner();
@@ -476,4 +477,5 @@ fn const_cells() {
const CELL_FROM: Cell<i32> = Cell::from(3);
const _: i32 = CELL.into_inner();
+*/
}
diff --git a/library/core/tests/char.rs b/library/core/tests/char.rs
index ac0b2ca16..85ba51c92 100644
--- a/library/core/tests/char.rs
+++ b/library/core/tests/char.rs
@@ -21,6 +21,7 @@ fn test_convert() {
assert!(char::try_from(0xFFFF_FFFF_u32).is_err());
}
+/* FIXME(#110395)
#[test]
const fn test_convert_const() {
assert!(u32::from('a') == 0x61);
@@ -30,6 +31,7 @@ const fn test_convert_const() {
assert!(char::from(b'a') == 'a');
assert!(char::from(b'\xFF') == '\u{FF}');
}
+*/
#[test]
fn test_from_str() {
diff --git a/library/core/tests/clone.rs b/library/core/tests/clone.rs
index 33ca9f2c6..aafe5ced2 100644
--- a/library/core/tests/clone.rs
+++ b/library/core/tests/clone.rs
@@ -1,4 +1,5 @@
#[test]
+#[cfg_attr(not(bootstrap), allow(suspicious_double_ref_op))]
fn test_borrowed_clone() {
let x = 5;
let y: &i32 = &x;
diff --git a/library/core/tests/cmp.rs b/library/core/tests/cmp.rs
index 8d0e59d5a..72fdd490d 100644
--- a/library/core/tests/cmp.rs
+++ b/library/core/tests/cmp.rs
@@ -217,18 +217,19 @@ fn cmp_default() {
assert_eq!(Fool(false), Fool(true));
}
+/* FIXME(#110395)
mod const_cmp {
use super::*;
struct S(i32);
- impl const PartialEq for S {
+ impl PartialEq for S {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
- impl const PartialOrd for S {
+ impl PartialOrd for S {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
let ret = match (self.0, other.0) {
(a, b) if a > b => Ordering::Greater,
@@ -248,3 +249,4 @@ mod const_cmp {
const _: () = assert!(S(0) < S(1));
const _: () = assert!(S(1) > S(0));
}
+*/
diff --git a/library/core/tests/convert.rs b/library/core/tests/convert.rs
index f1048f4cf..f76dd2778 100644
--- a/library/core/tests/convert.rs
+++ b/library/core/tests/convert.rs
@@ -1,3 +1,4 @@
+/* FIXME(#110395)
#[test]
fn convert() {
const fn from(x: i32) -> i32 {
@@ -14,3 +15,4 @@ fn convert() {
const BAR: Vec<String> = into(Vec::new());
assert_eq!(BAR, Vec::<String>::new());
}
+*/
diff --git a/library/core/tests/hash/mod.rs b/library/core/tests/hash/mod.rs
index 267245f05..033bd1ed6 100644
--- a/library/core/tests/hash/mod.rs
+++ b/library/core/tests/hash/mod.rs
@@ -9,13 +9,13 @@ struct MyHasher {
hash: u64,
}
-impl const Default for MyHasher {
+impl Default for MyHasher {
fn default() -> MyHasher {
MyHasher { hash: 0 }
}
}
-impl const Hasher for MyHasher {
+impl Hasher for MyHasher {
fn write(&mut self, buf: &[u8]) {
// FIXME(const_trait_impl): change to for loop
let mut i = 0;
@@ -35,13 +35,14 @@ impl const Hasher for MyHasher {
#[test]
fn test_writer_hasher() {
- const fn hash<T: ~const Hash>(t: &T) -> u64 {
+ // FIXME(#110395)
+ /* const */ fn hash<T: Hash>(t: &T) -> u64 {
let mut s = MyHasher { hash: 0 };
t.hash(&mut s);
s.finish()
}
- const {
+ /* const {
// FIXME(fee1-dead): assert_eq
assert!(hash(&()) == 0);
assert!(hash(&5_u8) == 5);
@@ -52,7 +53,7 @@ fn test_writer_hasher() {
let s: &str = "a";
assert!(hash(&s) == 97 + 0xFF);
- };
+ }; */
assert_eq!(hash(&()), 0);
@@ -113,7 +114,7 @@ struct CustomHasher {
output: u64,
}
-impl const Hasher for CustomHasher {
+impl Hasher for CustomHasher {
fn finish(&self) -> u64 {
self.output
}
@@ -125,21 +126,22 @@ impl const Hasher for CustomHasher {
}
}
-impl const Default for CustomHasher {
+impl Default for CustomHasher {
fn default() -> CustomHasher {
CustomHasher { output: 0 }
}
}
-impl const Hash for Custom {
- fn hash<H: ~const Hasher>(&self, state: &mut H) {
+impl Hash for Custom {
+ fn hash<H: Hasher>(&self, state: &mut H) {
state.write_u64(self.hash);
}
}
#[test]
fn test_custom_state() {
- const fn hash<T: ~const Hash>(t: &T) -> u64 {
+ // FIXME(#110395)
+ /* const */ fn hash<T: Hash>(t: &T) -> u64 {
let mut c = CustomHasher { output: 0 };
t.hash(&mut c);
c.finish()
@@ -147,7 +149,7 @@ fn test_custom_state() {
assert_eq!(hash(&Custom { hash: 5 }), 5);
- const { assert!(hash(&Custom { hash: 6 }) == 6) };
+ // const { assert!(hash(&Custom { hash: 6 }) == 6) };
}
// FIXME: Instantiated functions with i128 in the signature is not supported in Emscripten.
diff --git a/library/core/tests/hash/sip.rs b/library/core/tests/hash/sip.rs
index 3abf6efcf..0a67c485c 100644
--- a/library/core/tests/hash/sip.rs
+++ b/library/core/tests/hash/sip.rs
@@ -23,12 +23,13 @@ fn hash<T: Hash>(x: &T) -> u64 {
hash_with(SipHasher::new(), x)
}
+/* FIXME(#110395)
#[test]
const fn test_const_sip() {
let val1 = 0x45;
let val2 = 0xfeed;
- const fn const_hash<T: ~const Hash>(x: &T) -> u64 {
+ const fn const_hash<T: Hash>(x: &T) -> u64 {
let mut st = SipHasher::new();
x.hash(&mut st);
st.finish()
@@ -36,6 +37,7 @@ const fn test_const_sip() {
assert!(const_hash(&(val1)) != const_hash(&(val2)));
}
+*/
#[test]
#[allow(unused_must_use)]
diff --git a/library/core/tests/lazy.rs b/library/core/tests/lazy.rs
index c7c3c479b..7f7f1f005 100644
--- a/library/core/tests/lazy.rs
+++ b/library/core/tests/lazy.rs
@@ -10,7 +10,7 @@ fn once_cell() {
c.get_or_init(|| 92);
assert_eq!(c.get(), Some(&92));
- c.get_or_init(|| panic!("Kabom!"));
+ c.get_or_init(|| panic!("Kaboom!"));
assert_eq!(c.get(), Some(&92));
}
@@ -46,11 +46,13 @@ fn unsync_once_cell_drop_empty() {
drop(x);
}
+/* FIXME(#110395)
#[test]
const fn once_cell_const() {
let _once_cell: OnceCell<u32> = OnceCell::new();
let _once_cell: OnceCell<u32> = OnceCell::from(32);
}
+*/
#[test]
fn clone() {
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 6cdafa411..3933e3289 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -8,20 +8,16 @@
#![feature(const_assume)]
#![feature(const_align_of_val_raw)]
#![feature(const_black_box)]
-#![feature(const_bool_to_option)]
#![feature(const_caller_location)]
#![feature(const_cell_into_inner)]
-#![feature(const_convert)]
#![feature(const_hash)]
#![feature(const_heap)]
#![feature(const_maybe_uninit_as_mut_ptr)]
#![feature(const_maybe_uninit_assume_init_read)]
#![feature(const_nonnull_new)]
-#![feature(const_num_from_num)]
#![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)]
@@ -57,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)]
@@ -112,6 +109,7 @@
#![feature(utf8_chunks)]
#![feature(is_ascii_octdigit)]
#![feature(get_many_mut)]
+#![cfg_attr(not(bootstrap), feature(offset_of))]
#![deny(unsafe_op_in_unsafe_fn)]
#![deny(fuzzy_provenance_casts)]
diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs
index f7740a114..aee9c89b5 100644
--- a/library/core/tests/mem.rs
+++ b/library/core/tests/mem.rs
@@ -364,3 +364,213 @@ fn const_maybe_uninit() {
assert_eq!(FIELD_BY_FIELD, Foo { x: 1, y: 2 });
}
+
+#[test]
+#[cfg(not(bootstrap))]
+fn offset_of() {
+ #[repr(C)]
+ struct Foo {
+ x: u8,
+ y: u16,
+ z: Bar,
+ }
+
+ #[repr(C)]
+ struct Bar(u8, u8);
+
+ assert_eq!(offset_of!(Foo, x), 0);
+ assert_eq!(offset_of!(Foo, y), 2);
+ assert_eq!(offset_of!(Foo, z.0), 4);
+ assert_eq!(offset_of!(Foo, z.1), 5);
+
+ // Layout of tuples is unstable
+ assert!(offset_of!((u8, u16), 0) <= size_of::<(u8, u16)>() - 1);
+ assert!(offset_of!((u8, u16), 1) <= size_of::<(u8, u16)>() - 2);
+
+ #[repr(C)]
+ struct Generic<T> {
+ x: u8,
+ y: u32,
+ z: T
+ }
+
+ trait Trait {}
+
+ // Ensure that this type of generics works
+ fn offs_of_z<T>() -> usize {
+ offset_of!(Generic<T>, z)
+ }
+
+ assert_eq!(offset_of!(Generic<u8>, z), 8);
+ assert_eq!(offs_of_z::<u8>(), 8);
+
+ // Ensure that it works with the implicit lifetime in `Box<dyn Trait + '_>`.
+ assert_eq!(offset_of!(Generic<Box<dyn Trait>>, z), 8);
+}
+
+#[test]
+#[cfg(not(bootstrap))]
+fn offset_of_union() {
+ #[repr(C)]
+ union Foo {
+ x: u8,
+ y: u16,
+ z: Bar,
+ }
+
+ #[repr(C)]
+ #[derive(Copy, Clone)]
+ struct Bar(u8, u8);
+
+ assert_eq!(offset_of!(Foo, x), 0);
+ assert_eq!(offset_of!(Foo, y), 0);
+ assert_eq!(offset_of!(Foo, z.0), 0);
+ assert_eq!(offset_of!(Foo, z.1), 1);
+}
+
+#[test]
+#[cfg(not(bootstrap))]
+fn offset_of_dst() {
+ #[repr(C)]
+ struct Alpha {
+ x: u8,
+ y: u16,
+ z: [u8],
+ }
+
+ trait Trait {}
+
+ #[repr(C)]
+ struct Beta {
+ x: u8,
+ y: u16,
+ z: dyn Trait,
+ }
+
+ extern "C" {
+ type Extern;
+ }
+
+ #[repr(C)]
+ struct Gamma {
+ x: u8,
+ y: u16,
+ z: Extern,
+ }
+
+ assert_eq!(offset_of!(Alpha, x), 0);
+ assert_eq!(offset_of!(Alpha, y), 2);
+
+ assert_eq!(offset_of!(Beta, x), 0);
+ assert_eq!(offset_of!(Beta, y), 2);
+
+ assert_eq!(offset_of!(Gamma, x), 0);
+ assert_eq!(offset_of!(Gamma, y), 2);
+}
+
+#[test]
+#[cfg(not(bootstrap))]
+fn offset_of_packed() {
+ #[repr(C, packed)]
+ struct Foo {
+ x: u8,
+ y: u16,
+ }
+
+ assert_eq!(offset_of!(Foo, x), 0);
+ assert_eq!(offset_of!(Foo, y), 1);
+}
+
+#[test]
+#[cfg(not(bootstrap))]
+fn offset_of_projection() {
+ #[repr(C)]
+ struct Foo {
+ x: u8,
+ y: u16,
+ }
+
+ trait Projector {
+ type Type;
+ }
+
+ impl Projector for () {
+ type Type = Foo;
+ }
+
+ assert_eq!(offset_of!(<() as Projector>::Type, x), 0);
+ assert_eq!(offset_of!(<() as Projector>::Type, y), 2);
+}
+
+#[test]
+#[cfg(not(bootstrap))]
+fn offset_of_alias() {
+ #[repr(C)]
+ struct Foo {
+ x: u8,
+ y: u16,
+ }
+
+ type Bar = Foo;
+
+ assert_eq!(offset_of!(Bar, x), 0);
+ assert_eq!(offset_of!(Bar, y), 2);
+}
+
+#[test]
+#[cfg(not(bootstrap))]
+fn const_offset_of() {
+ #[repr(C)]
+ struct Foo {
+ x: u8,
+ y: u16,
+ }
+
+ const X_OFFSET: usize = offset_of!(Foo, x);
+ const Y_OFFSET: usize = offset_of!(Foo, y);
+
+ assert_eq!(X_OFFSET, 0);
+ assert_eq!(Y_OFFSET, 2);
+}
+
+#[test]
+#[cfg(not(bootstrap))]
+fn offset_of_without_const_promotion() {
+ #[repr(C)]
+ struct Foo<SuppressConstPromotion> {
+ x: u8,
+ y: u16,
+ _scp: SuppressConstPromotion,
+ }
+
+ // Normally, offset_of is always const promoted.
+ // The generic parameter prevents this from happening.
+ // This is needed to test the codegen impl of offset_of
+ fn inner<SuppressConstPromotion>() {
+ assert_eq!(offset_of!(Foo<SuppressConstPromotion>, x), 0);
+ assert_eq!(offset_of!(Foo<SuppressConstPromotion>, y), 2);
+ }
+
+ inner::<()>();
+}
+
+#[test]
+#[cfg(not(bootstrap))]
+fn offset_of_addr() {
+ #[repr(C)]
+ struct Foo {
+ x: u8,
+ y: u16,
+ z: Bar,
+ }
+
+ #[repr(C)]
+ struct Bar(u8, u8);
+
+ let base = Foo { x: 0, y: 0, z: Bar(0, 0) };
+
+ assert_eq!(ptr::addr_of!(base).addr() + offset_of!(Foo, x), ptr::addr_of!(base.x).addr());
+ assert_eq!(ptr::addr_of!(base).addr() + offset_of!(Foo, y), ptr::addr_of!(base.y).addr());
+ assert_eq!(ptr::addr_of!(base).addr() + offset_of!(Foo, z.0), ptr::addr_of!(base.z.0).addr());
+ assert_eq!(ptr::addr_of!(base).addr() + offset_of!(Foo, z.1), ptr::addr_of!(base.z.1).addr());
+}
diff --git a/library/core/tests/nonzero.rs b/library/core/tests/nonzero.rs
index a0ca919a8..007f84425 100644
--- a/library/core/tests/nonzero.rs
+++ b/library/core/tests/nonzero.rs
@@ -215,11 +215,13 @@ fn nonzero_const() {
const ONE: Option<NonZeroU8> = NonZeroU8::new(1);
assert!(ONE.is_some());
+ /* FIXME(#110395)
const FROM_NONZERO_U8: u8 = u8::from(NONZERO_U8);
assert_eq!(FROM_NONZERO_U8, 5);
const NONZERO_CONVERT: NonZeroU32 = NonZeroU32::from(NONZERO_U8);
assert_eq!(NONZERO_CONVERT.get(), 5);
+ */
}
#[test]
@@ -334,3 +336,21 @@ fn test_nonzero_uint_rem() {
let x: u32 = 42u32 % nz;
assert_eq!(x, 2u32);
}
+
+#[test]
+fn test_signed_nonzero_neg() {
+ assert_eq!((-NonZeroI8::new(1).unwrap()).get(), -1);
+ assert_eq!((-NonZeroI8::new(-1).unwrap()).get(), 1);
+
+ assert_eq!((-NonZeroI16::new(1).unwrap()).get(), -1);
+ assert_eq!((-NonZeroI16::new(-1).unwrap()).get(), 1);
+
+ assert_eq!((-NonZeroI32::new(1).unwrap()).get(), -1);
+ assert_eq!((-NonZeroI32::new(-1).unwrap()).get(), 1);
+
+ assert_eq!((-NonZeroI64::new(1).unwrap()).get(), -1);
+ assert_eq!((-NonZeroI64::new(-1).unwrap()).get(), 1);
+
+ assert_eq!((-NonZeroI128::new(1).unwrap()).get(), -1);
+ assert_eq!((-NonZeroI128::new(-1).unwrap()).get(), 1);
+}
diff --git a/library/core/tests/num/const_from.rs b/library/core/tests/num/const_from.rs
index aca18ef39..fa58e7718 100644
--- a/library/core/tests/num/const_from.rs
+++ b/library/core/tests/num/const_from.rs
@@ -1,3 +1,4 @@
+/* FIXME(#110395)
#[test]
fn from() {
use core::convert::TryFrom;
@@ -23,3 +24,4 @@ fn from() {
const I16_FROM_U16: Result<i16, TryFromIntError> = i16::try_from(1u16);
assert_eq!(I16_FROM_U16, Ok(1i16));
}
+*/
diff --git a/library/core/tests/num/ieee754.rs b/library/core/tests/num/ieee754.rs
index f6e5dfc98..48ab75b6f 100644
--- a/library/core/tests/num/ieee754.rs
+++ b/library/core/tests/num/ieee754.rs
@@ -39,7 +39,6 @@ macro_rules! assert_biteq {
// ToString uses the default fmt::Display impl without special concerns, and bypasses other parts
// of the formatting infrastructure, which makes it ideal for testing here.
-#[allow(unused_macros)]
macro_rules! roundtrip {
($f:expr => $t:ty) => {
($f).to_string().parse::<$t>().unwrap()
diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs
index 18c55e43a..439bbe669 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 c79e909e4..3f3659ba8 100644
--- a/library/core/tests/num/mod.rs
+++ b/library/core/tests/num/mod.rs
@@ -170,7 +170,7 @@ fn test_can_not_overflow() {
for base in 2..=36 {
let num = (<$t>::MAX as u128) + 1;
- // Calcutate the string length for the smallest overflowing number:
+ // Calculate the string length for the smallest overflowing number:
let max_len_string = format_radix(num, base as u128);
// Ensure that string length is deemed to potentially overflow:
assert!(can_overflow::<$t>(base, &max_len_string));
@@ -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 15ae9f232..7d6203db0 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);
+ }
}
};
}
diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs
index dca6321cf..5defeb50d 100644
--- a/library/core/tests/option.rs
+++ b/library/core/tests/option.rs
@@ -88,6 +88,7 @@ fn test_and() {
assert_eq!(x.and(Some(2)), None);
assert_eq!(x.and(None::<isize>), None);
+ /* FIXME(#110395)
const FOO: Option<isize> = Some(1);
const A: Option<isize> = FOO.and(Some(2));
const B: Option<isize> = FOO.and(None);
@@ -99,6 +100,7 @@ fn test_and() {
const D: Option<isize> = BAR.and(None);
assert_eq!(C, None);
assert_eq!(D, None);
+ */
}
#[test]
@@ -119,6 +121,7 @@ fn test_and_then() {
assert_eq!(x.and_then(plus_one), None);
assert_eq!(x.and_then(none), None);
+ /* FIXME(#110395)
const FOO: Option<isize> = Some(1);
const A: Option<isize> = FOO.and_then(plus_one);
const B: Option<isize> = FOO.and_then(none);
@@ -130,6 +133,7 @@ fn test_and_then() {
const D: Option<isize> = BAR.and_then(none);
assert_eq!(C, None);
assert_eq!(D, None);
+ */
}
#[test]
@@ -142,6 +146,7 @@ fn test_or() {
assert_eq!(x.or(Some(2)), Some(2));
assert_eq!(x.or(None), None);
+ /* FIXME(#110395)
const FOO: Option<isize> = Some(1);
const A: Option<isize> = FOO.or(Some(2));
const B: Option<isize> = FOO.or(None);
@@ -153,6 +158,7 @@ fn test_or() {
const D: Option<isize> = BAR.or(None);
assert_eq!(C, Some(2));
assert_eq!(D, None);
+ */
}
#[test]
@@ -173,6 +179,7 @@ fn test_or_else() {
assert_eq!(x.or_else(two), Some(2));
assert_eq!(x.or_else(none), None);
+/* FIXME(#110395)
const FOO: Option<isize> = Some(1);
const A: Option<isize> = FOO.or_else(two);
const B: Option<isize> = FOO.or_else(none);
@@ -184,6 +191,7 @@ fn test_or_else() {
const D: Option<isize> = BAR.or_else(none);
assert_eq!(C, Some(2));
assert_eq!(D, None);
+*/
}
#[test]
@@ -215,10 +223,12 @@ fn test_unwrap_or() {
let x: Option<isize> = None;
assert_eq!(x.unwrap_or(2), 2);
+ /* FIXME(#110395)
const A: isize = Some(1).unwrap_or(2);
const B: isize = None.unwrap_or(2);
assert_eq!(A, 1);
assert_eq!(B, 2);
+ */
}
#[test]
@@ -233,10 +243,12 @@ fn test_unwrap_or_else() {
let x: Option<isize> = None;
assert_eq!(x.unwrap_or_else(two), 2);
+ /* FIXME(#110395)
const A: isize = Some(1).unwrap_or_else(two);
const B: isize = None.unwrap_or_else(two);
assert_eq!(A, 1);
assert_eq!(B, 2);
+ */
}
#[test]
@@ -439,14 +451,15 @@ fn option_const() {
const OPTION: Option<usize> = Some(32);
assert_eq!(OPTION, Some(32));
- const OPTION_FROM: Option<usize> = Option::from(32);
- assert_eq!(OPTION_FROM, Some(32));
+ // FIXME(#110395)
+ // const OPTION_FROM: Option<usize> = Option::from(32);
+ // assert_eq!(OPTION_FROM, Some(32));
const REF: Option<&usize> = OPTION.as_ref();
assert_eq!(REF, Some(&32));
- const REF_FROM: Option<&usize> = Option::from(&OPTION);
- assert_eq!(REF_FROM, Some(&32));
+ // const REF_FROM: Option<&usize> = Option::from(&OPTION);
+ // assert_eq!(REF_FROM, Some(&32));
const IS_SOME: bool = OPTION.is_some();
assert!(IS_SOME);
@@ -474,7 +487,7 @@ const fn option_const_mut() {
None => unreachable!(),
}
}
-
+/* FIXME(const-hack)
{
let as_mut: Option<&mut usize> = Option::from(&mut option);
match as_mut {
@@ -482,6 +495,7 @@ const fn option_const_mut() {
None => unreachable!(),
}
}
+*/
}
#[test]
diff --git a/library/core/tests/time.rs b/library/core/tests/time.rs
index 2975c81f8..872611937 100644
--- a/library/core/tests/time.rs
+++ b/library/core/tests/time.rs
@@ -425,14 +425,16 @@ fn duration_const() {
const SECONDS_F32: f32 = Duration::SECOND.as_secs_f32();
assert_eq!(SECONDS_F32, 1.0);
- const FROM_SECONDS_F32: Duration = Duration::from_secs_f32(1.0);
- assert_eq!(FROM_SECONDS_F32, Duration::SECOND);
+ // FIXME(#110395)
+ // const FROM_SECONDS_F32: Duration = Duration::from_secs_f32(1.0);
+ // assert_eq!(FROM_SECONDS_F32, Duration::SECOND);
const SECONDS_F64: f64 = Duration::SECOND.as_secs_f64();
assert_eq!(SECONDS_F64, 1.0);
- const FROM_SECONDS_F64: Duration = Duration::from_secs_f64(1.0);
- assert_eq!(FROM_SECONDS_F64, Duration::SECOND);
+ // FIXME(#110395)
+ // const FROM_SECONDS_F64: Duration = Duration::from_secs_f64(1.0);
+ // assert_eq!(FROM_SECONDS_F64, Duration::SECOND);
const MILLIS: u128 = Duration::SECOND.as_millis();
assert_eq!(MILLIS, 1_000);
@@ -463,6 +465,7 @@ fn duration_const() {
const CHECKED_MUL: Option<Duration> = Duration::SECOND.checked_mul(1);
assert_eq!(CHECKED_MUL, Some(Duration::SECOND));
+/* FIXME(#110395)
const MUL_F32: Duration = Duration::SECOND.mul_f32(1.0);
assert_eq!(MUL_F32, Duration::SECOND);
@@ -477,6 +480,7 @@ fn duration_const() {
const DIV_F64: Duration = Duration::SECOND.div_f64(1.0);
assert_eq!(DIV_F64, Duration::SECOND);
+*/
const DIV_DURATION_F32: f32 = Duration::SECOND.div_duration_f32(Duration::SECOND);
assert_eq!(DIV_DURATION_F32, 1.0);