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.

Lemma expr_closed_binop: forall {cs: compspecs} S op e1 e2 t,
expr_closed_wrt_vars S e1 ->
expr_closed_wrt_vars S e2 ->
expr_closed_wrt_vars S (Ebinop op e1 e2 t).