diff --git a/tests/kani/FunctionContracts/fixme_receiver_contracts.rs b/tests/kani/FunctionContracts/fixme_receiver_contracts.rs new file mode 100644 index 000000000000..3a894354b868 --- /dev/null +++ b/tests/kani/FunctionContracts/fixme_receiver_contracts.rs @@ -0,0 +1,147 @@ +// Copyright Kani Contributors +// SPDX-License-Identifier: Apache-2.0 OR MIT +//! Checks that function contracts work with different types of receivers. I.e.: +//! - &Self (i.e. &self) +//! - &mut Self (i.e &mut self) +//! - Box +//! - Rc +//! - Arc +//! - Pin

where P is one of the types above +//! Source: +// compile-flags: --edition 2021 +// kani-flags: -Zfunction-contracts + +#![feature(rustc_attrs)] + +extern crate kani; + +use std::boxed::Box; +use std::pin::Pin; +use std::rc::Rc; +use std::sync::Arc; + +/// Type representing a valid ASCII value going from `0..128`. +#[derive(Copy, Clone, PartialEq, Eq)] +#[rustc_layout_scalar_valid_range_start(0)] +#[rustc_layout_scalar_valid_range_end(128)] +struct CharASCII(u8); + +impl kani::Arbitrary for CharASCII { + fn any() -> CharASCII { + let val = kani::any_where(|inner: &u8| *inner < 128); + unsafe { CharASCII(val) } + } +} + +/// This type contains unsafe setter functions with the same contract but different type of +/// receivers. +impl CharASCII { + #[kani::modifies(&self.0)] + #[kani::requires(new_val < 128)] + #[kani::ensures(|_| self.0 == new_val)] + unsafe fn set_val(&mut self, new_val: u8) { + self.0 = new_val + } + + #[kani::modifies(&self.0)] + #[kani::requires(new_val < 128)] + #[kani::ensures(|_| self.0 == new_val)] + unsafe fn set_mut_ref(self: &mut Self, new_val: u8) { + self.0 = new_val + } + + #[kani::modifies(&self.as_ref().0)] + #[kani::requires(new_val < 128)] + #[kani::ensures(|_| self.as_ref().0 == new_val)] + unsafe fn set_box(mut self: Box, new_val: u8) { + self.as_mut().0 = new_val + } + + #[kani::modifies(&self.as_ref().0)] + #[kani::requires(new_val < 128)] + #[kani::ensures(|_| self.as_ref().0 == new_val)] + unsafe fn set_rc(mut self: Rc, new_val: u8) { + Rc::<_>::get_mut(&mut self).unwrap().0 = new_val + } + + #[kani::modifies(&self.as_ref().0)] + #[kani::requires(new_val < 128)] + #[kani::ensures(|_| self.as_ref().0 == new_val)] + unsafe fn set_arc(mut self: Arc, new_val: u8) { + Arc::<_>::get_mut(&mut self).unwrap().0 = new_val; + } + + #[kani::modifies(&self.0)] + #[kani::requires(new_val < 128)] + #[kani::ensures(|_| self.0 == new_val)] + unsafe fn set_pin(mut self: Pin<&mut Self>, new_val: u8) { + self.0 = new_val + } + + #[kani::modifies(&self.0)] + #[kani::requires(new_val < 128)] + #[kani::ensures(|_| self.0 == new_val)] + unsafe fn set_pin_box(mut self: Pin>, new_val: u8) { + self.0 = new_val + } +} + +mod verify { + use super::*; + use kani::Arbitrary; + + #[kani::proof_for_contract(CharASCII::set_val)] + fn check_set_val() { + let mut obj = CharASCII::any(); + let original = obj.0; + let new_val: u8 = kani::any(); + unsafe { obj.set_val(new_val) }; + } + + #[kani::proof_for_contract(CharASCII::set_mut_ref)] + fn check_mut_ref() { + let mut obj = CharASCII::any(); + let new_val: u8 = kani::any(); + unsafe { obj.set_mut_ref(new_val) }; + } + + #[kani::proof_for_contract(CharASCII::set_box)] + fn check_box() { + let obj = CharASCII::any(); + let original = obj.0; + let new_val: u8 = kani::any(); + unsafe { Box::new(obj).set_box(new_val) }; + } + + #[kani::proof_for_contract(CharASCII::set_rc)] + fn check_rc() { + let obj = CharASCII::any(); + let original = obj.0; + let new_val: u8 = kani::any(); + unsafe { Rc::new(obj).set_rc(new_val) }; + } + + #[kani::proof_for_contract(CharASCII::set_arc)] + fn check_arc() { + let obj = CharASCII::any(); + let original = obj.0; + let new_val: u8 = kani::any(); + unsafe { Arc::new(obj).set_arc(new_val) }; + } + + #[kani::proof_for_contract(CharASCII::set_pin)] + fn check_pin() { + let mut obj = CharASCII::any(); + let original = obj.0; + let new_val: u8 = kani::any(); + unsafe { Pin::new(&mut obj).set_pin(new_val) }; + } + + #[kani::proof_for_contract(CharASCII::set_pin_box)] + fn check_pin_box() { + let obj = CharASCII::any(); + let original = obj.0; + let new_val: u8 = kani::any(); + unsafe { Pin::new(Box::new(obj)).set_pin_box(new_val) }; + } +} diff --git a/tests/kani/FunctionContracts/fn_params.rs b/tests/kani/FunctionContracts/fn_params.rs index b485ddf2b32b..42e2c52c193e 100644 --- a/tests/kani/FunctionContracts/fn_params.rs +++ b/tests/kani/FunctionContracts/fn_params.rs @@ -21,8 +21,6 @@ struct MyStruct { #[kani::requires(val.u == tup_u)] #[kani::requires(Ok(val.c) == char::try_from(first))] #[kani::requires(val.c == tup_c)] -/// We need this extra clause due to . -#[kani::requires(char::try_from(first).is_ok())] pub fn odd_parameters_eq( [first, second]: [u32; 2], (tup_c, tup_u): (char, u32), @@ -41,8 +39,6 @@ pub fn odd_parameters_eq( #[kani::requires(val.u == tup_u)] #[kani::requires(Ok(val.c) == char::try_from(first))] // MISSING: #[kani::requires(val.c == tup_c)] -// We need this extra clause due to . -#[kani::requires(char::try_from(first).is_ok())] pub fn odd_parameters_eq_wrong( [first, second]: [u32; 2], (tup_c, tup_u): (char, u32), diff --git a/tests/kani/FunctionContracts/modify_slice_elem.rs b/tests/kani/FunctionContracts/modify_slice_elem.rs new file mode 100644 index 000000000000..50df13b45af3 --- /dev/null +++ b/tests/kani/FunctionContracts/modify_slice_elem.rs @@ -0,0 +1,25 @@ +// Copyright Kani Contributors +// SPDX-License-Identifier: Apache-2.0 OR MIT +//! Check that Kani correctly verifies the contract that modifies slices. +//! +//! Note that this test used to crash while parsing the annotations. +// kani-flags: -Zfunction-contracts +extern crate kani; + +#[kani::requires(idx < slice.len())] +#[kani::modifies(slice.as_ptr().wrapping_add(idx))] +#[kani::ensures(|_| slice[idx] == new_val)] +fn modify_slice(slice: &mut [u32], idx: usize, new_val: u32) { + *slice.get_mut(idx).unwrap() = new_val; +} + +#[cfg(kani)] +mod verify { + use super::modify_slice; + + #[kani::proof_for_contract(modify_slice)] + fn check_modify_slice() { + let mut data = kani::vec::any_vec::(); + modify_slice(&mut data, kani::any(), kani::any()) + } +}