Definition gfield_array_type t lo hi :=
match t with
| Tarray t0 _ a => Tarray t0 (hi - lo) (no_alignas_attr a)
| _ => Tarray Tvoid (hi - lo) (no_alignas_attr (attr_of_type t))
end.
Fixpoint nested_field_rec (t: type) (gfs: list gfield) : option (prod Z type) :=
match gfs with
| nil => Some (0, t)
| hd :: tl =>
match nested_field_rec t tl with
| Some (pos, t') =>
match t', hd with
| Tarray t'' n _, ArraySubsc i => Some(pos + sizeof t'' * i, t'')
| Tstruct id _, StructField i =>
let m := co_members (get_co id) in
if compute_in_members i m then
Some (pos + field_offset cenv_cs i m, field_type i m)
else
None
| Tunion id _, UnionField i =>
let m := co_members (get_co id) in
if compute_in_members i m then
Some (pos, field_type i m)
else
None
| _, _ => None
end
| None => None
end
end%Z.
(* Fixpoint nested_field_rec (t: type) (gfs: list gfield) : option (prod Z type) := match gfs with | nil => Some (0, t) | hd :: tl => match nested_field_rec t tl with | Some (pos, t') => match t', hd with | Tarray t'' n _, ArraySubsc i => Some(pos + sizeof t'' * i, t'') | Tstruct id _, StructField i => if compute_in_members i (co_members (get_co id)) then Some (pos + field_offset cenv_cs i (co_members (get_co id)), field_type i (co_members (get_co id))) else None | Tunion id _, UnionField i => if compute_in_members i (co_members (get_co id)) then Some (pos, field_type i (co_members (get_co id))) else None | _, _ => None end | None => None end end. *)
Definition nested_field_offset (t: type) (gfs: list gfield) : Z :=
match nested_field_rec t gfs with
| Some (pos, _) => pos
| _ => 0
end.
Definition nested_field_type (t: type) (gfs: list gfield) : type :=
match nested_field_rec t gfs with
| Some (_, t0) => t0
| _ => Tvoid
end.
Definition nested_field_array_type t gfs lo hi :=
Tarray (nested_field_type t (ArraySubsc 0 :: gfs)) (hi - lo) (no_alignas_attr (attr_of_type (nested_field_type t gfs))).
Definition legal_field t gf :=
match t, gf with
| Tarray _ n _, ArraySubsc i => 0 <= i < n
| Tstruct id _, StructField i => in_members i (co_members (get_co id))
| Tunion id _, UnionField i => in_members i (co_members (get_co id))
| _, _ => False
end.
Definition legal_field0 t gf :=
match t, gf with
| Tarray _ n _, ArraySubsc i => 0 <= i <= n
| Tstruct id _, StructField i => in_members i (co_members (get_co id))
| Tunion id _, UnionField i => in_members i (co_members (get_co id))
| _, _ => False
end.
Fixpoint legal_nested_field (t: type) (gfs: list gfield) : Prop :=
match gfs with
| nil => True
| gf :: gfs0 => legal_nested_field t gfs0 /\ legal_field (nested_field_type t gfs0) gf
end.
Definition legal_nested_field0 t gfs :=
match gfs with
| nil => True
| gf :: gfs0 => legal_nested_field t gfs0 /\ legal_field0 (nested_field_type t gfs0) gf
end.
Fixpoint compute_legal_nested_field (t: type) (gfs: list gfield) : list Prop :=
match gfs with
| nil => nil
| gf :: gfs0 =>
match (nested_field_type t gfs0), gf with
| Tarray _ n _, ArraySubsc i =>
(0 <= i < n) :: compute_legal_nested_field t gfs0
| Tstruct id _, StructField i =>
if compute_in_members i (co_members (get_co id)) then compute_legal_nested_field t gfs0 else False :: nil
| Tunion id _, UnionField i =>
if compute_in_members i (co_members (get_co id)) then compute_legal_nested_field t gfs0 else False :: nil
| _, _ => False :: nil
end
end.

(* Specifications: *)
Lemma nested_field_type_ind: forall t gfs,
nested_field_type t gfs =
match gfs with
| nil => t
| gf :: gfs0 => gfield_type (nested_field_type t gfs0) gf
end.
Lemma nested_field_offset_ind': forall t gfs,
legal_nested_field t gfs ->
nested_field_offset t gfs =
match gfs with
| nil => 0
| gf :: gfs0 => nested_field_offset t gfs0 + gfield_offset (nested_field_type t gfs0) gf
end.
Lemma offset_val_nested_field_offset_ind: forall t gfs p,
legal_nested_field0 t gfs ->
offset_val (nested_field_offset t gfs) p =
match gfs with
| nil => force_ptr p
| gf :: gfs0 => offset_val (gfield_offset (nested_field_type t gfs0) gf)
(offset_val (nested_field_offset t gfs0) p)
end.
Lemma nested_field_array_type_ind: forall t gfs lo hi,
nested_field_array_type t gfs lo hi =
gfield_array_type (nested_field_type t gfs) lo hi.
Lemma nested_field0_offset_ind: forall t gfs,
legal_nested_field0 t gfs ->
nested_field_offset t gfs =
match gfs with
| nil => 0
| gf :: gfs0 => nested_field_offset t gfs0 + gfield_offset (nested_field_type t gfs0) gf
end.