Skip to content

Commit 7dd70f5

Browse files
committed
Port all viable contracts from verify-rust-std
Ports over all contracts (other than those for `Alignment`, see the separate PR) that can be expressed using the current, experimental contracts syntax. (Notably, this excludes all contracts that refer to pointer validity.)
1 parent 292be5c commit 7dd70f5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+669
-0
lines changed

library/alloc/src/collections/vec_deque/iter.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ impl<'a, T> Iterator for Iter<'a, T> {
144144
}
145145

146146
#[inline]
147+
#[core::contracts::requires(idx < self.len())]
147148
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
148149
// Safety: The TrustedRandomAccess contract requires that callers only pass an index
149150
// that is in bounds.

library/alloc/src/collections/vec_deque/iter_mut.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,8 @@ impl<'a, T> Iterator for IterMut<'a, T> {
208208
}
209209

210210
#[inline]
211+
#[allow(unused_parens)]
212+
#[core::contracts::requires(idx < self.len())]
211213
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
212214
// Safety: The TrustedRandomAccess contract requires that callers only pass an index
213215
// that is in bounds.

library/alloc/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@
106106
#![feature(const_default)]
107107
#![feature(const_eval_select)]
108108
#![feature(const_heap)]
109+
#![feature(contracts)]
109110
#![feature(core_intrinsics)]
110111
#![feature(deprecated_suggestion)]
111112
#![feature(deref_pure_trait)]

library/alloc/src/vec/into_iter.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
360360
R::from_output(accum)
361361
}
362362

363+
#[core::contracts::requires(i < self.len())]
363364
unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item
364365
where
365366
Self: TrustedRandomAccessNoCoerce,

library/alloctests/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
#![allow(rustdoc::redundant_explicit_links)]
1212
#![warn(rustdoc::unescaped_backticks)]
1313
#![deny(ffi_unwind_calls)]
14+
// permit use of experimental feature contracts
15+
#![allow(incomplete_features)]
1416
//
1517
// Library features:
1618
// tidy-alphabetical-start
@@ -20,6 +22,7 @@
2022
#![feature(assert_matches)]
2123
#![feature(char_internals)]
2224
#![feature(char_max_len)]
25+
#![feature(contracts)]
2326
#![feature(core_intrinsics)]
2427
#![feature(exact_size_is_empty)]
2528
#![feature(extend_one)]

