Auto merge of #118405 - matthiaskrgr:rollup-3a2eevc, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #115331 (optimize str::iter::Chars::advance_by) - #118236 (Update mod comment) - #118299 (Update `OnceLock` documentation to give a concrete 'lazy static' example, and expand on the existing example.) - #118314 (Rename `{collections=>alloc}{tests,benches}`) - #118341 (Simplify indenting in THIR printing) - #118366 (Detect and reject malformed `repr(Rust)` hints) - #118397 (Fix comments for unsigned non-zero `checked_add`, `saturating_add`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
46a24ed2f4
@ -985,7 +985,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
||||
Ok(literal) => acc.push(ReprPacked(literal)),
|
||||
Err(message) => literal_error = Some(message),
|
||||
};
|
||||
} else if matches!(name, sym::C | sym::simd | sym::transparent)
|
||||
} else if matches!(name, sym::Rust | sym::C | sym::simd | sym::transparent)
|
||||
|| int_type_of_word(name).is_some()
|
||||
{
|
||||
recognised = true;
|
||||
@ -1018,7 +1018,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
||||
});
|
||||
} else if matches!(
|
||||
meta_item.name_or_empty(),
|
||||
sym::C | sym::simd | sym::transparent
|
||||
sym::Rust | sym::C | sym::simd | sym::transparent
|
||||
) || int_type_of_word(meta_item.name_or_empty()).is_some()
|
||||
{
|
||||
recognised = true;
|
||||
@ -1043,7 +1043,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
||||
);
|
||||
} else if matches!(
|
||||
meta_item.name_or_empty(),
|
||||
sym::C | sym::simd | sym::transparent
|
||||
sym::Rust | sym::C | sym::simd | sym::transparent
|
||||
) || int_type_of_word(meta_item.name_or_empty()).is_some()
|
||||
{
|
||||
recognised = true;
|
||||
|
@ -31,8 +31,8 @@ struct ThirPrinter<'a, 'tcx> {
|
||||
|
||||
macro_rules! print_indented {
|
||||
($writer:ident, $s:expr, $indent_lvl:expr) => {
|
||||
let indent = (0..$indent_lvl).map(|_| INDENT).collect::<Vec<_>>().concat();
|
||||
writeln!($writer, "{}{}", indent, $s).expect("unable to write to ThirPrinter");
|
||||
$writer.indent($indent_lvl);
|
||||
writeln!($writer, "{}", $s).expect("unable to write to ThirPrinter");
|
||||
};
|
||||
}
|
||||
|
||||
@ -48,6 +48,12 @@ fn new(thir: &'a Thir<'tcx>) -> Self {
|
||||
Self { thir, fmt: String::new() }
|
||||
}
|
||||
|
||||
fn indent(&mut self, level: usize) {
|
||||
for _ in 0..level {
|
||||
self.fmt.push_str(INDENT);
|
||||
}
|
||||
}
|
||||
|
||||
fn print(&mut self) {
|
||||
print_indented!(self, "params: [", 0);
|
||||
for param in self.thir.params.iter() {
|
||||
|
@ -17,11 +17,11 @@ rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
|
||||
rand_xorshift = "0.3.0"
|
||||
|
||||
[[test]]
|
||||
name = "collectionstests"
|
||||
name = "alloctests"
|
||||
path = "tests/lib.rs"
|
||||
|
||||
[[bench]]
|
||||
name = "collectionsbenches"
|
||||
name = "allocbenches"
|
||||
path = "benches/lib.rs"
|
||||
test = true
|
||||
|
||||
|
@ -1170,6 +1170,17 @@ fn test_iterator() {
|
||||
assert_eq!(s.chars().count(), v.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_advance() {
|
||||
let s = "「赤錆」と呼ばれる鉄錆は、水の存在下での鉄の自然酸化によって生じる、オキシ水酸化鉄(III) 等の(含水)酸化物粒子の疎な凝集膜であるとみなせる。";
|
||||
let chars: Vec<char> = s.chars().collect();
|
||||
let mut it = s.chars();
|
||||
it.advance_by(1).unwrap();
|
||||
assert_eq!(it.next(), Some(chars[1]));
|
||||
it.advance_by(33).unwrap();
|
||||
assert_eq!(it.next(), Some(chars[35]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rev_iterator() {
|
||||
let s = "ศไทย中华Việt Nam";
|
||||
|
@ -5,6 +5,7 @@
|
||||
#![feature(trusted_random_access)]
|
||||
#![feature(iter_array_chunks)]
|
||||
#![feature(iter_next_chunk)]
|
||||
#![feature(iter_advance_by)]
|
||||
|
||||
extern crate test;
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
mod char_count;
|
||||
mod corpora;
|
||||
mod iter;
|
||||
|
||||
#[bench]
|
||||
fn str_validate_emoji(b: &mut Bencher) {
|
||||
|
17
library/core/benches/str/iter.rs
Normal file
17
library/core/benches/str/iter.rs
Normal file
@ -0,0 +1,17 @@
|
||||
use super::corpora;
|
||||
use test::{black_box, Bencher};
|
||||
|
||||
#[bench]
|
||||
fn chars_advance_by_1000(b: &mut Bencher) {
|
||||
b.iter(|| black_box(corpora::ru::LARGE).chars().advance_by(1000));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn chars_advance_by_0010(b: &mut Bencher) {
|
||||
b.iter(|| black_box(corpora::ru::LARGE).chars().advance_by(10));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn chars_advance_by_0001(b: &mut Bencher) {
|
||||
b.iter(|| black_box(corpora::ru::LARGE).chars().advance_by(1));
|
||||
}
|
@ -474,7 +474,7 @@ impl isize {
|
||||
}
|
||||
}
|
||||
|
||||
/// If 6th bit is set ascii is lower case.
|
||||
/// If the 6th bit is set ascii is lower case.
|
||||
const ASCII_CASE_MASK: u8 = 0b0010_0000;
|
||||
|
||||
impl u8 {
|
||||
@ -549,7 +549,7 @@ pub const fn as_ascii(&self) -> Option<ascii::Char> {
|
||||
#[rustc_const_stable(feature = "const_ascii_methods_on_intrinsics", since = "1.52.0")]
|
||||
#[inline]
|
||||
pub const fn to_ascii_uppercase(&self) -> u8 {
|
||||
// Toggle the fifth bit if this is a lowercase letter
|
||||
// Toggle the 6th bit if this is a lowercase letter
|
||||
*self ^ ((self.is_ascii_lowercase() as u8) * ASCII_CASE_MASK)
|
||||
}
|
||||
|
||||
@ -574,7 +574,7 @@ pub const fn to_ascii_uppercase(&self) -> u8 {
|
||||
#[rustc_const_stable(feature = "const_ascii_methods_on_intrinsics", since = "1.52.0")]
|
||||
#[inline]
|
||||
pub const fn to_ascii_lowercase(&self) -> u8 {
|
||||
// Set the fifth bit if this is an uppercase letter
|
||||
// Set the 6th bit if this is an uppercase letter
|
||||
*self | (self.is_ascii_uppercase() as u8 * ASCII_CASE_MASK)
|
||||
}
|
||||
|
||||
|
@ -355,7 +355,7 @@ pub const fn checked_add(self, other: $Int) -> Option<$Ty> {
|
||||
if let Some(result) = self.get().checked_add(other) {
|
||||
// SAFETY:
|
||||
// - `checked_add` returns `None` on overflow
|
||||
// - `self` and `other` are non-zero
|
||||
// - `self` is non-zero
|
||||
// - the only way to get zero from an addition without overflow is for both
|
||||
// sides to be zero
|
||||
//
|
||||
@ -393,7 +393,7 @@ pub const fn checked_add(self, other: $Int) -> Option<$Ty> {
|
||||
pub const fn saturating_add(self, other: $Int) -> $Ty {
|
||||
// SAFETY:
|
||||
// - `saturating_add` returns `u*::MAX` on overflow, which is non-zero
|
||||
// - `self` and `other` are non-zero
|
||||
// - `self` is non-zero
|
||||
// - the only way to get zero from an addition without overflow is for both
|
||||
// sides to be zero
|
||||
//
|
||||
|
@ -8,6 +8,7 @@
|
||||
use crate::ops::Try;
|
||||
use crate::option;
|
||||
use crate::slice::{self, Split as SliceSplit};
|
||||
use core::num::NonZeroUsize;
|
||||
|
||||
use super::from_utf8_unchecked;
|
||||
use super::pattern::Pattern;
|
||||
@ -49,6 +50,55 @@ fn count(self) -> usize {
|
||||
super::count::count_chars(self.as_str())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_by(&mut self, mut remainder: usize) -> Result<(), NonZeroUsize> {
|
||||
const CHUNK_SIZE: usize = 32;
|
||||
|
||||
if remainder >= CHUNK_SIZE {
|
||||
let mut chunks = self.iter.as_slice().array_chunks::<CHUNK_SIZE>();
|
||||
let mut bytes_skipped: usize = 0;
|
||||
|
||||
while remainder > CHUNK_SIZE
|
||||
&& let Some(chunk) = chunks.next()
|
||||
{
|
||||
bytes_skipped += CHUNK_SIZE;
|
||||
|
||||
let mut start_bytes = [false; CHUNK_SIZE];
|
||||
|
||||
for i in 0..CHUNK_SIZE {
|
||||
start_bytes[i] = !super::validations::utf8_is_cont_byte(chunk[i]);
|
||||
}
|
||||
|
||||
remainder -= start_bytes.into_iter().map(|i| i as u8).sum::<u8>() as usize;
|
||||
}
|
||||
|
||||
// SAFETY: The amount of bytes exists since we just iterated over them,
|
||||
// so advance_by will succeed.
|
||||
unsafe { self.iter.advance_by(bytes_skipped).unwrap_unchecked() };
|
||||
|
||||
// skip trailing continuation bytes
|
||||
while self.iter.len() > 0 {
|
||||
let b = self.iter.as_slice()[0];
|
||||
if !super::validations::utf8_is_cont_byte(b) {
|
||||
break;
|
||||
}
|
||||
// SAFETY: We just peeked at the byte, therefore it exists
|
||||
unsafe { self.iter.advance_by(1).unwrap_unchecked() };
|
||||
}
|
||||
}
|
||||
|
||||
while (remainder > 0) && (self.iter.len() > 0) {
|
||||
remainder -= 1;
|
||||
let b = self.iter.as_slice()[0];
|
||||
let slurp = super::validations::utf8_char_width(b);
|
||||
// SAFETY: utf8 validity requires that the string must contain
|
||||
// the continuation bytes (if any)
|
||||
unsafe { self.iter.advance_by(slurp).unwrap_unchecked() };
|
||||
}
|
||||
|
||||
NonZeroUsize::new(remainder).map_or(Ok(()), Err)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let len = self.iter.len();
|
||||
|
@ -13,22 +13,54 @@
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Using `OnceCell` to store a function’s previously computed value (a.k.a.
|
||||
/// ‘lazy static’ or ‘memoizing’):
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::HashMap;
|
||||
/// use std::sync::OnceLock;
|
||||
///
|
||||
/// fn hash_map() -> &'static HashMap<u32, char> {
|
||||
/// static HASHMAP: OnceLock<HashMap<u32, char>> = OnceLock::new();
|
||||
/// HASHMAP.get_or_init(|| {
|
||||
/// let mut m = HashMap::new();
|
||||
/// m.insert(0, 'a');
|
||||
/// m.insert(1, 'b');
|
||||
/// m.insert(2, 'c');
|
||||
/// m
|
||||
/// })
|
||||
/// }
|
||||
///
|
||||
/// // The `HashMap` is built, stored in the `OnceLock`, and returned.
|
||||
/// let _ = hash_map();
|
||||
///
|
||||
/// // The `HashMap` is retrieved from the `OnceLock` and returned.
|
||||
/// let _ = hash_map();
|
||||
/// ```
|
||||
///
|
||||
/// Writing to a `OnceLock` from a separate thread:
|
||||
///
|
||||
/// ```
|
||||
/// use std::sync::OnceLock;
|
||||
///
|
||||
/// static CELL: OnceLock<String> = OnceLock::new();
|
||||
/// static CELL: OnceLock<usize> = OnceLock::new();
|
||||
///
|
||||
/// // `OnceLock` has not been written to yet.
|
||||
/// assert!(CELL.get().is_none());
|
||||
///
|
||||
/// // Spawn a thread and write to `OnceLock`.
|
||||
/// std::thread::spawn(|| {
|
||||
/// let value: &String = CELL.get_or_init(|| {
|
||||
/// "Hello, World!".to_string()
|
||||
/// });
|
||||
/// assert_eq!(value, "Hello, World!");
|
||||
/// }).join().unwrap();
|
||||
/// let value = CELL.get_or_init(|| 12345);
|
||||
/// assert_eq!(value, &12345);
|
||||
/// })
|
||||
/// .join()
|
||||
/// .unwrap();
|
||||
///
|
||||
/// let value: Option<&String> = CELL.get();
|
||||
/// assert!(value.is_some());
|
||||
/// assert_eq!(value.unwrap().as_str(), "Hello, World!");
|
||||
/// // `OnceLock` now contains the value.
|
||||
/// assert_eq!(
|
||||
/// CELL.get(),
|
||||
/// Some(&12345),
|
||||
/// );
|
||||
/// ```
|
||||
#[stable(feature = "once_cell", since = "1.70.0")]
|
||||
pub struct OnceLock<T> {
|
||||
|
@ -19,6 +19,15 @@
|
||||
//~^ ERROR: incorrect `repr(align)` attribute format
|
||||
struct S4;
|
||||
|
||||
// Regression test for issue #118334:
|
||||
#[repr(Rust(u8))]
|
||||
//~^ ERROR: invalid representation hint
|
||||
#[repr(Rust(0))]
|
||||
//~^ ERROR: invalid representation hint
|
||||
#[repr(Rust = 0)]
|
||||
//~^ ERROR: invalid representation hint
|
||||
struct S5;
|
||||
|
||||
#[repr(i8())]
|
||||
//~^ ERROR: invalid representation hint
|
||||
enum E1 { A, B }
|
@ -1,46 +1,64 @@
|
||||
error[E0552]: incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all
|
||||
--> $DIR/issue-83921-ice.rs:6:8
|
||||
--> $DIR/malformed-repr-hints.rs:6:8
|
||||
|
|
||||
LL | #[repr(packed())]
|
||||
| ^^^^^^^^
|
||||
|
||||
error[E0589]: invalid `repr(align)` attribute: `align` needs an argument
|
||||
--> $DIR/issue-83921-ice.rs:10:8
|
||||
--> $DIR/malformed-repr-hints.rs:10:8
|
||||
|
|
||||
LL | #[repr(align)]
|
||||
| ^^^^^ help: supply an argument here: `align(...)`
|
||||
|
||||
error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
|
||||
--> $DIR/issue-83921-ice.rs:14:8
|
||||
--> $DIR/malformed-repr-hints.rs:14:8
|
||||
|
|
||||
LL | #[repr(align(2, 4))]
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
|
||||
--> $DIR/issue-83921-ice.rs:18:8
|
||||
--> $DIR/malformed-repr-hints.rs:18:8
|
||||
|
|
||||
LL | #[repr(align())]
|
||||
| ^^^^^^^
|
||||
|
||||
error[E0552]: invalid representation hint: `Rust` does not take a parenthesized argument list
|
||||
--> $DIR/malformed-repr-hints.rs:23:8
|
||||
|
|
||||
LL | #[repr(Rust(u8))]
|
||||
| ^^^^^^^^
|
||||
|
||||
error[E0552]: invalid representation hint: `Rust` does not take a parenthesized argument list
|
||||
--> $DIR/malformed-repr-hints.rs:25:8
|
||||
|
|
||||
LL | #[repr(Rust(0))]
|
||||
| ^^^^^^^
|
||||
|
||||
error[E0552]: invalid representation hint: `Rust` does not take a value
|
||||
--> $DIR/malformed-repr-hints.rs:27:8
|
||||
|
|
||||
LL | #[repr(Rust = 0)]
|
||||
| ^^^^^^^^
|
||||
|
||||
error[E0552]: invalid representation hint: `i8` does not take a parenthesized argument list
|
||||
--> $DIR/issue-83921-ice.rs:22:8
|
||||
--> $DIR/malformed-repr-hints.rs:31:8
|
||||
|
|
||||
LL | #[repr(i8())]
|
||||
| ^^^^
|
||||
|
||||
error[E0552]: invalid representation hint: `u32` does not take a parenthesized argument list
|
||||
--> $DIR/issue-83921-ice.rs:26:8
|
||||
--> $DIR/malformed-repr-hints.rs:35:8
|
||||
|
|
||||
LL | #[repr(u32(42))]
|
||||
| ^^^^^^^
|
||||
|
||||
error[E0552]: invalid representation hint: `i64` does not take a value
|
||||
--> $DIR/issue-83921-ice.rs:30:8
|
||||
--> $DIR/malformed-repr-hints.rs:39:8
|
||||
|
|
||||
LL | #[repr(i64 = 2)]
|
||||
| ^^^^^^^
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
error: aborting due to 10 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0552, E0589, E0693.
|
||||
For more information about an error, try `rustc --explain E0552`.
|
Loading…
Reference in New Issue
Block a user