1

I had a question regarding the use of VST and switch statements.

I am having trouble writing a proof that steps through the switch statement when there is a matching case for the switch variable. For example:

I CAN write a proof for something like this:

int switchTest(int x){
   switch (x){
      case(0): return 0;
      default: return 1;
   }
}

However I CANNOT write a proof for something like this:

int switchTest(){
   int x = 5;
   switch (x){
      case(0): return 0;
      case(1): return 1;
      case(5): return 5;  //The matching case for x - causes my problem
      default: return 8;
   }
}

Whenever there is a matching case for "x" (like my second code example), then I run into a "No matching clauses for match" error when trying to write a tactic for the switch statement.

Normally I could write something like: "forward_if", "forward_if True", "forward_if (PROP() LOCAL() SEP())", and they would work for my first code example, but not for my second code example.

In summary: what should the next line(s) in my proof be for the second code example?

Lemma body_switchTest: semax body Vprog Gprog f_switchTest switchTest_spec.
Proof.
start_function.
forward.
???

Thanks in advance!

Philip JF
  • 28,199
  • 5
  • 70
  • 77
R2D2
  • 11
  • 1

1 Answers1

1

This is, indeed, a bug in the VST-Floyd tactics for VST. You can patch it by doing this anywhere after Import VST.floyd.proofauto:

Ltac process_cases sign ::= 
match goal with
| |- semax _ _ (seq_of_labeled_statement 
     match select_switch_case ?N (LScons (Some ?X) ?C ?SL)
      with Some _ => _ | None => _ end) _ =>
       let y := constr:(adjust_for_sign sign X) in let y := eval compute in y in 
      rewrite (select_switch_case_signed y); 
           [ | reflexivity | clear; compute; split; congruence];
     let E := fresh "E" in let NE := fresh "NE" in 
     destruct (zeq N (Int.unsigned (Int.repr y))) as [E|NE];
      [ try ( rewrite if_true; [  | symmetry; apply E]);
        unfold seq_of_labeled_statement at 1;
        apply unsigned_eq_eq in E;
        match sign with
        | Signed => apply repr_inj_signed in E; [ | rep_lia | rep_lia]
        | Unsigned => apply repr_inj_unsigned in E; [ | rep_lia | rep_lia]
        end;
        try match type of E with ?a = _ => is_var a; subst a end;
        repeat apply -> semax_skip_seq
     | try (rewrite if_false by (contradict NE; symmetry; apply NE));
        process_cases sign
    ]
| |- semax _ _ (seq_of_labeled_statement 
     match select_switch_case ?N (LScons None ?C ?SL)
      with Some _ => _ | None => _ end) _ =>
      change (select_switch_case N (LScons None C SL))
       with (select_switch_case N SL);
        process_cases sign
| |- semax _ _ (seq_of_labeled_statement 
     match select_switch_case ?N LSnil
      with Some _ => _ | None => _ end) _ =>
      change (select_switch_case N LSnil)
           with (@None labeled_statements);
      cbv iota;
      unfold seq_of_labeled_statement at 1;
      repeat apply -> semax_skip_seq
end.
Andrew Appel
  • 453
  • 3
  • 4
  • This will be fixed in release 2.7, which you can already fetch as v2.7 from github, or the opam package for v2.7 will be coming out within a month. – Andrew Appel Dec 17 '20 at 13:59