@@ -10,9 +10,10 @@ use crate::ops;
10
10
impl [ u8 ] {
11
11
/// Checks if all bytes in this slice are within the ASCII range.
12
12
#[ stable( feature = "ascii_methods_on_intrinsics" , since = "1.23.0" ) ]
13
+ #[ rustc_const_unstable( feature = "const_slice_is_ascii" , issue = "111090" ) ]
13
14
#[ must_use]
14
15
#[ inline]
15
- pub fn is_ascii ( & self ) -> bool {
16
+ pub const fn is_ascii ( & self ) -> bool {
16
17
is_ascii ( self )
17
18
}
18
19
@@ -21,7 +22,7 @@ impl [u8] {
21
22
#[ unstable( feature = "ascii_char" , issue = "110998" ) ]
22
23
#[ must_use]
23
24
#[ inline]
24
- pub fn as_ascii ( & self ) -> Option < & [ ascii:: Char ] > {
25
+ pub const fn as_ascii ( & self ) -> Option < & [ ascii:: Char ] > {
25
26
if self . is_ascii ( ) {
26
27
// SAFETY: Just checked that it's ASCII
27
28
Some ( unsafe { self . as_ascii_unchecked ( ) } )
@@ -262,7 +263,7 @@ impl<'a> fmt::Debug for EscapeAscii<'a> {
262
263
/// Returns `true` if any byte in the word `v` is nonascii (>= 128). Snarfed
263
264
/// from `../str/mod.rs`, which does something similar for utf8 validation.
264
265
#[ inline]
265
- fn contains_nonascii ( v : usize ) -> bool {
266
+ const fn contains_nonascii ( v : usize ) -> bool {
266
267
const NONASCII_MASK : usize = usize:: repeat_u8 ( 0x80 ) ;
267
268
( NONASCII_MASK & v) != 0
268
269
}
@@ -280,7 +281,7 @@ fn contains_nonascii(v: usize) -> bool {
280
281
/// If any of these loads produces something for which `contains_nonascii`
281
282
/// (above) returns true, then we know the answer is false.
282
283
#[ inline]
283
- fn is_ascii ( s : & [ u8 ] ) -> bool {
284
+ const fn is_ascii ( s : & [ u8 ] ) -> bool {
284
285
const USIZE_SIZE : usize = mem:: size_of :: < usize > ( ) ;
285
286
286
287
let len = s. len ( ) ;
@@ -292,7 +293,16 @@ fn is_ascii(s: &[u8]) -> bool {
292
293
// We also do this for architectures where `size_of::<usize>()` isn't
293
294
// sufficient alignment for `usize`, because it's a weird edge case.
294
295
if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < mem:: align_of :: < usize > ( ) {
295
- return s. iter ( ) . all ( |b| b. is_ascii ( ) ) ;
296
+ // FIXME: once iterators and closures can be used in `const fn`,
297
+ // return s.iter().all(|b| b.is_ascii());
298
+ let mut i = 0 ;
299
+ while i < len {
300
+ if !s[ i] . is_ascii ( ) {
301
+ return false ;
302
+ }
303
+ i += 1 ;
304
+ }
305
+ return true ;
296
306
}
297
307
298
308
// We always read the first word unaligned, which means `align_offset` is
@@ -321,18 +331,26 @@ fn is_ascii(s: &[u8]) -> bool {
321
331
// Paranoia check about alignment, since we're about to do a bunch of
322
332
// unaligned loads. In practice this should be impossible barring a bug in
323
333
// `align_offset` though.
324
- debug_assert_eq ! ( word_ptr. addr( ) % mem:: align_of:: <usize >( ) , 0 ) ;
334
+ // While this method is allowed to spuriously fail in CTFE, if it doesn't
335
+ // have alignment information it should have given a `usize::MAX` for
336
+ // `align_offset` earlier, sending things through the scalar path instead of
337
+ // this one, so this check should pass if it's reachable.
338
+ debug_assert ! ( word_ptr. is_aligned_to( mem:: align_of:: <usize >( ) ) ) ;
325
339
326
340
// Read subsequent words until the last aligned word, excluding the last
327
341
// aligned word by itself to be done in tail check later, to ensure that
328
342
// tail is always one `usize` at most to extra branch `byte_pos == len`.
329
343
while byte_pos < len - USIZE_SIZE {
330
- debug_assert ! (
331
- // Sanity check that the read is in bounds
332
- ( word_ptr. addr( ) + USIZE_SIZE ) <= start. addr( ) . wrapping_add( len) &&
333
- // And that our assumptions about `byte_pos` hold.
334
- ( word_ptr. addr( ) - start. addr( ) ) == byte_pos
335
- ) ;
344
+ // Sanity check that the read is in bounds
345
+ debug_assert ! ( byte_pos + USIZE_SIZE <= len) ;
346
+ // And that our assumptions about `byte_pos` hold.
347
+ debug_assert ! ( matches!(
348
+ word_ptr. cast:: <u8 >( ) . guaranteed_eq( start. wrapping_add( byte_pos) ) ,
349
+ // These are from the same allocation, so will hopefully always be
350
+ // known to match even in CTFE, but if it refuses to compare them
351
+ // that's ok since it's just a debug check anyway.
352
+ None | Some ( true ) ,
353
+ ) ) ;
336
354
337
355
// SAFETY: We know `word_ptr` is properly aligned (because of
338
356
// `align_offset`), and we know that we have enough bytes between `word_ptr` and the end
0 commit comments