Local Open Scope logic.
(* Lemma gvar_globals_only: forall i v rho, gvar i v rho -> gvar i v (globals_only rho). Hint Resolve gvar_globals_only. *)
Ltac safe_auto_with_closed :=
(* won't instantiate evars by accident *)
match goal with |- ?A =>
solve [first [has_evar A | auto 50 with closed]]
end.
Hint Rewrite @closed_env_set using safe_auto_with_closed : norm2.
Hint Rewrite subst_eval_id_eq : subst.
Hint Rewrite subst_eval_id_neq using safe_auto_with_closed : subst.
(* Lemma subst_temp_eq: forall i v w, subst i `v (temp i w) = `(eq w v).  Lemma subst_temp_neq: forall i j v w, i<>j -> subst i v (temp j w) = temp j w.  Lemma subst_var: forall i j v t w,  subst i v (var j t w) = var j t w.  Hint Rewrite subst_var : subst. Hint Rewrite subst_temp_eq : subst. Hint Rewrite subst_temp_neq using safe_auto_with_closed : subst. *)
Fixpoint subst_eval_expr  {cs: compspecs}  (j: ident) (v: environ -> val) (e: expr) : environ -> val :=
match e with
| Econst_int i ty => `(Vint i)
| Econst_long i ty => `(Vlong i)
| Econst_float f ty => `(Vfloat f)
| Econst_single f ty => `(Vsingle f)
| Etempvar id ty => if eqb_ident j id then v else eval_id id
| Eaddrof a ty => subst_eval_lvalue j v a
| Eunop op a ty =>  `(eval_unop op (typeof a)) (subst_eval_expr j v a)
| Ebinop op a1 a2 ty =>
`(eval_binop op (typeof a1) (typeof a2)) (subst_eval_expr j v a1) (subst_eval_expr j v a2)
| Ecast a ty => `(eval_cast (typeof a) ty) (subst_eval_expr j v a)
| Evar id ty => eval_var id ty
| Ederef a ty => subst_eval_expr j v a
| Efield a i ty => `(eval_field (typeof a) i) (subst_eval_lvalue j v a)
| Esizeof t ty => `(if complete_type cenv_cs t
then Vptrofs (Ptrofs.repr (sizeof t))
else Vundef)
| Ealignof t ty => `(if complete_type cenv_cs t
then Vptrofs (Ptrofs.repr (alignof t))
else Vundef)
end
with subst_eval_lvalue {cs: compspecs} (j: ident) (v: environ -> val) (e: expr) : environ -> val :=
match e with
| Evar id ty => eval_var id ty
| Ederef a ty => subst_eval_expr j v a
| Efield a i ty => `(eval_field (typeof a) i) (subst_eval_lvalue j v a)
| _  => `Vundef
end.
Hint Rewrite @subst_eval_expr_eq @subst_eval_lvalue_eq : subst.
Hint Rewrite @closed_wrt_map_subst using safe_auto_with_closed : subst.
Hint Rewrite @closed_wrt_subst using safe_auto_with_closed : subst.
(*Hint Rewrite @closed_wrt_map_subst' using safe_auto_with_closed : norm.*)
Hint Rewrite @closed_wrt_map_subst' using safe_auto_with_closed : subst.
Hint Rewrite @closed_wrt_subst_eval_expr using solve [auto 50 with closed] : subst.
Hint Rewrite @closed_wrt_subst_eval_lvalue using solve [auto 50 with closed] : subst.
Hint Unfold closed_wrt_modvars : closed.
Hint Resolve closed_wrt_local closed_wrtl_local : closed.
Hint Resolve closed_wrt_lift0 closed_wrtl_lift0 : closed.
Hint Resolve @closed_wrt_lift0C @closed_wrtl_lift0C: closed.
Hint Resolve closed_wrt_lift1 closed_wrtl_lift1 : closed.
Hint Resolve @closed_wrt_lift1C @closed_wrtl_lift1C : closed.
Hint Resolve closed_wrt_lift2 closed_wrtl_lift2 : closed.
Hint Resolve @closed_wrt_lift2C @closed_wrtl_lift2C : closed.
Hint Resolve closed_wrt_lift3 closed_wrtl_lift3 : closed.
Hint Resolve @closed_wrt_lift3C @closed_wrtl_lift3C : closed.
Hint Resolve closed_wrt_lift4  closed_wrtl_lift4 : closed.
Hint Resolve @closed_wrt_lift4C @closed_wrtl_lift4C : closed.
Hint Resolve @closed_wrt_const @closed_wrtl_const : closed.
Hint Resolve closed_wrt_eval_var : closed.
Hint Resolve closed_wrtl_eval_var : closed.
(* Lemma closed_wrt_var: forall S id t v, closed_wrt_vars S (var id t v). Hint Resolve closed_wrt_var : closed.  Lemma closed_wrtl_var: forall S id t v, ~ S id -> closed_wrt_lvars S (var id t v). Hint Resolve closed_wrtl_var : closed. *)
Hint Resolve closed_wrt_lvar : closed.
Hint Resolve closed_wrt_gvars : closed.
Hint Resolve closed_wrtl_gvars : closed.
Hint Resolve closed_wrtl_lvar : closed.
Definition expr_closed_wrt_lvars (S: ident -> Prop) (e: expr) : Prop :=
forall (cs: compspecs) rho ve',
(forall i, S i \/ Map.get (ve_of rho) i = Map.get ve' i) ->
eval_expr e rho = eval_expr e (mkEnviron (ge_of rho) ve' (te_of rho)).
Definition lvalue_closed_wrt_lvars (S: ident -> Prop) (e: expr) : Prop :=
forall (cs: compspecs) rho ve',
(forall i, S i \/ Map.get (ve_of rho) i = Map.get ve' i) ->
eval_lvalue e rho = eval_lvalue e (mkEnviron (ge_of rho) ve'  (te_of rho)).
Hint Resolve closed_wrt_cmp_ptr closed_wrtl_cmp_ptr: closed.
Hint Resolve closed_wrt_eval_id closed_wrtl_eval_id : closed.
Hint Resolve closed_wrt_temp closed_wrtl_temp : closed.
Hint Resolve closed_wrt_get_result1 closed_wrtl_get_result1 : closed.
Hint Resolve closed_wrt_tc_FF closed_wrtl_tc_FF : closed.
Hint Resolve closed_wrt_tc_TT closed_wrtl_tc_TT : closed.
Hint Resolve closed_wrt_andp closed_wrtl_andp : closed.
Hint Resolve closed_wrt_exp closed_wrtl_exp : closed.
Hint Resolve closed_wrt_imp closed_wrtl_imp : closed.
Hint Resolve closed_wrt_sepcon closed_wrtl_sepcon : closed.
Hint Resolve closed_wrt_allp closed_wrtl_allp : closed.
Hint Resolve closed_wrt_globvars closed_wrtl_globvars: closed.
Hint Resolve closed_wrt_main_pre closed_wrtl_main_pre : closed.
Hint Resolve closed_wrt_not1 : closed.
Hint Resolve closed_wrt_tc_andp closed_wrt_tc_orp closed_wrt_tc_bool
closed_wrt_tc_int_or_ptr_type : closed.
Hint Resolve closed_wrtl_tc_andp closed_wrtl_tc_orp closed_wrtl_tc_bool : closed.
Hint Resolve  closed_wrt_tc_test_eq  closed_wrtl_tc_test_eq : closed.
Hint Resolve  closed_wrt_tc_test_order  closed_wrtl_tc_test_order : closed.
Hint Resolve expr_closed_const_int expr_closedl_const_int : closed.
Hint Resolve closed_wrt_tc_iszero : closed.
Hint Resolve closed_wrtl_tc_iszero : closed.
Hint Resolve closed_wrt_tc_isptr : closed.
Hint Resolve closed_wrtl_tc_isptr : closed.
Hint Resolve closed_wrt_tc_isint : closed.
Hint Resolve closed_wrtl_tc_isint : closed.
Hint Resolve closed_wrt_tc_islong : closed.
Hint Resolve closed_wrtl_tc_islong : closed.
Hint Resolve closed_wrtl_tc_Zge closed_wrtl_tc_Zle : closed.
Hint Resolve closed_wrt_isCastResultType closed_wrtl_isCastResultType : closed.
Hint Resolve closed_wrt_tc_temp_id closed_wrtl_tc_temp_id : closed.
Hint Resolve expr_closed_tempvar expr_closedl_tempvar : closed.
Hint Extern 1 (not (@eq ident _ _)) => (let Hx := fresh in intro Hx; inversion Hx) : closed.
Hint Resolve expr_closed_cast expr_closedl_cast : closed.
Hint Resolve expr_closed_field expr_closedl_field : closed.
Hint Resolve expr_closed_binop expr_closedl_binop : closed.
Hint Resolve expr_closed_unop expr_closedl_unop : closed.
Hint Resolve closed_wrt_stackframe_of : closed.
Definition included {U} (S S': U -> Prop) := forall x, S x -> S' x.
Hint Resolve closed_wrt_TT closed_wrtl_TT : closed.
Hint Resolve closed_wrt_subset closed_wrtl_subset : closed.
Hint Resolve lvalue_closed_tempvar lvalue_closedl_tempvar : closed.
Hint Resolve expr_closed_addrof expr_closedl_addrof : closed.
Hint Resolve lvalue_closed_field lvalue_closedl_field : closed.
Hint Resolve lvalue_closed_deref lvalue_closedl_deref: closed.
Fixpoint closed_eval_expr (j: ident) (e: expr) : bool :=
match e with
| Econst_int i ty => true
| Econst_long i ty => true
| Econst_float f ty => true
| Econst_single f ty => true
| Etempvar id ty => negb (eqb_ident j id)
| Eaddrof a ty => closed_eval_lvalue j a
| Eunop op a ty =>  closed_eval_expr j a
| Ebinop op a1 a2 ty =>  andb (closed_eval_expr j a1) (closed_eval_expr j a2)
| Ecast a ty => closed_eval_expr j a
| Evar id ty => true
| Ederef a ty => closed_eval_expr j a
| Efield a i ty => closed_eval_lvalue j a
| Esizeof _ _ => true
| Ealignof _ _ => true
end
with closed_eval_lvalue (j: ident) (e: expr) : bool :=
match e with
| Evar id ty => true
| Ederef a ty => closed_eval_expr j a
| Efield a i ty => closed_eval_lvalue j a
| _  => false
end.
Hint Extern 2 (closed_wrt_vars (eq _) (@eval_expr _ _)) => (apply closed_eval_expr_e; reflexivity) : closed.
Hint Extern 2 (closed_wrt_vars (eq _) (@eval_lvalue _ _)) => (apply closed_eval_lvalue_e; reflexivity) : closed.
(* Hint Resolve closed_wrt_eval_expr : closed. *)
(* Hint Resolve closed_wrt_lvalue : closed. *)
Hint Extern 2 (closed_wrt_vars (eq _) _) =>
(apply closed_wrt_ideq; [solve [let Hx := fresh in (intro Hx; inv Hx)] | reflexivity]) : closed.
Hint Resolve closed_wrt_tc_nonzero : closed.
Hint Resolve closed_wrt_binarithType : closed.
Hint Resolve closed_wrt_tc_samebase : closed.
Hint Resolve closed_wrt_tc_ilt : closed.
Hint Resolve closed_wrt_tc_llt : closed.
Hint Resolve closed_wrt_tc_Zge : closed.
Hint Resolve closed_wrt_tc_Zle : closed.
Hint Resolve @closed_wrt_replace_nth : closed.
Hint Resolve closed_wrt_tc_nodivover : closed.
Hint Resolve closed_wrt_tc_nosignedover : closed.
Hint Resolve closed_wrt_tc_nobinover : closed.
Hint Resolve closed_wrt_tc_expr : closed.
Hint Resolve closed_wrt_tc_lvalue : closed.
Hint Resolve closed_wrt_lift1' : closed.
Hint Resolve closed_wrt_Econst_int : closed.
Hint Resolve closed_wrt_PROPx closed_wrtl_PROPx: closed.
(* Lemma closed_wrt_LOCALx: forall S Q R, Forall (fun q => closed_wrt_vars S (local q)) Q -> closed_wrt_vars S R -> closed_wrt_vars S (LOCALx Q R). *)
Hint Resolve closed_wrt_LOCALx closed_wrtl_LOCALx: closed.
Hint Resolve closed_wrt_SEPx closed_wrtl_SEPx: closed.
Hint Resolve not_not_a_param_i : closed.
Hint Resolve in_map_fst1 : closed.
Hint Resolve in_map_fst2 : closed.
Ltac precondition_closed :=  (* obsolete? DELETE_ME *)
match goal with |- precondition_closed _ _ => idtac end;
let x := fresh "x" in intro x;
split;
repeat match goal with
| |- closed_wrt_vars _ (let (y,z) := ?x in _) => is_var x; destruct x
| |- closed_wrt_lvars _ (let (y,z) := ?x in _) => is_var x; destruct x
end;
[simpl not_a_param; auto 50 with closed
| simpl is_a_local; auto 50 with closed ].

Lemma Forall_map_cons:
forall {A B} (F: A -> Prop) (g: B -> A) b bl,
F (g b) -> Forall F (map g bl) ->
Forall F (map g (b::bl)).