creusot_std/ghost.rs
1//! Definitions for ghost code
2//!
3//! Ghost code is code that will be erased during the normal compilation of the program.
4//! To use ghost code in creusot, you must use the [`ghost!`] macro:
5//!
6//! ```
7//! # use creusot_std::prelude::*;
8//! let x: Ghost<i32> = ghost!(1);
9//! ghost! {
10//! let y: i32 = *x;
11//! assert!(y == 1);
12//! };
13//! ```
14//!
15//! There are restrictions on the values that can enter/exit a `ghost!` block: see
16//! [`Ghost`] and [`ghost!`] for more details.
17
18use crate::{logic::ops::Fin, prelude::*};
19use core::{
20 marker::PhantomData,
21 ops::{Deref, DerefMut},
22};
23
24mod fn_ghost;
25pub mod invariant;
26pub mod resource;
27pub use fn_ghost::{FnGhost, FnGhostWrapper};
28pub mod perm;
29
30/// A type that can be used in [`ghost!`] context.
31///
32/// This type may be used to make more complicated proofs possible. In particular, some
33/// proof may need a notion of non-duplicable token to carry around.
34///
35/// Conceptually, a `Ghost<T>` is an object of type `T` that resides in a special "ghost"
36/// heap. This heap is inaccessible from normal code, and `Ghost` values cannot be used
37/// to influence the behavior of normal code.
38///
39/// This box can be accessed in a [`ghost!`] block:
40/// ```compile_fail
41/// let b: Ghost<i32> = Ghost::new(1);
42/// ghost! {
43/// let value: i32 = b.into_inner();
44/// // use value here
45/// }
46/// let value: i32 = b.into_inner(); // compile error !
47/// ```
48#[opaque]
49#[intrinsic("ghost")]
50
51pub struct Ghost<T: ?Sized>(PhantomData<T>);
52
53impl<T: Copy> Copy for Ghost<T> {}
54
55// FIXME: we would like to have an instance that does not require T: Copy, but it would
56// require the underlying clone instance to be #[check(ghost)], which we cannot require in general
57impl<T: Clone + Copy> Clone for Ghost<T> {
58 #[check(ghost)]
59 #[ensures(result == *self)]
60 fn clone(&self) -> Self {
61 ghost!(**self)
62 }
63}
64
65impl<T: ?Sized> Deref for Ghost<T> {
66 type Target = T;
67
68 /// This function can only be called in `ghost!` context
69 #[trusted]
70 #[check(ghost)]
71 #[requires(false)] // If called from generic context, false precondition
72 #[ensures(result == &**self)]
73 #[intrinsic("ghost_deref")]
74 fn deref(&self) -> &Self::Target {
75 panic!()
76 }
77}
78impl<T: ?Sized> DerefMut for Ghost<T> {
79 /// This function can only be called in `ghost!` context
80 #[trusted]
81 #[check(ghost)]
82 #[requires(false)] // If called from generic context, false precondition
83 #[ensures(result == &mut **self)]
84 #[intrinsic("ghost_deref_mut")]
85 fn deref_mut(&mut self) -> &mut Self::Target {
86 panic!()
87 }
88}
89
90impl<T: ?Sized + Fin> Fin for Ghost<T> {
91 type Target = T::Target;
92
93 #[logic(open, prophetic, inline)]
94 fn fin<'a>(self) -> &'a Self::Target {
95 pearlite! { &^*self }
96 }
97}
98
99impl<T: ?Sized> Invariant for Ghost<T> {
100 #[logic(open, prophetic, inline)]
101 #[creusot::trusted_trivial_if_param_trivial]
102 fn invariant(self) -> bool {
103 inv(*self)
104 }
105}
106
107impl<T: ?Sized> Ghost<T> {
108 /// Transforms a `&Ghost<T>` into `Ghost<&T>`
109 #[trusted]
110 #[erasure(_)]
111 #[check(ghost)]
112 #[ensures(**result == **self)]
113 pub fn borrow(&self) -> Ghost<&T> {
114 Ghost::conjure()
115 }
116
117 /// Transforms a `&mut Ghost<T>` into a `Ghost<&mut T>`.
118 #[trusted]
119 #[erasure(_)]
120 #[check(ghost)]
121 #[ensures(*result == &mut **self)]
122 pub fn borrow_mut(&mut self) -> Ghost<&mut T> {
123 Ghost::conjure()
124 }
125
126 /// Conjures a `Ghost<T>` out of thin air.
127 ///
128 /// This would be unsound in verified code, hence the `false` precondition.
129 /// This function is nevertheless useful to create a `Ghost` in "trusted"
130 /// contexts, when axiomatizing an API that is believed to be sound for
131 /// external reasons.
132 #[trusted]
133 #[erasure(_)]
134 #[check(ghost)]
135 #[requires(false)]
136 pub fn conjure() -> Self {
137 Ghost(PhantomData)
138 }
139
140 // Internal function to easily create a `Ghost` in non-creusot mode.
141 #[cfg(not(creusot))]
142 #[doc(hidden)]
143 pub fn from_fn(_: impl FnOnce() -> T) -> Self {
144 Ghost::conjure()
145 }
146}
147
148impl<T: ?Sized> Ghost<T> {
149 /// Creates a new ghost variable.
150 ///
151 /// This function can only be called in `ghost!` code.
152 #[trusted]
153 #[check(ghost)]
154 #[ensures(*result == x)]
155 #[intrinsic("ghost_new")]
156 pub fn new(x: T) -> Self
157 where
158 T: Sized,
159 {
160 let _ = x;
161 panic!()
162 }
163
164 #[trusted]
165 #[logic(opaque)]
166 #[ensures(*result == x)]
167 pub fn new_logic(x: T) -> Self {
168 dead
169 }
170
171 /// Returns the inner value of the `Ghost`.
172 ///
173 /// This function can only be called in `ghost!` context.
174 #[trusted]
175 #[check(ghost)]
176 #[ensures(result == *self)]
177 #[intrinsic("ghost_into_inner")]
178 pub fn into_inner(self) -> T
179 where
180 T: Sized,
181 {
182 panic!()
183 }
184
185 /// Returns the inner value of the `Ghost`.
186 ///
187 /// You should prefer the dereference operator `*` instead.
188 #[logic]
189 #[builtin("identity")]
190 pub fn inner_logic(self) -> T
191 where
192 T: Sized,
193 {
194 dead
195 }
196}
197
198impl<T, U: ?Sized> Ghost<(T, U)> {
199 #[check(ghost)]
200 #[trusted]
201 #[erasure(_)]
202 #[ensures((*self).0 == *result.0)]
203 #[ensures((*self).1 == *result.1)]
204 pub fn split(self) -> (Ghost<T>, Ghost<U>) {
205 (Ghost::conjure(), Ghost::conjure())
206 }
207}
208
209/// A marker trait for types that can be extracted from snapshots in ghost code.
210/// These are type that only contain plain data and whose onership does not convey
211/// any additional information.
212///
213/// For example, Booleans and integers are plain, but references are not, be they
214/// mutable or not. Indeed, the ownership of a shared reference can be used to deduce
215/// facts, for example with `Perm::disjoint_lemma`.
216#[trusted]
217pub trait Plain: Copy {}
218
219#[trusted]
220impl Plain for bool {}
221
222#[trusted]
223impl<T> Plain for *const T {}
224
225#[trusted]
226impl<T> Plain for *mut T {}
227
228/// Wrapper around a single atomic operation, where multiple ghost steps can be
229/// performed.
230#[opaque]
231pub struct Committer;
232
233impl Committer {
234 /// Status of the committer
235 #[logic(opaque)]
236 pub fn shot(self) -> bool {
237 dead
238 }
239
240 /// Identity of the committer
241 ///
242 /// This is used so that we can only use the committer with the right [`AtomicOwn`].
243 #[logic(opaque)]
244 #[cfg(feature = "std")]
245 pub fn ward(self) -> crate::std::sync::AtomicI32 {
246 dead
247 }
248
249 /// Value held by the [`AtomicOwn`], before the [`shoot`].
250 #[logic(opaque)]
251 pub fn old_value(self) -> i32 {
252 dead
253 }
254
255 /// Value held by the [`AtomicOwn`], after the [`shoot`].
256 #[logic(opaque)]
257 pub fn new_value(self) -> i32 {
258 dead
259 }
260
261 /// 'Shoot' the committer
262 ///
263 /// This does the write on the atomic in ghost code, and can only be called once.
264 #[requires(!self.shot())]
265 #[requires(self.ward() == *own.ward())]
266 #[ensures((^self).shot())]
267 #[ensures((^own).ward() == (*own).ward())]
268 #[ensures(*(*own).val() == (*self).old_value())]
269 #[ensures(*(^own).val() == (*self).new_value())]
270 #[check(ghost)]
271 #[trusted]
272 #[allow(unused_variables)]
273 #[cfg(feature = "std")]
274 pub fn shoot(&mut self, own: &mut perm::Perm<crate::std::sync::AtomicI32>) {
275 panic!("Should not be called outside ghost code")
276 }
277}