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

Lemma closed_wrt_cmp_ptr : forall {cs: compspecs} S e1 e2 c,
expr_closed_wrt_vars S e1 ->
expr_closed_wrt_vars S e2 ->
closed_wrt_vars S (`(cmp_ptr_no_mem c) (eval_expr e1) (eval_expr e2)).