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_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.
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.