Attribute Macro check
#[check]Expand description
Specify that the function can be called in additionnal contexts.
§Syntax
Checking modes are specified as arguments:
#[check(terminates)]
fn foo() { /* */ }
#[check(ghost)]
fn bar() { /* */ }
// cannot be called in neither ghost nor terminates contexts
fn baz() { /* */ }§#[check(terminates)]
The function is guaranteed to terminate.
At this moment, this means that:
- the function cannot be recursive
- the function cannot contain loops
- the function can only call other
terminatesorghostfunctions.
The first two limitations may be lifted at some point.
§#[check(ghost)]
The function can be called from ghost code. In particular, this means that the fuction will not panic.
§No panics ?
“But I though Creusot was supposed to check the absence of panics ?”
That’s true, but with a caveat: some functions of the standard library
are allowed to panic in specific cases. The main example is Vec::push:
we want its specification to be
#[ensures((^self)@ == self@.push(v))]
fn push(&mut self, v: T) { /* ... */ }But the length of a vector cannot overflow isize::MAX.
This is a very annoying condition to check, so we don’t. In exchange,
this means Vec::push might panic in some cases, even though your
code passed Creusot’s verification.
§Non-ghost std function
Here are some examples of functions in std that are not marked as
terminates but not ghost (this list is not exhaustive):
Vec::push,Vec::insert,Vec::reserve,Vec::with_capacitystr::to_string<&[T]>::into_vecDeque::push_front,Deque::push_back,Deque::with_capacity