A lcpp-primary beginning with fresh
,
for example fresh(x)
, can only be used
in a postcondition.
(See section 6.1.10 Larch/C++ Special Primaries for the exact syntax.)
Informally, fresh(x)
says that the object denoted by the term x
was not allocated in the pre-state, and is allocated in the post-state.
Writing fresh(t1,t2)
says that both t1
and t2
are newly allocated, and that,
in addition, t1
and t2
are distinct objects.
A common use of fresh
is to state that the result
of a function
call is newly allocated. For example, consider the following,
which says that the result of a call to make_ratl
must be a
pointer to newly allocated memory.
// @(#)$Id: make_ratl.lh,v 1.7 1997/06/03 20:30:13 leavens Exp $ typedef int *ratl; extern ratl make_ratl(int n, int d) throw(); //@ behavior { //@ requires d > 0; //@ ensures assigned(result, post) /\ size(locs(result)) = 2 //@ /\ (result[0])' = n /\ (result[1])' = d //@ /\ fresh(result[0], result[1]); //@ }
The terms in the term-list passed to fresh
should usually be of sort Set[TypeTaggedObject]
or a sort of the form Obj[T]
or ConstObj[T]
, for some sort T
;
alternatively, as a syntactic sugar,
they can be terms of a sort for which the trait function
contained_objects
is defined.
The syntactic sugar obtains a set of objects (which must not be empty)
from a value by applying contained_objects
to the value and the post-state.
(Since the post-state is used, the syntax of a store-ref-list
is not used with fresh
, because the syntactic sugar for
a store-ref-list uses the pre-state.)
The semantics of fresh(term-list)
is as follows.
Let E be a term
in the term-list.
Let TTO(E) be defined as follows.
Set[TypeTaggedObject]
,
{asTypeTaggedObject(E)}
,
if the E has a sort of the form Obj[T]
or ConstObj[T]
,
and
contained_objects(E, post)
, otherwise.
Then ignoringTypeTags(TTO(E)) is a set of untyped objects obtained from TTO(E) by taking off each type tag from each object in TTO(E). Let AssertedFresh(term-list) be the union of the sets TTO(E), for each term E in term-list. Somewhat informally, this is summarized as follows.
AssertedFresh(term-list) = { tto | tto is in TTO(E), E is a term in term-list }
Then fresh(
term-list)
,
means that for each E in term-list,
the sets ignoringTypeTags(TTO(E)) are mutually disjoint,
and that the following is true, for each typed object sort Loc[T]
.
\A loc:Loc[T] (loc \in AssertedFresh(term-list) => isFresh(loc, pre, post))
For example, the term
fresh(result[0], result[1])
used in the above example
has the following meaning, because the only sort in question
is Obj[int]
.
(ignoringTypeTags({asTypeTaggedObject(result[0])}) \I ignoringTypeTags({asTypeTaggedObject(result[1])})) = {} /\ (\A loc:Obj[int] (loc \in ({asTypeTaggedObject(result[0])} \U {asTypeTaggedObject(result[1])}) => isFresh(loc, pre, post)))
The above can be simplified, using facts about type-tagged objects, to the following.
({widen(result[0])} \I {widen(result[1])}) = {} /\ isFresh(result[0], pre, post) /\ isFresh(result[1], pre, post)
The trait FreshSemantics
below gives the definitions
of the trait function isFresh
used in the semantics.
(See section 6.2.3 The Modifies Clause for the trait TypeTaggedObject
that defines the trait function ignoringTypeTags
.)
% @(#)$Id: FreshSemantics.lsl,v 1.10 1995/11/13 22:20:37 leavens Exp $ FreshSemantics(Loc, T): trait assumes AllocatedAssigned(Loc, T) introduces isFresh: Loc[T], State, State -> Bool asserts \forall loc: Loc[T], pre, post: State isFresh(loc, pre, post) == ~allocated(loc, pre) /\ allocated(loc, post); implies converts isFresh exempting \forall loc: Loc[T], st:State isFresh(loc, bottom, st), isFresh(loc, st, bottom)
The sort of a lcpp-primary of the form fresh(t)
is Bool
.
In the specification of make_ratl
given above,
and in similar cases,
it is inconvenient to have to explicitly list each element of an array
pointed at as fresh.
But since the trait function contained_objects
is defined for pointers (see section 11.8 Pointer Types),
the syntactic sugar described above
allows one to write
in the specification of make_ratl
fresh(result)
as a shorthand for fresh(result[0], result[1])
.
In general, when a
is a pointer or an array name,
then fresh(a)
means the fresh(contained_objects(a,post))
.
This sugar works for multi-dimensional arrays as well;
that is, when a
is the name of a multi-dimensional array
fresh(a)
means that each element is fresh.
(See section 11.7 Array Types for details on the trait function
contained_objects
for arrays).
For struct
s, one has to pass to fresh
both the struct
object itself, and the contained objects.
This can be done, as in the first conjunct of the following specification's
postcondition.
(See section 11.10 Structure and Class Types for the abstract values of struct
s.)
// @(#)$Id: make_sratl.lh,v 1.8 1997/07/31 17:25:53 leavens Exp $ struct sratl { int num; int den; }; extern sratl& make_sratl(int n, int d) throw(); //@ behavior { //@ requires d > 0; //@ ensures fresh(result, result'.num, result'.den) //@ /\ assigned(result, post) //@ /\ assigned(result.num, post) /\ assigned(result.den, post) //@ /\ result'.num' = n /\ result'.den' = d; //@ }
In the above specification, fresh(result, result'.num, result'.den)
could also have been written as one of the two following terms.
fresh(result, result') fresh(result, contained_objects(result',post))
If u
is a union object,
then usually one would write fresh(u, contained_objects(u', post))
to assert that u
and its fields are fresh.
See section 11.11 Union Types for more details on the abstract values of union
s.
Go to the first, previous, next, last section, table of contents.