(** ** Byte offset for a field of a structure *)
(** [field_offset env id fld] returns the byte offset for field [id] in a structure whose members are [fld].  Fields are laid out consecutively, and padding is inserted to align each field to the alignment for its type. *)
Fixpoint field_offset_rec (env: composite_env) (id: ident) (fld: members) (pos: Z)
{struct fld} : res Z :=
match fld with
| nil => Error (MSG "Unknown field " :: CTX id :: nil)
| (id', t) :: fld' =>
if ident_eq id id'
then OK (align pos (alignof env t))
else field_offset_rec env id fld' (align pos (alignof env t) + sizeof env t)
end.
Definition field_offset (env: composite_env) (id: ident) (fld: members) : res Z :=
field_offset_rec env id fld 0.
Fixpoint field_type (id: ident) (fld: members) {struct fld} : res type :=
match fld with
| nil => Error (MSG "Unknown field " :: CTX id :: nil)
| (id', t) :: fld' => if ident_eq id id' then OK t else field_type id fld'
end.
(** Some sanity checks about field offsets.  First, field offsets are within the range of acceptable offsets. *)
Remark field_offset_rec_in_range:
forall env id ofs ty fld pos,
field_offset_rec env id fld pos = OK ofs -> field_type id fld = OK ty ->
pos <= ofs /\ ofs + sizeof env ty <= sizeof_struct env pos fld.

(* Specifications: *)
Lemma field_offset_in_range:
forall env fld id ofs ty,
field_offset env id fld = OK ofs -> field_type id fld = OK ty ->
0 <= ofs /\ ofs + sizeof env ty <= sizeof_struct env 0 fld.
Lemma field_offset_in_range:
forall env fld id ofs ty,
field_offset env id fld = OK ofs -> field_type id fld = OK ty ->
0 <= ofs /\ ofs + sizeof env ty <= sizeof_struct env 0 fld.