Ltac make_func_ptr id :=
  eapply (make_func_ptr id);
  [ (reflexivity || fail 99  "Local variable " id " is shadowing the global variable" id)
  | (reflexivity || fail 99 "No specification of function " id " in Delta")
  | (reflexivity || fail 99 "No global variable " id " in Delta, i.e., in your extern declarations")
  | split; reflexivity | ].Ltac type_lists_compatible al bl :=
 match al with
 | Ctypes.Tcons ?a ?al' => match bl with Ctypes.Tcons ?b ?bl' => 
                 first [unify a b | unify (classify_cast a b) cast_case_pointer];
                 type_lists_compatible al' bl'
                end
 | Ctypes.Tnil => match bl with Ctypes.Tnil => idtac end
 end.Ltac function_types_compatible t1 t2 :=
 match t1 with
 | Tfunction ?al1 ?r1 _ =>
  match t2 with Tfunction ?al2 ?r2 _ =>
     type_lists_compatible al1 al2;
     first [unify r1 r2 | unify (classify_cast r1 r2) cast_case_pointer]
 end end.Fixpoint find_expressions {A: Type} (f: expr -> A -> A) (c: statement) (x: A) : A :=
 match c with
 | Sskip => x
 | Sassign e1 e2 => f e1 (f e2 x)
 | Sset _ e => f e x
 | Scall _ (Evar _ _) el => fold_right f x el
 | Scall _ e el => f e (fold_right f x el)
 | Sbuiltin _ _ _ el => fold_right f x el
 | Ssequence c1 c2 => find_expressions f c1 (find_expressions f c2 x)
 | Sifthenelse e c1 c2 => f e (find_expressions f c1 (find_expressions f c2 x))
 | Sloop c1 c2 => find_expressions f c1 (find_expressions f c2 x)
 | Sbreak => x
 | Scontinue => x
 | Sreturn (Some e) => f e x
 | Sreturn None => x
 | Sswitch e cl => f e (find_expressions_sl f cl x)
 | Slabel _ c => find_expressions f c x
 | Sgoto _ => x
 end
with find_expressions_sl {A: Type} (f: expr -> A -> A) (c: labeled_statements) (x: A) : A :=
 match c with
 | LSnil => x
 | LScons _ c1 c2 => find_expressions f c1 (find_expressions_sl f c2 x)
 end.Fixpoint find_vars {A: Type} (f: ident -> A -> A) (e: expr) (x: A) : A :=
 match e with
 | Evar i _ => f i x
 | Ederef e _ => find_vars f e x
 | Eaddrof e _ => find_vars f e x
 | Eunop _ e _ => find_vars f e x
 | Ebinop _ e1 e2 _ => find_vars f e1 (find_vars f e2 x)
 | Ecast e _ => find_vars f e x
 | Efield e _ _ => find_vars f e x
 | _ => x
 end.Fixpoint find_lvars (locals: list localdef)  (m: PTree.t unit) : PTree.t unit :=
 match locals with
 | lvar i _ _ :: locals'=> find_lvars locals' (PTree.set i tt m)
 | _ :: locals' => find_lvars locals' m
 | nil => m
 end.Definition another_gvar (i: ident) (ml: PTree.t unit * list ident) : (PTree.t unit * list ident) :=
 match ml with (t,il) =>
  match PTree.get i t with Some _ => ml | None =>  (PTree.set i tt t, i :: il) end
 end.Ltac start_function_hint := idtac.(* "Hint: at any time, try the 'hint' tactic.  To disable this message, 'Ltac start_function_hint ::= idtac.' ". *)


Definition firstopt {A} (e1 e2: option A) := 
match e1 with None => e2 | Some x => Some x end.Fixpoint check_norm_expr (e: expr) : option expr :=
match e with
 | Evar _ ty => match access_mode ty with
                            | By_reference => None
                            | _ => Some e
                           end
 | Ederef a ty => match access_mode ty with
                  | By_reference => if is_pointer_type (typeof a) 
                                               then check_norm_expr a
                                               else Some e
                  | _ => Some e
                  end
| Eunop _ e _ => check_norm_expr e
| Ebinop _ e1 e2 _ => firstopt (check_norm_expr e1) (check_norm_expr e2)
| Ecast e _ => check_norm_expr e
| Efield a _ ty => match access_mode ty with
                            | By_reference => check_norm_lvalue a
                            | _ => Some e
                           end
| Eaddrof e _ => check_norm_lvalue e
| _ => None
end
with check_norm_lvalue (e: expr) : option expr :=
match e with
| Ederef a _ => if is_pointer_type (typeof a) 
                              then check_norm_expr a
                              else Some e
| Ecast e _ => check_norm_lvalue e
| Efield e _ _ => check_norm_lvalue e
| Eunop _ e _ => check_norm_expr e
| Ebinop _ e1 e2 _ => firstopt (check_norm_expr e1) (check_norm_expr e2)
| _ => None
end.Fixpoint check_norm_stmt (s: statement) : option expr :=
match s with
| Sassign e1 e2 => firstopt (check_norm_lvalue e1) (check_norm_expr e2)
| Sset _ e1 => check_norm_lvalue e1
| Scall _ (Evar _ _) el => fold_right firstopt None (map check_norm_expr el)
| Scall _ e el => fold_right firstopt None (map check_norm_expr (e::el))
| Sbuiltin _ _ _ el => fold_right firstopt None (map check_norm_expr el)
| Ssequence s1 s2 => firstopt (check_norm_stmt s1) (check_norm_stmt s2)
| Sifthenelse e s1 s2 => firstopt (check_norm_expr e) (firstopt (check_norm_stmt s1) (check_norm_stmt s2))
| Sloop s1 s2 => firstopt (check_norm_stmt s1) (check_norm_stmt s2)
| Sreturn (Some e) => check_norm_expr e
| Sswitch e ls => firstopt (check_norm_expr e)
                              (check_norm_ls ls)
| _ => None
end
with
check_norm_ls (ls: labeled_statements) : option expr :=
match ls with 
| LSnil => None 
| LScons _ s1 sr => firstopt (check_norm_stmt s1) (check_norm_ls sr)
end.Ltac check_normalized f := 
let x := constr:(check_norm_stmt (fn_body f)) in
let x := eval hnf in x in
match x with 
| None => idtac
| Some ?e => fail 99 "The expression " e " contains internal memory dereferences, which suggests that you ran clightgen without the -normalize flag.  Print Info.normalized and make sure it has the value 'true'"
end.

Lemma legal_alignas_env_completeness': forall (cenv : composite_env) (ha_env : PTree.t Z) (la_env: PTree.t legal_alignas_obs), la_env = legal_alignas_env cenv ha_env -> legal_alignas_env_complete cenv la_env.