Skip to content

Commit 9338dae

Browse files
committed
Auto merge of rust-lang#122483 - matthiaskrgr:rollup-n07dsh5, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - rust-lang#104353 (Add CStr::bytes iterator) - rust-lang#119676 (rustdoc-search: search types by higher-order functions) - rust-lang#120699 (Document `TRACK_DIAGNOSTIC` calls.) - rust-lang#121899 (Document how removing a type's field can be bad and what to do instead) - rust-lang#122405 (Add methods to create StableMIR constant) - rust-lang#122416 (Various style improvements to `rustc_lint::levels`) - rust-lang#122421 (Improve `Step` docs) - rust-lang#122440 (const-eval: organize and extend tests for required-consts) - rust-lang#122461 (fix unsoundness in Step::forward_unchecked for signed integers) Failed merges: - rust-lang#122397 (Various cleanups around the const eval query providers) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 9ab7ca4 + 2cdbd5b commit 9338dae

File tree

3 files changed

+131
-10
lines changed

3 files changed

+131
-10
lines changed

core/src/ffi/c_str.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@ use crate::error::Error;
55
use crate::ffi::c_char;
66
use crate::fmt;
77
use crate::intrinsics;
8+
use crate::iter::FusedIterator;
9+
use crate::marker::PhantomData;
810
use crate::ops;
911
use crate::ptr::addr_of;
12+
use crate::ptr::NonNull;
1013
use crate::slice;
1114
use crate::slice::memchr;
1215
use crate::str;
@@ -504,6 +507,13 @@ impl CStr {
504507
self.inner.as_ptr()
505508
}
506509

510+
/// We could eventually expose this publicly, if we wanted.
511+
#[inline]
512+
#[must_use]
513+
const fn as_non_null_ptr(&self) -> NonNull<c_char> {
514+
NonNull::from(&self.inner).as_non_null_ptr()
515+
}
516+
507517
/// Returns the length of `self`. Like C's `strlen`, this does not include the nul terminator.
508518
///
509519
/// > **Note**: This method is currently implemented as a constant-time
@@ -617,6 +627,26 @@ impl CStr {
617627
unsafe { &*(addr_of!(self.inner) as *const [u8]) }
618628
}
619629

630+
/// Iterates over the bytes in this C string.
631+
///
632+
/// The returned iterator will **not** contain the trailing nul terminator
633+
/// that this C string has.
634+
///
635+
/// # Examples
636+
///
637+
/// ```
638+
/// #![feature(cstr_bytes)]
639+
/// use std::ffi::CStr;
640+
///
641+
/// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
642+
/// assert!(cstr.bytes().eq(*b"foo"));
643+
/// ```
644+
#[inline]
645+
#[unstable(feature = "cstr_bytes", issue = "112115")]
646+
pub fn bytes(&self) -> Bytes<'_> {
647+
Bytes::new(self)
648+
}
649+
620650
/// Yields a <code>&[str]</code> slice if the `CStr` contains valid UTF-8.
621651
///
622652
/// If the contents of the `CStr` are valid UTF-8 data, this
@@ -735,3 +765,64 @@ const unsafe fn const_strlen(ptr: *const c_char) -> usize {
735765
intrinsics::const_eval_select((ptr,), strlen_ct, strlen_rt)
736766
}
737767
}
768+
769+
/// An iterator over the bytes of a [`CStr`], without the nul terminator.
770+
///
771+
/// This struct is created by the [`bytes`] method on [`CStr`].
772+
/// See its documentation for more.
773+
///
774+
/// [`bytes`]: CStr::bytes
775+
#[must_use = "iterators are lazy and do nothing unless consumed"]
776+
#[unstable(feature = "cstr_bytes", issue = "112115")]
777+
#[derive(Clone, Debug)]
778+
pub struct Bytes<'a> {
779+
// since we know the string is nul-terminated, we only need one pointer
780+
ptr: NonNull<u8>,
781+
phantom: PhantomData<&'a u8>,
782+
}
783+
impl<'a> Bytes<'a> {
784+
#[inline]
785+
fn new(s: &'a CStr) -> Self {
786+
Self { ptr: s.as_non_null_ptr().cast(), phantom: PhantomData }
787+
}
788+
789+
#[inline]
790+
fn is_empty(&self) -> bool {
791+
// SAFETY: We uphold that the pointer is always valid to dereference
792+
// by starting with a valid C string and then never incrementing beyond
793+
// the nul terminator.
794+
unsafe { self.ptr.read() == 0 }
795+
}
796+
}
797+
798+
#[unstable(feature = "cstr_bytes", issue = "112115")]
799+
impl Iterator for Bytes<'_> {
800+
type Item = u8;
801+
802+
#[inline]
803+
fn next(&mut self) -> Option<u8> {
804+
// SAFETY: We only choose a pointer from a valid C string, which must
805+
// be non-null and contain at least one value. Since we always stop at
806+
// the nul terminator, which is guaranteed to exist, we can assume that
807+
// the pointer is non-null and valid. This lets us safely dereference
808+
// it and assume that adding 1 will create a new, non-null, valid
809+
// pointer.
810+
unsafe {
811+
let ret = self.ptr.read();
812+
if ret == 0 {
813+
None
814+
} else {
815+
self.ptr = self.ptr.offset(1);
816+
Some(ret)
817+
}
818+
}
819+
}
820+
821+
#[inline]
822+
fn size_hint(&self) -> (usize, Option<usize>) {
823+
if self.is_empty() { (0, Some(0)) } else { (1, None) }
824+
}
825+
}
826+
827+
#[unstable(feature = "cstr_bytes", issue = "112115")]
828+
impl FusedIterator for Bytes<'_> {}