library/core/src/alloc/layout.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ impl Layout {
6666
#[stable(feature = "alloc_layout", since = "1.28.0")]
6767
#[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")]
6868
#[inline]
69+
#[rustc_allow_const_fn_unstable(contracts)]
70+
#[core::contracts::ensures(
71+
move |result: &Result<Self, LayoutError>|
72+
result.is_err() || (
73+
align.is_power_of_two() &&
74+
size <= isize::MAX as usize - (align - 1) &&
75+
result.as_ref().unwrap().size() == size &&
76+
result.as_ref().unwrap().align() == align))]
6977
pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutError> {
7078
if Layout::is_size_align_valid(size, align) {
7179
// SAFETY: Layout::is_size_align_valid checks the preconditions for this call.
@@ -127,6 +135,10 @@ impl Layout {
127135
#[must_use]
128136
#[inline]
129137
#[track_caller]
138+
#[rustc_allow_const_fn_unstable(contracts)]
139+
#[core::contracts::requires(Layout::from_size_align(size, align).is_ok())]
140+
#[core::contracts::ensures(
141+
move |result: &Self| result.size() == size && result.align() == align)]
130142
pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
131143
assert_unsafe_precondition!(
132144
check_library_ub,
@@ -167,6 +179,10 @@ impl Layout {
167179
#[rustc_const_stable(feature = "alloc_layout_const_new", since = "1.42.0")]
168180
#[must_use]
169181
#[inline]
182+
#[rustc_allow_const_fn_unstable(contracts)]
183+
#[core::contracts::ensures(
184+
|result: &Self|
185+
result.size() == mem::size_of::<T>() && result.align() == mem::align_of::<T>())]
170186
pub const fn new<T>() -> Self {
171187
let (size, align) = size_align::<T>();
172188
// SAFETY: if the type is instantiated, rustc already ensures that its
@@ -182,6 +198,10 @@ impl Layout {
182198
#[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")]
183199
#[must_use]
184200
#[inline]
201+
#[rustc_allow_const_fn_unstable(contracts)]
202+
#[core::contracts::requires(mem::align_of_val(t).is_power_of_two())]
203+
// FIXME: requires `&self` to be `'static`
204+
// #[core::contracts::ensures(move |result: &Self| result.align() == mem::align_of_val(t))]
185205
pub const fn for_value<T: ?Sized>(t: &T) -> Self {
186206
let (size, align) = (size_of_val(t), align_of_val(t));
187207
// SAFETY: see rationale in `new` for why this is using the unsafe variant
@@ -217,6 +237,8 @@ impl Layout {
217237
/// [extern type]: ../../unstable-book/language-features/extern-types.html
218238
#[unstable(feature = "layout_for_ptr", issue = "69835")]
219239
#[must_use]
240+
#[rustc_allow_const_fn_unstable(contracts)]
241+
#[core::contracts::ensures(|result: &Self| result.align().is_power_of_two())]
220242
pub const unsafe fn for_value_raw<T: ?Sized>(t: *const T) -> Self {
221243
// SAFETY: we pass along the prerequisites of these functions to the caller
222244
let (size, align) = unsafe { (mem::size_of_val_raw(t), mem::align_of_val_raw(t)) };
@@ -233,6 +255,8 @@ impl Layout {
233255
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
234256
#[must_use]
235257
#[inline]
258+
#[rustc_allow_const_fn_unstable(contracts)]
259+
#[core::contracts::ensures(|result: &NonNull<u8>| result.is_aligned())]
236260
pub const fn dangling(&self) -> NonNull<u8> {
237261
NonNull::without_provenance(self.align.as_nonzero())
238262
}
@@ -254,6 +278,12 @@ impl Layout {
254278
#[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
255279
#[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")]
256280
#[inline]
281+
#[rustc_allow_const_fn_unstable(contracts)]
282+
#[core::contracts::ensures(
283+
move |result: &Result<Self, LayoutError>|
284+
result.is_err() || (
285+
result.as_ref().unwrap().align() >= align &&
286+
result.as_ref().unwrap().align().is_power_of_two()))]
257287
pub const fn align_to(&self, align: usize) -> Result<Self, LayoutError> {
258288
if let Some(align) = Alignment::new(align) {
259289
Layout::from_size_alignment(self.size, Alignment::max(self.align, align))
@@ -282,6 +312,8 @@ impl Layout {
282312
#[must_use = "this returns the padding needed, \
283313
without modifying the `Layout`"]
284314
#[inline]
315+
#[rustc_allow_const_fn_unstable(contracts)]
316+
#[core::contracts::ensures(move |result| *result <= align)]
285317
pub const fn padding_needed_for(&self, align: usize) -> usize {
286318
// FIXME: Can we just change the type on this to `Alignment`?
287319
let Some(align) = Alignment::new(align) else { return usize::MAX };
@@ -330,6 +362,14 @@ impl Layout {
330362
#[must_use = "this returns a new `Layout`, \
331363
without modifying the original"]
332364
#[inline]
365+
// FIXME: requires `&self` to be `'static`
366+
// #[rustc_allow_const_fn_unstable(contracts)]
367+
// #[core::contracts::ensures(
368+
// move |result: &Layout|
369+
// result.size() >= self.size() &&
370+
// result.align() == self.align() &&
371+
// result.size() % result.align() == 0 &&
372+
// self.size() + self.padding_needed_for(self.align()) == result.size())]
333373
pub const fn pad_to_align(&self) -> Layout {
334374
// This cannot overflow. Quoting from the invariant of Layout:
335375
// > `size`, when rounded up to the nearest multiple of `align`,
@@ -370,6 +410,12 @@ impl Layout {
370410
/// ```
371411
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
372412
#[inline]
413+
#[rustc_allow_const_fn_unstable(contracts)]
414+
#[core::contracts::ensures(
415+
move |result: &Result<(Self, usize), LayoutError>|
416+
result.is_err() || (
417+
(n == 0 || result.as_ref().unwrap().0.size() % n == 0) &&
418+
result.as_ref().unwrap().0.size() == n * result.as_ref().unwrap().1))]
373419
pub const fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutError> {
374420
let padded = self.pad_to_align();
375421
if let Ok(repeated) = padded.repeat_packed(n) {
@@ -427,6 +473,15 @@ impl Layout {
427473
#[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
428474
#[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")]
429475
#[inline]
476+
// FIXME: requires `&self` to be `'static`
477+
// #[rustc_allow_const_fn_unstable(contracts)]
478+
// #[core::contracts::ensures(
479+
// move |result: &Result<(Self, usize), LayoutError>|
480+
// result.is_err() || (
481+
// result.as_ref().unwrap().0.align() == cmp::max(self.align(), next.align()) &&
482+
// result.as_ref().unwrap().0.size() >= self.size() + next.size() &&
483+
// result.as_ref().unwrap().1 >= self.size() &&
484+
// result.as_ref().unwrap().1 <= result.as_ref().unwrap().0.size()))]
430485
pub const fn extend(&self, next: Self) -> Result<(Self, usize), LayoutError> {
431486
let new_align = Alignment::max(self.align, next.align);
432487
let offset = self.size_rounded_up_to_custom_align(next.align);
@@ -458,6 +513,13 @@ impl Layout {
458513
/// On arithmetic overflow, returns `LayoutError`.
459514
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
460515
#[inline]
516+
// FIXME: requires `&self` to be `'static`
517+
// #[rustc_allow_const_fn_unstable(contracts)]
518+
// #[core::contracts::ensures(
519+
// move |result: &Result<Self, LayoutError>|
520+
// result.is_err() || (
521+
// result.as_ref().unwrap().size() == n * self.size() &&
522+
// result.as_ref().unwrap().align() == self.align()))]
461523
pub const fn repeat_packed(&self, n: usize) -> Result<Self, LayoutError> {
462524
if let Some(size) = self.size.checked_mul(n) {
463525
// The safe constructor is called here to enforce the isize size limit.
@@ -475,6 +537,13 @@ impl Layout {
475537
/// On arithmetic overflow, returns `LayoutError`.
476538
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
477539
#[inline]
540+
// FIXME: requires `&self` to be `'static`
541+
// #[rustc_allow_const_fn_unstable(contracts)]
542+
// #[core::contracts::ensures(
543+
// move |result: &Result<Self, LayoutError>|
544+
// result.is_err() || (
545+
// result.as_ref().unwrap().size() == self.size() + next.size() &&
546+
// result.as_ref().unwrap().align() == self.align()))]
478547
pub const fn extend_packed(&self, next: Self) -> Result<Self, LayoutError> {
479548
// SAFETY: each `size` is at most `isize::MAX == usize::MAX/2`, so the
480549
// sum is at most `usize::MAX/2*2 == usize::MAX - 1`, and cannot overflow.
@@ -490,6 +559,12 @@ impl Layout {
490559
#[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
491560
#[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")]
492561
#[inline]
562+
#[rustc_allow_const_fn_unstable(contracts)]
563+
#[core::contracts::ensures(
564+
move |result: &Result<Self, LayoutError>|
565+
result.is_err() || (
566+
result.as_ref().unwrap().size() == n * mem::size_of::<T>() &&
567+
result.as_ref().unwrap().align() == mem::align_of::<T>()))]
493568
pub const fn array<T>(n: usize) -> Result<Self, LayoutError> {
494569
// Reduce the amount of code we need to monomorphize per `T`.
495570
return inner(T::LAYOUT, n);

library/core/src/array/iter.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ impl<T, const N: usize> IntoIter<T, N> {
138138
/// ```
139139
#[unstable(feature = "array_into_iter_constructors", issue = "91583")]
140140
#[inline]
141+
#[rustc_allow_const_fn_unstable(contracts)]
142+
#[core::contracts::requires(initialized.start <= initialized.end && initialized.end <= N)]
141143
pub const unsafe fn new_unchecked(
142144
buffer: [MaybeUninit<T>; N],
143145
initialized: Range<usize>,
@@ -279,6 +281,7 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
279281
}
280282

281283
#[inline]
284+
#[core::contracts::requires(idx < self.len())]
282285
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
283286
// SAFETY: The caller must provide an idx that is in bound of the remainder.
284287
let elem_ref = unsafe { self.as_mut_slice().get_unchecked_mut(idx) };

library/core/src/ascii/ascii_char.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,10 @@ impl AsciiChar {
458458
/// or returns `None` if it's too large.
459459
#[unstable(feature = "ascii_char", issue = "110998")]
460460
#[inline]
461+
#[rustc_allow_const_fn_unstable(contracts)]
462+
#[core::contracts::ensures(
463+
move |result: &Option<AsciiChar>|
464+
(b <= 127) == (result.is_some() && result.unwrap() as u8 == b))]
461465
pub const fn from_u8(b: u8) -> Option<Self> {
462466
if b <= 127 {
463467
// SAFETY: Just checked that `b` is in-range
@@ -475,6 +479,9 @@ impl AsciiChar {
475479
/// `b` must be in `0..=127`, or else this is UB.
476480
#[unstable(feature = "ascii_char", issue = "110998")]
477481
#[inline]
482+
#[rustc_allow_const_fn_unstable(contracts)]
483+
#[core::contracts::requires(b <= 127)]
484+
#[core::contracts::ensures(move |result: &Self| *result as u8 == b)]
478485
pub const unsafe fn from_u8_unchecked(b: u8) -> Self {
479486
// SAFETY: Our safety precondition is that `b` is in-range.
480487
unsafe { transmute(b) }
@@ -513,6 +520,11 @@ impl AsciiChar {
513520
#[unstable(feature = "ascii_char", issue = "110998")]
514521
#[inline]
515522
#[track_caller]
523+
// Only `d < 64` is required for safety as described above, but we use `d < 10` as in the
524+
// `assert_unsafe_precondition` inside. See https://github.com/rust-lang/rust/pull/129374 for
525+
// some context about the discrepancy.
526+
#[rustc_allow_const_fn_unstable(contracts)]
527+
#[core::contracts::requires(d < 10)]
516528
pub const unsafe fn digit_unchecked(d: u8) -> Self {
517529
assert_unsafe_precondition!(
518530
check_library_ub,
@@ -532,6 +544,8 @@ impl AsciiChar {
532544
/// Gets this ASCII character as a byte.
533545
#[unstable(feature = "ascii_char", issue = "110998")]
534546
#[inline]
547+
#[rustc_allow_const_fn_unstable(contracts)]
548+
#[core::contracts::ensures(|result: &u8| *result <= 127)]
535549
pub const fn to_u8(self) -> u8 {
536550
self as u8
537551
}

library/core/src/char/convert.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ pub(super) const fn from_u32(i: u32) -> Option<char> {
2323
#[must_use]
2424
#[allow(unnecessary_transmutes)]
2525
#[track_caller]
26+
#[rustc_allow_const_fn_unstable(contracts)]
27+
#[core::contracts::requires(char_try_from_u32(i).is_ok())]
28+
#[core::contracts::ensures(move |result: &char| *result as u32 == i)]
2629
pub(super) const unsafe fn from_u32_unchecked(i: u32) -> char {
2730
// SAFETY: the caller must guarantee that `i` is a valid char value.
2831
unsafe {

library/core/src/char/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ pub const fn from_u32(i: u32) -> Option<char> {
138138
#[rustc_const_stable(feature = "const_char_from_u32_unchecked", since = "1.81.0")]
139139
#[must_use]
140140
#[inline]
141+
#[rustc_allow_const_fn_unstable(contracts)]
142+
#[core::contracts::requires(i <= 0x10FFFF && (i < 0xD800 || i > 0xDFFF))]
141143
pub const unsafe fn from_u32_unchecked(i: u32) -> char {
142144
// SAFETY: the safety contract must be upheld by the caller.
143145
unsafe { self::convert::from_u32_unchecked(i) }
@@ -399,6 +401,7 @@ macro_rules! casemappingiter_impls {
399401
self.0.advance_by(n)
400402
}
401403

404+
#[core::contracts::requires(idx < self.0.len())]
402405
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
403406
// SAFETY: just forwarding requirements to caller
404407
unsafe { self.0.__iterator_get_unchecked(idx) }
@@ -533,6 +536,7 @@ impl Iterator for CaseMappingIter {
533536
self.0.advance_by(n)
534537
}
535538

539+
#[core::contracts::requires(idx < self.len())]
536540
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
537541
// SAFETY: just forwarding requirements to caller
538542
unsafe { self.0.__iterator_get_unchecked(idx) }

0 commit comments

Comments
 (0)