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.

Lemma closed_wrt_lift3C: forall {A1 A2 A3}{B} S (f: A1 -> A2 -> A3 -> B) P1 P2 P3,
closed_wrt_vars S P1 ->
closed_wrt_vars S P2 ->
closed_wrt_vars S P3 ->
closed_wrt_vars S (@liftx (Tarrow A1 (Tarrow A2 (Tarrow A3 (LiftEnviron B)))) f P1 P2 P3).