core/src/iter/range.rs

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ unsafe_impl_trusted_step![AsciiChar char i8 i16 i32 i64 i128 isize u8 u16 u32 u6
2222
///
2323
/// The *successor* operation moves towards values that compare greater.
2424
/// The *predecessor* operation moves towards values that compare lesser.
25-
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
25+
#[unstable(feature = "step_trait", issue = "42168")]
2626
pub trait Step: Clone + PartialOrd + Sized {
2727
/// Returns the number of *successor* steps required to get from `start` to `end`.
2828
///
@@ -52,15 +52,12 @@ pub trait Step: Clone + PartialOrd + Sized {
5252
/// For any `a`, `n`, and `m`:
5353
///
5454
/// * `Step::forward_checked(a, n).and_then(|x| Step::forward_checked(x, m)) == Step::forward_checked(a, m).and_then(|x| Step::forward_checked(x, n))`
55-
///
56-
/// For any `a`, `n`, and `m` where `n + m` does not overflow:
57-
///
58-
/// * `Step::forward_checked(a, n).and_then(|x| Step::forward_checked(x, m)) == Step::forward_checked(a, n + m)`
55+
/// * `Step::forward_checked(a, n).and_then(|x| Step::forward_checked(x, m)) == try { Step::forward_checked(a, n.checked_add(m)) }`
5956
///
6057
/// For any `a` and `n`:
6158
///
6259
/// * `Step::forward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::forward_checked(&x, 1))`
63-
/// * Corollary: `Step::forward_checked(&a, 0) == Some(a)`
60+
/// * Corollary: `Step::forward_checked(a, 0) == Some(a)`
6461
fn forward_checked(start: Self, count: usize) -> Option<Self>;
6562

6663
/// Returns the value that would be obtained by taking the *successor*
@@ -106,6 +103,7 @@ pub trait Step: Clone + PartialOrd + Sized {
106103
/// * if there exists `b` such that `b > a`, it is safe to call `Step::forward_unchecked(a, 1)`
107104
/// * if there exists `b`, `n` such that `steps_between(&a, &b) == Some(n)`,
108105
/// it is safe to call `Step::forward_unchecked(a, m)` for any `m <= n`.
106+
/// * Corollary: `Step::forward_unchecked(a, 0)` is always safe.
109107
///
110108
/// For any `a` and `n`, where no overflow occurs:
111109
///
@@ -128,8 +126,8 @@ pub trait Step: Clone + PartialOrd + Sized {
128126
///
129127
/// For any `a` and `n`:
130128
///
131-
/// * `Step::backward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::backward_checked(&x, 1))`
132-
/// * Corollary: `Step::backward_checked(&a, 0) == Some(a)`
129+
/// * `Step::backward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::backward_checked(x, 1))`
130+
/// * Corollary: `Step::backward_checked(a, 0) == Some(a)`
133131
fn backward_checked(start: Self, count: usize) -> Option<Self>;
134132

135133
/// Returns the value that would be obtained by taking the *predecessor*
@@ -175,6 +173,7 @@ pub trait Step: Clone + PartialOrd + Sized {
175173
/// * if there exists `b` such that `b < a`, it is safe to call `Step::backward_unchecked(a, 1)`
176174
/// * if there exists `b`, `n` such that `steps_between(&b, &a) == Some(n)`,
177175
/// it is safe to call `Step::backward_unchecked(a, m)` for any `m <= n`.
176+
/// * Corollary: `Step::backward_unchecked(a, 0)` is always safe.
178177
///
179178
/// For any `a` and `n`, where no overflow occurs:
180179
///
@@ -184,8 +183,25 @@ pub trait Step: Clone + PartialOrd + Sized {
184183
}
185184
}
186185

187-
// These are still macro-generated because the integer literals resolve to different types.
188-
macro_rules! step_identical_methods {
186+
// Separate impls for signed ranges because the distance within a signed range can be larger
187+
// than the signed::MAX value. Therefore `as` casting to the signed type would be incorrect.
188+
macro_rules! step_signed_methods {
189+
($unsigned: ty) => {
190+
#[inline]
191+
unsafe fn forward_unchecked(start: Self, n: usize) -> Self {
192+
// SAFETY: the caller has to guarantee that `start + n` doesn't overflow.
193+
unsafe { start.checked_add_unsigned(n as $unsigned).unwrap_unchecked() }
194+
}
195+
196+
#[inline]
197+
unsafe fn backward_unchecked(start: Self, n: usize) -> Self {
198+
// SAFETY: the caller has to guarantee that `start - n` doesn't overflow.
199+
unsafe { start.checked_sub_unsigned(n as $unsigned).unwrap_unchecked() }
200+
}
201+
};
202+
}
203+
204+
macro_rules! step_unsigned_methods {
189205
() => {
190206
#[inline]
191207
unsafe fn forward_unchecked(start: Self, n: usize) -> Self {
@@ -198,7 +214,12 @@ macro_rules! step_identical_methods {
198214
// SAFETY: the caller has to guarantee that `start - n` doesn't overflow.
199215
unsafe { start.unchecked_sub(n as Self) }
200216
}
217+
};
218+
}
201219

220+
// These are still macro-generated because the integer literals resolve to different types.
221+
macro_rules! step_identical_methods {
222+
() => {
202223
#[inline]
203224
#[allow(arithmetic_overflow)]
204225
#[rustc_inherit_overflow_checks]
@@ -239,6 +260,7 @@ macro_rules! step_integer_impls {
239260
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
240261
impl Step for $u_narrower {
241262
step_identical_methods!();
263+
step_unsigned_methods!();
242264

243265
#[inline]
244266
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
@@ -271,6 +293,7 @@ macro_rules! step_integer_impls {
271293
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
272294
impl Step for $i_narrower {
273295
step_identical_methods!();
296+
step_signed_methods!($u_narrower);
274297

275298
#[inline]
276299
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
@@ -335,6 +358,7 @@ macro_rules! step_integer_impls {
335358
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
336359
impl Step for $u_wider {
337360
step_identical_methods!();
361+
step_unsigned_methods!();
338362

339363
#[inline]
340364
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
@@ -360,6 +384,7 @@ macro_rules! step_integer_impls {
360384
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
361385
impl Step for $i_wider {
362386
step_identical_methods!();
387+
step_signed_methods!($u_wider);
363388

364389
#[inline]
365390
fn steps_between(start: &Self, end: &Self) -> Option<usize> {

core/tests/iter/range.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,11 @@ fn test_range_advance_by() {
325325
assert_eq!(Ok(()), r.advance_back_by(usize::MAX));
326326

327327
assert_eq!((r.start, r.end), (0u128 + usize::MAX as u128, u128::MAX - usize::MAX as u128));
328+
329+
// issue 122420, Step::forward_unchecked was unsound for signed integers
330+
let mut r = -128i8..127;
331+
assert_eq!(Ok(()), r.advance_by(200));
332+
assert_eq!(r.next(), Some(72));
328333
}
329334

330335
#[test]

0 commit comments

Comments
 (0)