Global Opaque denote_tc_test_eq.
Hint Rewrite @sem_add_pi_ptr_special' using (solve [try reflexivity; auto with norm]) : norm.
Hint Rewrite @sem_add_pl_ptr_special' using (solve [try reflexivity; auto with norm]) : norm.
Hint Extern 2 (isptr (force_val (sem_add_ptr_int _ _ _ _))) =>
apply isptr_force_sem_add_ptr_int; [reflexivity | auto with prove_it_now] : core.
(* Done in this tail-recursive style so that "hnf" fully reduces it *)
Fixpoint mk_varspecs' (dl: list (ident * globdef Clight.fundef type)) (el: list (ident * type)) :
list (ident * type) :=
match dl with
| (i,Gvar v)::dl' => mk_varspecs' dl' ((i, gvar_info v) :: el)
| (i, _) :: dl' => mk_varspecs' dl' el
| nil => rev_append el nil
end.
Ltac unfold_varspecs al :=
match al with
| context [gvar_info ?v] =>
let b := eval lazy beta zeta iota delta [gvar_info v] in al
in unfold_varspecs b
| _ => exact al
end.
Ltac mk_varspecs prog :=
let a := constr:(prog)
in let a := eval unfold prog in a
in let d :=  match a with
| Clightdefs.mkprogram _ ?d _ _ _ => constr:(d)
| {| prog_defs := ?d |} => constr:(d)
end
in let e := constr:(mk_varspecs' d nil)
in let e := eval hnf in e
in unfold_varspecs e.
Hint Resolve field_address_isptr : norm.
Hint Resolve field_address_eq_offset' : prove_it_now.
Hint Rewrite <- @prop_and using solve [auto with typeclass_instances]: norm1.
Local Open Scope logic.
Ltac process_stackframe_of :=
match goal with |- semax _ (_ * stackframe_of ?F) _ _ =>
let sf := fresh "sf" in set (sf:= stackframe_of F) at 1;
unfold stackframe_of in sf; simpl map in sf; subst sf
end;
repeat
match goal with |- semax _ (_ * fold_right sepcon emp (var_block _ (?i,_) :: _)) _ _ =>
match goal with
| n: name i |- _ => simple apply var_block_lvar2;
[ reflexivity | reflexivity | reflexivity | reflexivity | clear n; intro n ]
| |- _ =>    simple apply var_block_lvar2;
[ reflexivity | reflexivity | reflexivity | reflexivity | let n := fresh "v" i in intros n ]
end
end;
(* match goal with |- semax _ ?Pre _ _ => let p := fresh "p" in set (p := Pre); rewrite <- (@emp_sepcon (environ->mpred) _ _ _ (fold_right _ _ _)); subst p end; *)
repeat (simple apply postcondition_var_block;
[reflexivity | reflexivity | reflexivity | reflexivity | reflexivity |  ]);
change (fold_right sepcon emp (@nil (environ->mpred))) with
(@emp (environ->mpred) _ _);
rewrite ?sepcon_emp, ?emp_sepcon.
Definition tc_option_val' (t: type) : option val -> Prop :=
match t with Tvoid => fun v => match v with None => True | _ => False end | _ => fun v => tc_val t (force_val v) end.
Hint Rewrite tc_option_val'_eq : norm.
Definition tycontext_subVG Vprog1 Gprog1 Vprog2 Gprog2 :=
(forall id : positive,
sub_option (make_tycontext_g Vprog1 Gprog1) ! id
(make_tycontext_g Vprog2 Gprog2) ! id) /\
(forall id : positive,
subsumespec (make_tycontext_s Gprog1) ! id (make_tycontext_s Gprog2) ! id).
(* Ltac apply_semax_body L := eapply (@semax_body_subsumption' _ _ _ _ _ _ _ _ L); [red; red; apply @sub_option_get; repeat (apply Forall_cons; [reflexivity | ]);  apply Forall_nil | repeat (apply Forall_cons; [ reflexivity | ]); apply Forall_nil | simple apply tycontext_sub_refl || (apply tycontext_sub_i99; assumption)]. *)
Ltac apply_semax_body L :=
eapply (@semax_body_subsumption' _ _ _ _ _ _ _ _ L);
[ first [ apply cspecs_sub_refl
| split3; red; apply @sub_option_get;
repeat (apply Forall_cons; [reflexivity | ]);  apply Forall_nil ]
| repeat (apply Forall_cons; [ reflexivity | ]); apply Forall_nil
| simple apply tycontext_sub_refl ||
(apply tycontext_sub_i99; assumption)].
Ltac try_prove_tycontext_subVG L :=
match goal with |- semax_func ?V2 ?G2 _ _ _ =>
try match type of L with
| semax_body ?V1 ?G1 _ _ =>
lazymatch goal with
| H: tycontext_subVG V1 G1 V2 G2 |- _ => idtac
| _ =>
let H := fresh in
try assert (H: tycontext_subVG V1 G1 V2 G2) by
(split;
[ apply sub_option_get;  repeat (apply Forall_cons; [reflexivity | ]);  apply Forall_nil
| apply subsume_spec_get;
repeat (apply Forall_cons; [apply subsumespec_refl | ]); apply Forall_nil])
end end end.
Ltac semax_func_cons L :=
repeat (eapply semax_func_cons_ext_vacuous; [reflexivity | reflexivity | LookupID | LookupB |]);
try_prove_tycontext_subVG L;
first [eapply semax_func_cons;
[ reflexivity
| repeat apply Forall_cons; try apply Forall_nil; try computable; reflexivity
| unfold var_sizes_ok; repeat constructor; try (simpl; rep_omega)
| reflexivity | LookupID | LookupB
| try solve [apply L]; apply_semax_body L
| ]
| eapply semax_func_cons_ext;
[reflexivity | reflexivity | reflexivity | reflexivity | reflexivity
| left; reflexivity
| semax_func_cons_ext_tc | LookupID | LookupB | apply L |
]
];
repeat (eapply semax_func_cons_ext_vacuous; [reflexivity | reflexivity | LookupID | LookupB |]);
try apply semax_func_nil.
Ltac semax_func_cons_ext :=
repeat (eapply semax_func_cons_ext_vacuous; [reflexivity | reflexivity | LookupID | LookupB | ]);
eapply semax_func_cons_ext;
[ reflexivity | reflexivity | reflexivity | reflexivity | reflexivity
| left; reflexivity
| semax_func_cons_ext_tc;
try solve [apply typecheck_return_value; auto]
| LookupID | LookupB
| solve[ first [eapply semax_ext;
[ (*repeat first [reflexivity | left; reflexivity | right]*) apply from_elements_In; reflexivity
| apply compute_funspecs_norepeat_e; reflexivity
| reflexivity
| reflexivity ]]]
|| fail "Try 'eapply semax_func_cons_ext.'"
"To solve [semax_external] judgments, do 'eapply semax_ext.'"
"Make sure that the Espec declared using 'Existing Instance'
is defined as 'add_funspecs NullExtension.Espec Gprog.'"
|
].
Tactic Notation "forward_seq" :=
first [eapply semax_seq'; [  | abbreviate_semax ]
| eapply semax_post_flipped' ].
Tactic Notation "forward_seq" constr(R) :=
match goal with P := @abbreviate ret_assert _ |- semax _ _ _ ?P' =>
constr_eq P P'; unfold abbreviate in P; subst P;
first [apply semax_seq with R; abbreviate_semax
| apply (semax_post_flipped' R); [abbreviate_semax | ]]
end.
(* old: Ltac forward_seq := first [eapply semax_seq'; [  | abbreviate_semax ] | eapply semax_post_flipped' ]. *)
(* end of "stuff to move elsewhere" *)
Ltac Forall_pTree_from_elements :=
cbv beta;
unfold PTree.elements; simpl PTree.xelements;
go_lower;
repeat (( simple apply derives_extract_prop
|| simple apply derives_extract_prop');
fancy_intros true);
autorewrite with gather_prop;
repeat (( simple apply derives_extract_prop
|| simple apply derives_extract_prop');
fancy_intros true);
repeat erewrite unfold_reptype_elim in * by reflexivity;
try autorewrite with entailer_rewrite in *;
repeat first
[ apply prop_Forall_cons1;
[unfold check_one_temp_spec, check_gvars_spec;
simpl; auto;
solve [normalize]
| ]
| apply prop_Forall_cons'
| apply prop_Forall_cons
| apply prop_Forall_nil'
| apply prop_Forall_nil
];
unfold check_one_temp_spec; simpl PTree.get.
Ltac  unify_postcondition_exps :=
first [ reflexivity
| rewrite exp_uncurry;
apply exp_congr; intros [? ?]; simpl; reflexivity
| rewrite exp_uncurry2;
apply exp_congr; intros [[? ?] ?]; simpl; reflexivity
| rewrite exp_uncurry3;
apply exp_congr; intros [[[? ?] ?] ?]; simpl; reflexivity
].
Ltac change_compspecs' cs cs' :=
match goal with
| |- context [@data_at cs' ?sh ?t ?v1] => erewrite (@data_at_change_composite cs' cs _ sh t); [| apply JMeq_refl | reflexivity]
| |- context [@field_at cs' ?sh ?t ?gfs ?v1] => erewrite (@field_at_change_composite cs' cs _ sh t gfs); [| apply JMeq_refl | reflexivity]
| |- context [@data_at_ cs' ?sh ?t] => erewrite (@data_at__change_composite cs' cs _ sh t); [| reflexivity]
| |- context [@field_at_ cs' ?sh ?t ?gfs] => erewrite (@field_at__change_composite cs' cs _ sh t gfs); [| reflexivity]
| |- context [?A cs'] => change (A cs') with (A cs)
| |- context [?A cs' ?B] => change (A cs' B) with (A cs B)
| |- context [?A cs' ?B ?C] => change (A cs' B C) with (A cs B C)
| |- context [?A cs' ?B ?C ?D] => change (A cs' B C D) with (A cs B C D)
| |- context [?A cs' ?B ?C ?D ?E] => change (A cs' B C D E) with (A cs B C D E)
| |- context [?A cs' ?B ?C ?D ?E ?F] => change (A cs' B C D E F) with (A cs B C D E F)
end.
(* TODO: use CCE as arguments to gain CS' *)
Ltac change_compspecs cs :=
match goal with |- context [?cs'] =>
match type of cs' with compspecs =>
try (constr_eq cs cs'; fail 1);
change_compspecs' cs cs';
repeat change_compspecs' cs cs'
end
end.
Definition Warning_perhaps_funspec_postcondition_needs_EX_outside_PROP_LOCAL_SEP (p: Prop) := p.
Ltac give_EX_warning :=
match goal with |- ?A => change
(Warning_perhaps_funspec_postcondition_needs_EX_outside_PROP_LOCAL_SEP A)
end.
Ltac check_parameter_types :=
first [reflexivity | elimtype  Parameter_types_in_funspec_different_from_call_statement].
Ltac check_result_type :=
first [reflexivity | elimtype  Result_type_in_funspec_different_from_call_statement].
Inductive Cannot_find_function_spec_in_Delta (id: ident) := .
Inductive Global_function_name_shadowed_by_local_variable := .
Ltac check_function_name :=
first [reflexivity | elimtype Global_function_name_shadowed_by_local_variable].
Inductive Actual_parameters_cannot_be_coerced_to_formal_parameter_types := .
Ltac check_cast_params :=
reflexivity +
(simpl explicit_cast_exprlist;
match goal with |- force_list (map ?F ?A) = _ =>
let el := constr:(A) in
let bl := constr:(map F A) in
let cl := eval simpl in bl in
fail 100 "Some of the argument expressions in your function call do not evaluate (sometimes this is caused by missing LOCALs in your precondition).  Your argument expressions are:"
el "They evaluate (or fail) as follows:" cl
end).
Inductive Witness_type_of_forward_call_does_not_match_witness_type_of_funspec:
Type -> Type -> Prop := .
Ltac find_spec_in_globals' :=
match goal with |- ?X = _ => let x := fresh "x" in set (x:=X); hnf in x; subst x end;
try reflexivity.
Inductive Cannot_analyze_LOCAL_definitions : Prop := .
Ltac check_prove_local2ptree :=
first [prove_local2ptree | elimtype Cannot_analyze_LOCAL_definitions].
Inductive Funspec_precondition_is_not_in_PROP_LOCAL_SEP_form := .
Ltac check_funspec_precondition :=
first [reflexivity | elimtype  Funspec_precondition_is_not_in_PROP_LOCAL_SEP_form].
Ltac lookup_spec id :=
tryif apply f_equal_Some
then
match goal with
| |- vacuous_funspec _ = _ => fail 100 "Your Gprog contains no funspec with the name" id
| |- ?fs = _ => check_canonical_funspec (id,fs);
first [reflexivity |
match goal with
| |- mk_funspec _ _ ?t1 _ _ = mk_funspec _ _ ?t2 _ _ =>
first [unify t1 t2
| elimtype False; elimtype (Witness_type_of_forward_call_does_not_match_witness_type_of_funspec
t2 t1)]
end]
end
else elimtype  (Cannot_find_function_spec_in_Delta id).
Inductive Function_arguments_include_a_memory_load_of_type (t:type) := .
Ltac goal_has_evars :=
match goal with |- ?A => has_evar A end.
Ltac delete_FRZR_from_SEP :=
match goal with
| |- ENTAIL _, PROPx _ (LOCALx _ (SEPx ?R)) |-- _ =>
match R with context [FRZR] =>
eapply drop_SEP_tc;
[ first [apply extend_tc.extend_tc_expr
| apply extend_tc.extend_tc_exprlist
| apply extend_tc.extend_tc_lvalue]
| apply split_FRZ_in_SEP_spec; prove_split_FRZ_in_SEP
| ]
end end.
Ltac check_typecheck :=
try delete_FRZR_from_SEP;
first [goal_has_evars; idtac |
try apply local_True_right;
entailer!;
match goal with
| |- typecheck_error (deref_byvalue ?T) =>
elimtype (Function_arguments_include_a_memory_load_of_type T)
| |- _ => idtac
end].
Ltac prove_delete_temp := match goal with |- ?A = _ =>
let Q := fresh "Q" in set (Q:=A); hnf in Q; subst Q; reflexivity
end.
Ltac cancel_for_forward_call := cancel_for_evar_frame.
Ltac default_cancel_for_forward_call := cancel_for_evar_frame.
Ltac unfold_post := match goal with |- ?Post = _ => let A := fresh "A" in let B := fresh "B" in first
[evar (A : Type); evar (B : A -> environ -> mpred); unify Post (@exp _ _ ?A ?B);
change Post with (@exp _ _ A B); subst A B |
evar (A : list Prop); evar (B : environ -> mpred); unify Post (PROPx ?A ?B);
change Post with (PROPx A B); subst A B | idtac] end.
Ltac match_postcondition :=
cbv beta iota zeta; unfold_post;  extensionality rho;
repeat rewrite exp_uncurry;
try rewrite no_post_exists; repeat rewrite exp_unfold;
tryif apply exp_congr
then (intros ?vret;
apply equal_f;
apply PROP_LOCAL_SEP_ext; [reflexivity | | reflexivity];
(reflexivity || fail "The funspec of the function has a POSTcondition
that is ill-formed.  The LOCALS part of the postcondition
should be (temp ret_temp ...), but it is not"))
else fail "The funspec of the function should have a POSTcondition that starts
with an existential, that is,  EX _:_, PROP...LOCAL...SEP".
(* Ltac match_postcondition := cbv beta iota zeta; unfold_post; extensionality rho; repeat rewrite exp_uncurry; try rewrite no_post_exists; repeat rewrite exp_unfold; first [apply exp_congr; intros ?vret; reflexivity | give_EX_warning ]. *)
Ltac  forward_call_id1_wow_nil :=
let H := fresh in intro H;
eapply (semax_call_id1_wow_nil _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ H);
clear H;
lazymatch goal with Frame := _ : list mpred |- _ => try clear Frame end;
[check_result_type
|apply Logic.I
| match_postcondition
| prove_delete_temp
| unify_postcondition_exps
| unfold fold_right_and; repeat rewrite and_True; auto
].
Ltac  forward_call_id1_wow :=
let H := fresh in intro H;
eapply (semax_call_id1_wow _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ H);
clear H;
lazymatch goal with Frame := _ : list mpred |- _ => try clear Frame end;
[check_result_type
|apply Logic.I
| match_postcondition
| prove_delete_temp
| unify_postcondition_exps
| unfold fold_right_and; repeat rewrite and_True; auto
].
Ltac forward_call_id1_x_wow_nil :=
let H := fresh in intro H;
eapply (semax_call_id1_x_wow_nil
_ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ H);
clear H;
lazymatch goal with Frame := _ : list mpred |- _ => try clear Frame end;
[ check_result_type | check_result_type
| apply Coq.Init.Logic.I | apply Coq.Init.Logic.I | reflexivity
| (clear; let H := fresh in intro H; inversion H)
| match_postcondition
| prove_delete_temp
| prove_delete_temp
| unify_postcondition_exps
| unfold fold_right_and; repeat rewrite and_True; auto
].
Ltac forward_call_id1_x_wow :=
let H := fresh in intro H;
eapply (semax_call_id1_x_wow
_ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ H);
clear H;
lazymatch goal with Frame := _ : list mpred |- _ => try clear Frame end;
[ check_result_type | check_result_type
| apply Coq.Init.Logic.I | apply Coq.Init.Logic.I | reflexivity
| (clear; let H := fresh in intro H; inversion H)
| match_postcondition
| prove_delete_temp
| prove_delete_temp
| unify_postcondition_exps
| unfold fold_right_and; repeat rewrite and_True; auto
].
Ltac forward_call_id1_y_wow_nil :=
let H := fresh in intro H;
eapply (semax_call_id1_y_wow_nil
_ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ H);
clear H;
lazymatch goal with Frame := _ : list mpred |- _ => try clear Frame end;
[ check_result_type | check_result_type
| apply Coq.Init.Logic.I | apply Coq.Init.Logic.I | reflexivity
| (clear; let H := fresh in intro H; inversion H)
| match_postcondition
| prove_delete_temp
| prove_delete_temp
| unify_postcondition_exps
| unfold fold_right_and; repeat rewrite and_True; auto
].
Ltac forward_call_id1_y_wow :=
let H := fresh in intro H;
eapply (semax_call_id1_y_wow
_ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ H);
clear H;
lazymatch goal with Frame := _ : list mpred |- _ => try clear Frame end;
[ check_result_type | check_result_type
| apply Coq.Init.Logic.I | apply Coq.Init.Logic.I | reflexivity
| (clear; let H := fresh in intro H; inversion H)
| match_postcondition
| prove_delete_temp
| prove_delete_temp
| unify_postcondition_exps
| unfold fold_right_and; repeat rewrite and_True; auto
].
Ltac forward_call_id01_wow_nil :=
let H := fresh in intro H;
eapply (semax_call_id01_wow_nil _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ H);
clear H;
lazymatch goal with Frame := _ : list mpred |- _ => try clear Frame end;
[ apply Coq.Init.Logic.I
| match_postcondition
| unify_postcondition_exps
| unfold fold_right_and; repeat rewrite and_True; auto
].
Ltac forward_call_id01_wow :=
let H := fresh in intro H;
eapply (semax_call_id01_wow
_ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ H);
clear H;
lazymatch goal with Frame := _ : list mpred |- _ => try clear Frame end;
[ apply Coq.Init.Logic.I
| match_postcondition
| unify_postcondition_exps
| unfold fold_right_and; repeat rewrite and_True; auto
].
Ltac forward_call_id00_wow_nil  :=
let H := fresh in intro H;
eapply (semax_call_id00_wow_nil _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ H);
clear H;
lazymatch goal with Frame := _ : list mpred |- _ => try clear Frame end;
[ check_result_type
| cbv beta iota zeta; unfold_post; (* extensionality rho; *)
repeat rewrite exp_uncurry;
try rewrite no_post_exists0;
(* apply equal_f; *)
apply exp_congr; intros ?vret;
apply PROP_LOCAL_SEP_ext; [reflexivity | | reflexivity];
(reflexivity || fail "The funspec of the function has a POSTcondition
that is ill-formed.  The LOCALS part of the postcondition
should be empty, but it is not")
| unify_postcondition_exps
| unfold fold_right_and; repeat rewrite and_True; auto
].
Ltac forward_call_id00_wow  :=
let H := fresh in intro H;
eapply (semax_call_id00_wow _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ H);
clear H;
lazymatch goal with Frame := _ : list mpred |- _ => try clear Frame end;
[ check_result_type
| (*match_postcondition*)
cbv beta iota zeta; unfold_post; (* extensionality rho; *)
repeat rewrite exp_uncurry;
try rewrite no_post_exists0;
(* apply equal_f; *)
apply exp_congr; intros ?vret;
apply PROP_LOCAL_SEP_ext; [reflexivity | | reflexivity];
(reflexivity || fail "The funspec of the function has a POSTcondition
that is ill-formed.  The LOCALS part of the postcondition
should be empty, but it is not")
| unify_postcondition_exps
| unfold fold_right_and; repeat rewrite and_True; auto
].
Ltac simpl_strong_cast :=
try match goal with |- context [strong_cast ?t1 ?t2 ?v] =>
first [change (strong_cast t1 t2 v) with v
| change (strong_cast t1 t2 v) with
(force_val (sem_cast t1 t2 v))
]
end.
Ltac fwd_skip :=
match goal with |- semax _ _ Sskip _ =>
normalize_postcondition;
first [eapply semax_pre | eapply semax_pre_simple];
[ | apply semax_skip]
end.
Definition BINDER_NAME := tt.
Ltac find_postcond_binder_names :=
match goal with |- semax ?Delta _ ?c _ =>
match c with context [Scall _ (Evar ?id _) _] =>
let x := constr:((glob_specs Delta) ! id) in
let x' := eval hnf in x in
match x' with
| Some (mk_funspec _ _ _ _ (fun _ => exp (fun y1 => exp (fun y2 => exp (fun y3 => exp (fun y4 => _)))))) =>
let y4' := fresh y4 in  pose (y4' := BINDER_NAME);
let y3' := fresh y3 in  pose (y3' := BINDER_NAME);
let y2' := fresh y2 in  pose (y2' := BINDER_NAME);
let y1' := fresh y1 in  pose (y1' := BINDER_NAME)
| Some (mk_funspec _ _ _ _ (fun _ => exp (fun y1 => exp (fun y2 => exp (fun y3 => _))))) =>
let y3' := fresh y3 in  pose (y3' := BINDER_NAME);
let y2' := fresh y2 in  pose (y2' := BINDER_NAME);
let y1' := fresh y1 in  pose (y1' := BINDER_NAME)
| Some (mk_funspec _ _ _ _ (fun _ => exp (fun y1 => exp (fun y2 => _)))) =>
let y2' := fresh y2 in  pose (y2' := BINDER_NAME);
let y1' := fresh y1 in  pose (y1' := BINDER_NAME)
| Some (mk_funspec _ _ _ _ (fun _ => exp (fun y1 => _))) =>
let y1' := fresh y1 in  pose (y1' := BINDER_NAME)
| _ => idtac
end
end
end.
Ltac after_forward_call_binders :=
repeat match goal with
| r := BINDER_NAME |- _ =>
clear r; apply extract_exists_pre; intro r
| |- _ => apply extract_exists_pre; intros ?vret
end.
Ltac cleanup_no_post_exists :=
match goal with |-  context[eq_no_post] =>
let vret := fresh "vret" in let H := fresh in
apply extract_exists_pre; intro vret;
apply semax_extract_PROP; intro H;
change (eq_no_post vret) with (eq vret) in H;
subst vret
end
|| unfold eq_no_post.
Ltac factor_out_v L :=
match L with
| temp _ ?v :: ?L' => factor_out_v' v L'
| lvar _ _ ?v :: ?L' => factor_out_v' v L'
| _ => constr:(@nil val)
end
with factor_out_v' v L' := let x := fresh "v" in set (x:=v);
let y :=factor_out_v L'
in constr:(x::y).
Ltac factor_back L :=
match L with
| ?x :: ?y => subst x; factor_back y
| nil => idtac
end.
Ltac simplify_remove_localdef_temp :=
match goal with |- context [remove_localdef_temp ?i ?L]  =>
let L' := factor_out_v L in
simpl remove_localdef_temp;
factor_back L'
end.
Ltac after_forward_call :=
check_POSTCONDITION;
try match goal with |- context [remove_localdef_temp] =>
simplify_remove_localdef_temp
end;
unfold_app;
try (apply extract_exists_pre; intros _);
match goal with
| |- semax _ _ _ _ => idtac
| |- unit -> semax _ _ _ _ => intros _
end;
match goal with
| |- @semax ?CS _ _ _ _ _ => try change_compspecs CS
end;
repeat (apply semax_extract_PROP; intro);
cleanup_no_post_exists;
abbreviate_semax;
try fwd_skip.
Ltac clear_MORE_POST :=
try match goal with POSTCONDITION := @abbreviate ret_assert _ |- _ =>
clear POSTCONDITION
end;
try match goal with MORE_COMMANDS := @abbreviate statement _ |- _ =>
clear MORE_COMMANDS
end.
Inductive Ridiculous: Type := .
Ltac check_witness_type ts A witness :=
(unify A (rmaps.ConstType Ridiculous); (* because [is_evar A] doesn't seem to work *)
elimtype False)
||
let TA := constr:(functors.MixVariantFunctor._functor
(rmaps.dependent_type_functor_rec ts A) mpred) in
let TA' := eval cbv
[functors.MixVariantFunctor._functor
functors.MixVariantFunctorGenerator.fpair
functors.MixVariantFunctorGenerator.fconst
functors.MixVariantFunctorGenerator.fidentity
rmaps.dependent_type_functor_rec
functors.GeneralFunctorGenerator.CovariantBiFunctor_MixVariantFunctor_compose
functors.CovariantFunctorGenerator.fconst
functors.CovariantFunctorGenerator.fidentity
functors.CovariantBiFunctor._functor
functors.CovariantBiFunctorGenerator.Fpair
functors.GeneralFunctorGenerator.CovariantFunctor_MixVariantFunctor
functors.CovariantFunctor._functor
functors.MixVariantFunctor.fmap
] in TA
in let TA'' := eval simpl in TA'
in match type of witness with ?T =>
unify T TA''
+ (fail "Type of witness does not match type required by funspec WITH clause.
Witness value: " witness "
Witness type: " T "
Funspec type: " TA'')
end.
(*ready for deletion*)
Ltac check_witness_type_nil A witness :=
(unify A (rmaps.ConstType Ridiculous); (* because [is_evar A] doesn't seem to work *)
elimtype False)
||
let TA := constr:(functors.MixVariantFunctor._functor
(rmaps.dependent_type_functor_rec nil A) mpred) in
let TA' := eval cbv
[functors.MixVariantFunctor._functor
functors.MixVariantFunctorGenerator.fpair
functors.MixVariantFunctorGenerator.fconst
functors.MixVariantFunctorGenerator.fidentity
rmaps.dependent_type_functor_rec
functors.GeneralFunctorGenerator.CovariantBiFunctor_MixVariantFunctor_compose
functors.CovariantFunctorGenerator.fconst
functors.CovariantFunctorGenerator.fidentity
functors.CovariantBiFunctor._functor
functors.CovariantBiFunctorGenerator.Fpair
functors.GeneralFunctorGenerator.CovariantFunctor_MixVariantFunctor
functors.CovariantFunctor._functor
functors.MixVariantFunctor.fmap
] in TA
in let TA'' := eval simpl in TA'
in match type of witness with ?T =>
unify T TA''
+ (fail "Type of witness does not match type required by funspec WITH clause.
Witness value: " witness "
Witness type: " T "
Funspec type: " TA'')
end.
(* This is needed for the varargs (printf) hack *)
(* Ltac prove_call_setup1 subsumes := match goal with | |- @semax _ _ _ (@exp _ _ _ _) _ _ => fail 1 "forward_call fails because your precondition starts with EX. Use Intros  to move          the existentially bound variables above the line" | |- @semax ?CS _ ?Delta (PROPx ?P (LOCALx ?Q (SEPx ?R'))) ?c _ => lazymatch c with | context [Scall _ (Evar ?id ?ty) ?bl] => let R := strip1_later R' in exploit (call_setup1_i2 CS Delta P Q R' (*R*) id ty bl) ; [check_prove_local2ptree | apply can_assume_funcptr2; (*(can_assume_funcptr3 _ _ subsumes);*)
[ check_function_name
| lookup_spec id
| find_spec_in_globals'
| simpl; reflexivity  (* function-id type in AST matches type in funspec *)
]
| apply subsumes
| try reflexivity; (eapply classify_fun_ty_hack; [apply subsumes| reflexivity ..])  (* function-id type in AST matches type in funspec *)
|check_typecheck
|check_typecheck
|check_cast_params
|reflexivity
| ..
]
| context [Scall _ ?a ?bl] =>
let R := strip1_later R' in
exploit (call_setup1_i CS Delta P Q (*R*) R' a bl);
[check_prove_local2ptree
|reflexivity
|prove_func_ptr
| apply subsumes
|check_parameter_types
|check_typecheck
|check_typecheck
|check_cast_params
|reflexivity
| ]
end
end.
*)
(*The following version swaps the two context-cases and replaces the lazymatch by a match- we believe this priorizitizes func_ptr lookup over Delta-lookup*)
Ltac prove_call_setup1 subsumes :=
match goal with
| |- @semax _ _ _ (@exp _ _ _ _) _ _ =>
fail 1 "forward_call fails because your precondition starts with EX.
Use Intros  to move          the existentially bound variables above the line"
| |- @semax ?CS _ ?Delta (PROPx ?P (LOCALx ?Q (SEPx ?R'))) ?c _ =>
match c with
| context [Scall _ ?a ?bl] =>
let R := strip1_later R' in
exploit (call_setup1_i CS Delta P Q (*R*) R' a bl);
[check_prove_local2ptree
|reflexivity
|prove_func_ptr
| apply subsumes
|check_parameter_types
|check_typecheck
|check_typecheck
|check_cast_params
|reflexivity
| ]
| context [Scall _ (Evar ?id ?ty) ?bl] =>
let R := strip1_later R' in
exploit (call_setup1_i2 CS Delta P Q R' (*R*) id ty bl) ;
[check_prove_local2ptree
| apply can_assume_funcptr2; (*(can_assume_funcptr3 _ _ subsumes);*)
[ check_function_name
| lookup_spec id
| find_spec_in_globals'
| simpl; reflexivity  (* function-id type in AST matches type in funspec *)
]
| apply subsumes
| try reflexivity; (eapply classify_fun_ty_hack; [apply subsumes| reflexivity ..])  (* function-id type in AST matches type in funspec *)
|check_typecheck
|check_typecheck
|check_cast_params
|reflexivity
| ..
]
end
end.
Ltac check_gvars :=
first [exact Logic.I
| reflexivity
| match goal with |- check_gvars_spec None (Some ?gv) =>
fail 100 "The function precondition requires (gvars" gv ")" "which is not present in your current assertion's LOCAL clause"
end
].
Ltac prove_call_setup_aux  ts witness :=
let H := fresh in
intro H;
match goal with | |- @semax ?CS _ _ (PROPx ?P (LOCALx ?L (SEPx ?R'))) _ _ =>
let Frame := fresh "Frame" in evar (Frame: list mpred);
let R := strip1_later R' in
exploit (call_setup2_i _ _ _ _ _ _ _ _ R R' _ _ _ _ ts _ _ _ _ _ _ _ _ H witness Frame); clear H;
simpl functors.MixVariantFunctor._functor;
[ reflexivity
| check_prove_local2ptree
| Forall_pTree_from_elements
| auto 50 with derives
| unfold check_gvars_spec; solve [exact I | reflexivity]
| try change_compspecs CS; cancel_for_forward_call
|
]
end.
Ltac prove_call_setup ts subsumes witness :=
prove_call_setup1 subsumes;
[ .. |
match goal with |- call_setup1  _ _ _ _ _ _ _ _ (*_*) _ _ _ _ _ ?A _ _ _ _ _ _ _ -> _ =>
check_witness_type ts A witness
end;
prove_call_setup_aux ts witness].
Ltac fwd_call' ts subsumes witness :=
lazymatch goal with
| |- semax _ _ (Ssequence (Scall _ _ _) _) _ =>
eapply semax_seq';
[prove_call_setup ts subsumes witness;
clear_Delta_specs; clear_MORE_POST;
[ .. |
lazymatch goal with
| |- _ -> semax _ _ (Scall (Some _) _ _) _ =>(*
forward_call_id1_wow'
| |- call_setup2' _ _ _ _ _ _ _ _ _ _ _ _ ?retty _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ->
semax _ _ (Scall None _ _) _ =>*)
forward_call_id1_wow
| |- call_setup2 _ _ _ _ _ _ _ _ _ _ _ _ ?retty _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ->
semax _ _ (Scall None _ _) _ =>
tryif (unify retty Tvoid)
then forward_call_id00_wow(*'*)
else forward_call_id01_wow(*'*)
end]
| after_forward_call ]
| |- semax _ _ (Ssequence (Ssequence (Scall (Some ?ret') _ _)
(Sset _ (Ecast (Etempvar ?ret'2 _) _))) _) _ =>
unify ret' ret'2;
eapply semax_seq';
[prove_call_setup ts subsumes witness;
clear_Delta_specs; clear_MORE_POST;
[ .. | forward_call_id1_x_wow(*'*) ]
|  after_forward_call ]
| |- semax _ _ (Ssequence (Ssequence (Scall (Some ?ret') _ _)
(Sset _ (Etempvar ?ret'2 _))) _) _ =>
unify ret' ret'2;
eapply semax_seq';
[prove_call_setup ts subsumes witness;
clear_Delta_specs; clear_MORE_POST;
[ .. | forward_call_id1_y_wow(*'*) ]
|  after_forward_call ]
| |- _ => rewrite <- seq_assoc; fwd_call' ts subsumes witness
end.
Ltac fwd_call_dep ts subsumes witness :=
try lazymatch goal with
| |- semax _ _ (Scall _ _ _) _ => rewrite -> semax_seq_skip
end;
repeat lazymatch goal with
| |- semax _ _ (Ssequence (Ssequence (Ssequence _ _) _) _) _ =>
rewrite <- seq_assoc
end;
lazymatch goal with |- @semax ?CS _ ?Delta _ (Ssequence ?C _) _ =>
lazymatch C with context [Scall _ _ _] =>
fwd_call' ts subsumes witness
end
end.
Tactic Notation "forward_call" constr(ts) constr(subsumes) constr(witness) :=
fwd_call_dep ts subsumes witness.
Tactic Notation "forward_call" constr(witness) :=
fwd_call_dep (@nil Type) funspec_sub_refl witness.
Tactic Notation "forward_call" constr(subsumes) constr(witness) :=
fwd_call_dep (@nil Type) subsumes witness.
Ltac tuple_evar2 name T cb evar_tac :=
lazymatch T with
| prod ?A ?B => tuple_evar2 name A
ltac: (fun xA =>
tuple_evar2 name B ltac: (fun xB =>
cb (xA, xB)) evar_tac) evar_tac
| _ => my_unshelve_evar name T cb evar_tac
end; idtac.
Ltac get_function_witness_type func :=
let TA := constr:(functors.MixVariantFunctor._functor
(rmaps.dependent_type_functor_rec nil func) mpred) in
let TA' := eval cbv
[functors.MixVariantFunctor._functor
functors.MixVariantFunctorGenerator.fpair
functors.MixVariantFunctorGenerator.fconst
functors.MixVariantFunctorGenerator.fidentity
rmaps.dependent_type_functor_rec
functors.GeneralFunctorGenerator.CovariantBiFunctor_MixVariantFunctor_compose
functors.CovariantFunctorGenerator.fconst
functors.CovariantFunctorGenerator.fidentity
functors.CovariantBiFunctor._functor
functors.CovariantBiFunctorGenerator.Fpair
functors.GeneralFunctorGenerator.CovariantFunctor_MixVariantFunctor
functors.CovariantFunctor._functor
functors.MixVariantFunctor.fmap
] in TA
in let TA'' := eval simpl in TA'
in TA''.
Ltac new_prove_call_setup :=
prove_call_setup1 funspec_sub_refl;
[ .. |
match goal with |- call_setup1 _ _ _ _ _ _ _ _ _ (*_*) _ _ _ _ ?A _ _ _ _ _ _ _ -> _ =>
let x := fresh "x" in tuple_evar2 x ltac:(get_function_witness_type A)
ltac:(prove_call_setup_aux (@nil Type))
ltac:(fun _ => try refine tt; fail "Failed to infer some parts of witness")
end].
(* Ltac new_prove_call_setup := prove_call_setup1 funspec_sub_refl; [ .. | match goal with |- call_setup1 _ _ _ _ _ _ _ _ _ (*_*) _ _ _ _ ?A _ _ _ _ _ _ _ -> _ => let x := fresh "x" in tuple_evar2 x ltac:(get_function_witness_type A) ltac:(fun witness => let H := fresh in intro H; match goal with | |- @semax ?CS _ _ (PROPx ?P (LOCALx ?L (SEPx ?R'))) _ _ => let Frame := fresh "Frame" in evar (Frame: list mpred); let R := strip1_later R' in exploit (call_setup2_i _ _ _ _ _ _ _ _ R R' _ _ _ _ nil _ _ _ _ _ _ _ _ H witness Frame); clear H; simpl functors.MixVariantFunctor._functor; [ reflexivity | check_prove_local2ptree | Forall_pTree_from_elements | auto 50 with derives | unfold check_gvars_spec; solve [exact I | reflexivity] | try change_compspecs CS; cancel_for_forward_call | ] end) ltac:(fun _ => try refine tt; fail "Failed to infer some parts of witness") end]. *)
Ltac new_fwd_call' :=
lazymatch goal with
| |- semax _ _ (Ssequence (Scall _ _ _) _) _ =>
eapply semax_seq';
[new_prove_call_setup;
clear_Delta_specs; clear_MORE_POST;
[ .. |
lazymatch goal with
| |- _ -> semax _ _ (Scall (Some _) _ _) _ =>
forward_call_id1_wow(*
| |- call_setup2_nil _ _ _ _ _ _ _ _ _ _ _ _ ?retty _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ->
semax _ _ (Scall None _ _) _ =>*)
| |- call_setup2 _ _ _ _ _ _ _ _ _ _ _ _ _ ?retty _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ->
semax _ _ (Scall None _ _) _ =>
tryif (unify retty Tvoid)
then forward_call_id00_wow
else forward_call_id01_wow
end]
| after_forward_call ]
| |- semax _ _ (Ssequence (Ssequence (Scall (Some ?ret') _ _)
(Sset _ (Ecast (Etempvar ?ret'2 _) _))) _) _ =>
unify ret' ret'2;
eapply semax_seq';
[new_prove_call_setup;
clear_Delta_specs; clear_MORE_POST;
[ .. | forward_call_id1_x_wow ]
|  after_forward_call ]
| |- semax _ _ (Ssequence (Ssequence (Scall (Some ?ret') _ _)
(Sset _ (Etempvar ?ret'2 _))) _) _ =>
unify ret' ret'2;
eapply semax_seq';
[new_prove_call_setup;
clear_Delta_specs; clear_MORE_POST;
[ .. | forward_call_id1_y_wow ]
|  after_forward_call ]
| |- _ => rewrite <- seq_assoc; new_fwd_call'
end.
Ltac new_fwd_call:=
try lazymatch goal with
| |- semax _ _ (Scall _ _ _) _ => rewrite -> semax_seq_skip
end;
repeat lazymatch goal with
| |- semax _ _ (Ssequence (Ssequence (Ssequence _ _) _) _) _ =>
rewrite <- seq_assoc
end;
lazymatch goal with |- @semax ?CS _ ?Delta _ (Ssequence ?C _) _ =>
lazymatch C with context [Scall _ _ _] =>
new_fwd_call'
end
end.
Tactic Notation "forward_call"  := new_fwd_call.

Lemma seq_assoc2:
forall (Espec: OracleKind) {cs: compspecs}  Delta P c1 c2 c3 c4 Q,
semax Delta P (Ssequence (Ssequence c1 c2) (Ssequence c3 c4)) Q ->
semax Delta P (Ssequence (Ssequence (Ssequence c1 c2) c3) c4) Q.