diff --git a/docs/_static/coqdoc/bedrock.lang.cpp.logic.expr.html b/docs/_static/coqdoc/bedrock.lang.cpp.logic.expr.html index fbd7f7a8..3cd25881 100644 --- a/docs/_static/coqdoc/bedrock.lang.cpp.logic.expr.html +++ b/docs/_static/coqdoc/bedrock.lang.cpp.logic.expr.html @@ -872,23 +872,47 @@

bedrock.lang.cpp.logic.expr

            wp_operand e Q (* note: has_type v Tnullptr |-- has_type v (Tptr ty) *)
        |-- wp_operand (Ecast Cnull2ptr e Prvalue ty) Q.
+
+    (* Determine if a 0-constant of this type can be used as a pseudonym for <<nullptr>> *)
+    Definition can_represent_null (ty : type) : bool :=
+      match ty with
+      | Tnum _ _ => true
+      | _ => false
+      end.
+ +
+    (* For backwards compatiblity, the C++ semantics allows treating 0-valued integer
+       literals (of integral types) as synonymous with <<nullptr>>
+       (cf. <https://en.cppreference.com/w/cpp/language/pointerNull_pointers>). + + To make this rule compositional, we allow arbitrary integer expressions, but + note that the front-end will only use this construct if the expression is + exactly <<0>>. + *)

+    Axiom wp_operand_cast_null_int : forall e ty Q,
+        can_represent_null (type_of e) ->
+        is_ptr_type ty ->
+            (letI* v, free := wp_operand e in
+             [| v = Vint 0 |] ** Q (Vptr nullptr) free)
+        |-- wp_operand (Ecast Cnull2ptr e Prvalue ty) Q.
+
    (* note(gmm): in the clang AST, the subexpression is the call.
     * in essence, Ecast (Cuser ..) is a syntax annotation.
     *)

-    Axiom wp_init_cast_user : forall e p ty Z Q,
-        type_of e = ty ->
-            wp_init ty p e Q
-        |-- wp_init ty p (Ecast (Cuser Z) e Prvalue ty) Q.
+    Axiom wp_init_cast_user : forall e p ty Z Q,
+        type_of e = ty ->
+            wp_init ty p e Q
+        |-- wp_init ty p (Ecast (Cuser Z) e Prvalue ty) Q.

-    Axiom wp_operand_cast_user : forall e ty Z Q,
-        type_of e = ty ->
-            wp_operand e Q
-        |-- wp_operand (Ecast (Cuser Z) e Prvalue ty) Q.
+    Axiom wp_operand_cast_user : forall e ty Z Q,
+        type_of e = ty ->
+            wp_operand e Q
+        |-- wp_operand (Ecast (Cuser Z) e Prvalue ty) Q.

-    Definition UNSUPPORTED_reinterpret_cast (ty1 ty2 : type) : mpred.
+    Definition UNSUPPORTED_reinterpret_cast (ty1 ty2 : type) : mpred.
    Proof. exact False%I. Qed.

@@ -903,37 +927,37 @@

bedrock.lang.cpp.logic.expr

-    Axiom wp_operand_cast_reinterpret : forall e qt ty Q,
-        match (* source *) type_of e , (* target *) qt with
+    Axiom wp_operand_cast_reinterpret : forall e qt ty Q,
+        match (* source *) type_of e , (* target *) qt with
        | Tptr _ , Tnum _ _ =>
          (* https://eel.is/c++draft/expr.reinterpret.cast4 A pointer can be explicitly converted to any integral type large enough to hold all values of its type. The mapping function is implementation-defined. *)
-          wp_operand (Ecast Cptr2int e Prvalue ty) Q
+          wp_operand (Ecast Cptr2int e Prvalue ty) Q
        | Tnum _ _ , Tptr _ =>
          (* A value of integral type or enumeration type can be explicitly
             converted to a pointer. A pointer converted to an integer of sufficient
             size (if any such exists on the implementation) and back to the same
             pointer type will have its original value; mappings between pointers
             and integers are otherwise implementation-defined. *)

-          wp_operand (Ecast Cint2ptr e Prvalue ty) Q
+          wp_operand (Ecast Cint2ptr e Prvalue ty) Q
        | Tnullptr , Tnum _ _ =>
          (* A value of type std​::​nullptr_t can be converted to an integral type;
             the conversion has the same meaning and validity as a conversion of
             (void* )0 to the integral type.
           *)

-          wp_operand e (fun _ free => Q (Vint 0) free)
+          wp_operand e (fun _ free => Q (Vint 0) free)
        | Tptr (Tnum _ _), Tptr (Tnum W8 _) =>
          (* A narrow special case where the pointer does not change.
             This intentionally avoids the sources of struct pointers and union
             pointers because those might hit the "pointer-interconvertible"
             cases, where the pointer value might change.
           *)

-            wp_operand e Q
+            wp_operand e Q
        | ty1 , ty2 => UNSUPPORTED_reinterpret_cast ty1 ty2
        end
-        |-- wp_operand (Ecast (Creinterpret qt) e Prvalue ty) Q.
+        |-- wp_operand (Ecast (Creinterpret qt) e Prvalue ty) Q.

@@ -944,19 +968,19 @@

bedrock.lang.cpp.logic.expr

-    Axiom wp_operand_static_cast : forall c e ty Q,
-          wp_operand (Ecast c e Prvalue ty) Q
-      |-- wp_operand (Ecast (Cstatic c) e Prvalue ty) Q.
+    Axiom wp_operand_static_cast : forall c e ty Q,
+          wp_operand (Ecast c e Prvalue ty) Q
+      |-- wp_operand (Ecast (Cstatic c) e Prvalue ty) Q.

-    Axiom wp_lval_static_cast : forall c e ty Q,
-          wp_lval (Ecast c e Lvalue ty) Q
-      |-- wp_lval (Ecast (Cstatic c) e Lvalue ty) Q.
+    Axiom wp_lval_static_cast : forall c e ty Q,
+          wp_lval (Ecast c e Lvalue ty) Q
+      |-- wp_lval (Ecast (Cstatic c) e Lvalue ty) Q.

-    Axiom wp_xval_static_cast : forall c e ty Q,
-          wp_xval (Ecast c e Xvalue ty) Q
-      |-- wp_xval (Ecast (Cstatic c) e Xvalue ty) Q.
+    Axiom wp_xval_static_cast : forall c e ty Q,
+          wp_xval (Ecast c e Xvalue ty) Q
+      |-- wp_xval (Ecast (Cstatic c) e Xvalue ty) Q.

@@ -966,14 +990,14 @@

bedrock.lang.cpp.logic.expr

void can only be a pr_value
-    Axiom wp_operand_cast_tovoid : forall e Q,
-          wp_discard e (fun free => Q Vundef free)
-      |-- wp_operand (Ecast C2void e Prvalue Tvoid) Q.
+    Axiom wp_operand_cast_tovoid : forall e Q,
+          wp_discard e (fun free => Q Vundef free)
+      |-- wp_operand (Ecast C2void e Prvalue Tvoid) Q.

-    Axiom wp_operand_cast_array2ptr : forall e t Q,
-        wp_glval e (fun p => Q (Vptr p))
-        |-- wp_operand (Ecast Carray2ptr e Prvalue t) Q.
+    Axiom wp_operand_cast_array2ptr : forall e t Q,
+        wp_glval e (fun p => Q (Vptr p))
+        |-- wp_operand (Ecast Carray2ptr e Prvalue t) Q.

@@ -983,17 +1007,17 @@

bedrock.lang.cpp.logic.expr

-    Axiom wp_operand_ptr2int : forall e ty Q,
-        match drop_qualifiers (type_of e) , ty with
+    Axiom wp_operand_ptr2int : forall e ty Q,
+        match drop_qualifiers (type_of e) , ty with
        | Tptr _ , Tnum sz sgn =>
-          wp_operand e (fun v free => Exists p, [| v = Vptr p |] **
-            (Forall va, pinned_ptr va p -* Q (Vint (match sgn with
+          wp_operand e (fun v free => Exists p, [| v = Vptr p |] **
+            (Forall va, pinned_ptr va p -* Q (Vint (match sgn with
                                                    | Signed => to_signed sz
                                                    | Unsigned => trim (bitsN sz)
-                                                    end (Z.of_N va))) free))
+                                                    end (Z.of_N va))) free))
        | _ , _ => False
        end
-        |-- wp_operand (Ecast Cptr2int e Prvalue ty) Q.
+        |-- wp_operand (Ecast Cptr2int e Prvalue ty) Q.

@@ -1004,19 +1028,19 @@

bedrock.lang.cpp.logic.expr

-    Axiom wp_operand_int2ptr : forall e ty Q,
-        match unptr ty with
+    Axiom wp_operand_int2ptr : forall e ty Q,
+        match unptr ty with
        | Some ptype =>
-          wp_operand e (fun v free => Exists va : N, [| v = Vint (Z.of_N va) |] **
-             (([| (0 < va)%N |] **
-               Exists p : ptr,
-                 pinned_ptr va p **
-                 has_type (Vptr p) (Tptr ptype) **
-                 Q (Vptr p) free) \\//
-              ([| va = 0%N |] ** Q (Vptr nullptr) free)))
+          wp_operand e (fun v free => Exists va : N, [| v = Vint (Z.of_N va) |] **
+             (([| (0 < va)%N |] **
+               Exists p : ptr,
+                 pinned_ptr va p **
+                 has_type (Vptr p) (Tptr ptype) **
+                 Q (Vptr p) free) \\//
+              ([| va = 0%N |] ** Q (Vptr nullptr) free)))
        | _ => False
        end
-        |-- wp_operand (Ecast Cint2ptr e Prvalue ty) Q.
+        |-- wp_operand (Ecast Cint2ptr e Prvalue ty) Q.

@@ -1046,72 +1070,72 @@

bedrock.lang.cpp.logic.expr

-    Axiom wp_lval_cast_derived2base : forall e ty path Q,
-      match drop_qualifiers (type_of e), drop_qualifiers ty with
+    Axiom wp_lval_cast_derived2base : forall e ty path Q,
+      match drop_qualifiers (type_of e), drop_qualifiers ty with
      | Tnamed derived , Tnamed base =>
-          wp_glval e (fun addr free =>
-            let addr' := addr ,, derived_to_base derived path in
-            reference_to ty addr' ** Q addr' free)
+          wp_glval e (fun addr free =>
+            let addr' := addr ,, derived_to_base derived path in
+            reference_to ty addr' ** Q addr' free)
      | _, _ => False
      end
-      |-- wp_lval (Ecast (Cderived2base path) e Lvalue ty) Q.
+      |-- wp_lval (Ecast (Cderived2base path) e Lvalue ty) Q.

-    Axiom wp_xval_cast_derived2base : forall e ty path Q,
-      match drop_qualifiers (type_of e), drop_qualifiers ty with
+    Axiom wp_xval_cast_derived2base : forall e ty path Q,
+      match drop_qualifiers (type_of e), drop_qualifiers ty with
      | Tnamed derived , Tnamed base =>
-          wp_glval e (fun addr free =>
-            let addr' := addr ,, derived_to_base derived path in
-            reference_to ty addr' ** Q addr' free)
+          wp_glval e (fun addr free =>
+            let addr' := addr ,, derived_to_base derived path in
+            reference_to ty addr' ** Q addr' free)
      | _, _ => False
      end
-      |-- wp_xval (Ecast (Cderived2base path) e Xvalue ty) Q.
+      |-- wp_xval (Ecast (Cderived2base path) e Xvalue ty) Q.

-    Axiom wp_operand_cast_derived2base : forall e ty path Q,
-      match drop_qualifiers <$> unptr (type_of e), drop_qualifiers <$> unptr ty with
+    Axiom wp_operand_cast_derived2base : forall e ty path Q,
+      match drop_qualifiers <$> unptr (type_of e), drop_qualifiers <$> unptr ty with
      | Some (Tnamed derived) , Some (Tnamed base) =>
-          wp_operand e (fun addr free =>
-            let addr' := _eqv addr ,, derived_to_base derived path in
-            has_type (Vptr addr') ty ** Q (Vptr addr') free)
+          wp_operand e (fun addr free =>
+            let addr' := _eqv addr ,, derived_to_base derived path in
+            has_type (Vptr addr') ty ** Q (Vptr addr') free)
      | _, _ => False
      end
-      |-- wp_operand (Ecast (Cderived2base path) e Prvalue ty) Q.
+      |-- wp_operand (Ecast (Cderived2base path) e Prvalue ty) Q.

    (* Cbase2derived casts from a base class to a derived class.
     *)

-    Axiom wp_lval_cast_base2derived : forall e ty path Q,
-      match drop_qualifiers (type_of e), drop_qualifiers ty with
+    Axiom wp_lval_cast_base2derived : forall e ty path Q,
+      match drop_qualifiers (type_of e), drop_qualifiers ty with
      | Tnamed base , Tnamed derived =>
-          wp_glval e (fun addr free =>
-            let addr' := addr ,, base_to_derived derived path in
-            reference_to ty addr' ** Q addr' free)
+          wp_glval e (fun addr free =>
+            let addr' := addr ,, base_to_derived derived path in
+            reference_to ty addr' ** Q addr' free)
      | _, _ => False
      end
-      |-- wp_lval (Ecast (Cbase2derived path) e Lvalue ty) Q.
+      |-- wp_lval (Ecast (Cbase2derived path) e Lvalue ty) Q.

-    Axiom wp_xval_cast_base2derived : forall e ty path Q,
-      match drop_qualifiers (type_of e), drop_qualifiers ty with
+    Axiom wp_xval_cast_base2derived : forall e ty path Q,
+      match drop_qualifiers (type_of e), drop_qualifiers ty with
      | Tnamed base , Tnamed derived =>
-          wp_glval e (fun addr free =>
-            let addr' := addr ,, base_to_derived derived path in
-            reference_to ty addr' ** Q addr' free)
+          wp_glval e (fun addr free =>
+            let addr' := addr ,, base_to_derived derived path in
+            reference_to ty addr' ** Q addr' free)
      | _, _ => False
      end
-      |-- wp_xval (Ecast (Cbase2derived path) e Xvalue ty) Q.
+      |-- wp_xval (Ecast (Cbase2derived path) e Xvalue ty) Q.

-    Axiom wp_operand_cast_base2derived : forall e ty path Q,
-         match drop_qualifiers <$> unptr (type_of e), drop_qualifiers <$> unptr ty with
+    Axiom wp_operand_cast_base2derived : forall e ty path Q,
+         match drop_qualifiers <$> unptr (type_of e), drop_qualifiers <$> unptr ty with
         | Some (Tnamed base), Some (Tnamed derived) =>
-          wp_operand e (fun addr free =>
-            let addr' := _eqv addr ,, base_to_derived derived path in
-            has_type (Vptr addr') ty ** Q (Vptr addr') free)
+          wp_operand e (fun addr free =>
+            let addr' := _eqv addr ,, base_to_derived derived path in
+            has_type (Vptr addr') ty ** Q (Vptr addr') free)
         | _, _ => False
        end
-      |-- wp_operand (Ecast (Cbase2derived path) e Prvalue ty) Q.
+      |-- wp_operand (Ecast (Cbase2derived path) e Prvalue ty) Q.

@@ -1127,13 +1151,13 @@

bedrock.lang.cpp.logic.expr

-    Definition wp_cond {T} (vc : ValCat) (wp : Expr -> (T -> FreeTemps.t -> epred) -> mpred) : Prop :=
-      forall ty tst th el (Q : T -> FreeTemps -> mpred),
-        Unfold WPE.wp_test (wp_test tst (fun c free =>
-           if c
-           then wp th (fun v free' => Q v (free' >*> free))
-           else wp el (fun v free' => Q v (free' >*> free))))
-        |-- wp (Eif tst th el vc ty) Q.
+    Definition wp_cond {T} (vc : ValCat) (wp : Expr -> (T -> FreeTemps.t -> epred) -> mpred) : Prop :=
+      forall ty tst th el (Q : T -> FreeTemps -> mpred),
+        Unfold WPE.wp_test (wp_test tst (fun c free =>
+           if c
+           then wp th (fun v free' => Q v (free' >*> free))
+           else wp el (fun v free' => Q v (free' >*> free))))
+        |-- wp (Eif tst th el vc ty) Q.

    Axiom wp_lval_condition : Reduce (wp_cond Lvalue wp_lval).
@@ -1141,18 +1165,18 @@

bedrock.lang.cpp.logic.expr

    Axiom wp_operand_condition : Reduce (wp_cond Prvalue wp_operand).

-    Axiom wp_init_condition : forall ty addr tst th el Q,
-        Unfold WPE.wp_test (wp_test tst (fun c free =>
-           if c
-           then wp_init ty addr th (fun frees => Q (frees >*> free))
-           else wp_init ty addr el (fun frees => Q (frees >*> free))))
-        |-- wp_init ty addr (Eif tst th el Prvalue ty) Q.
+    Axiom wp_init_condition : forall ty addr tst th el Q,
+        Unfold WPE.wp_test (wp_test tst (fun c free =>
+           if c
+           then wp_init ty addr th (fun frees => Q (frees >*> free))
+           else wp_init ty addr el (fun frees => Q (frees >*> free))))
+        |-- wp_init ty addr (Eif tst th el Prvalue ty) Q.

-    Axiom wp_operand_implicit : forall e Q,
-        wp_operand e Q |-- wp_operand (Eimplicit e) Q.
-    Axiom wp_init_implicit : forall ty e p Q,
-        wp_init ty p e Q |-- wp_init ty p (Eimplicit e) Q.
+    Axiom wp_operand_implicit : forall e Q,
+        wp_operand e Q |-- wp_operand (Eimplicit e) Q.
+    Axiom wp_init_implicit : forall ty e p Q,
+        wp_init ty p e Q |-- wp_init ty p (Eimplicit e) Q.

@@ -1161,8 +1185,8 @@

bedrock.lang.cpp.logic.expr

Gets the type used in an expression like `sizeof` and `alignof`
-    Definition get_type (ety : type + Expr) : type :=
-      match ety with
+    Definition get_type (ety : type + Expr) : type :=
+      match ety with
      | inl ty => ty
      | inr e => type_of e
      end.
@@ -1189,12 +1213,12 @@

bedrock.lang.cpp.logic.expr

-    Axiom wp_operand_sizeof : forall ety ty Q,
-        Exists sz,
-          [| size_of (drop_reference $ get_type ety) = Some sz |] **
-          [| has_type_prop sz Tsize_t |] **
-          Q (Vn sz) FreeTemps.id
-        |-- wp_operand (Esizeof ety ty) Q.
+    Axiom wp_operand_sizeof : forall ety ty Q,
+        Exists sz,
+          [| size_of (drop_reference $ get_type ety) = Some sz |] **
+          [| has_type_prop sz Tsize_t |] **
+          Q (Vn sz) FreeTemps.id
+        |-- wp_operand (Esizeof ety ty) Q.

@@ -1210,12 +1234,12 @@

bedrock.lang.cpp.logic.expr

-    Axiom wp_operand_alignof : forall ety ty Q,
-        Exists align,
-          [| align_of (drop_reference $ get_type ety) = Some align |] **
-          [| has_type_prop align Tsize_t |] **
-          Q (Vn align) FreeTemps.id
-        |-- wp_operand (Ealignof ety ty) Q.
+    Axiom wp_operand_alignof : forall ety ty Q,
+        Exists align,
+          [| align_of (drop_reference $ get_type ety) = Some align |] **
+          [| has_type_prop align Tsize_t |] **
+          Q (Vn align) FreeTemps.id
+        |-- wp_operand (Ealignof ety ty) Q.

@@ -1255,18 +1279,18 @@

bedrock.lang.cpp.logic.expr

-    Definition wp_call (ooe : evaluation_order.t) (pfty : type) (f : Expr) (es : list Expr)
-      (Q : ptr -> FreeTemps -> epred) : mpred :=
-      match unptr pfty with
+    Definition wp_call (ooe : evaluation_order.t) (pfty : type) (f : Expr) (es : list Expr)
+      (Q : ptr -> FreeTemps -> epred) : mpred :=
+      match unptr pfty with
      | Some fty =>
-        let fty := normalize_type fty in
-        match arg_types fty with
+        let fty := normalize_type fty in
+        match arg_types fty with
        | Some targs =>
-            let eval_f Q := wp_operand f (fun v fr => Exists fp, [| v = Vptr fp |] ** Q fp fr) in
-            letI* fps, vs, ifree, free := wp_args ooe [eval_f] targs es in
-            match fps with
-            | [fp] => |> wp_fptr fty fp vs (fun v => interp ifree $ Q v free)
-            | _ => UNREACHABLE ("wp_args did not return a singleton list for pre", fps)
+            let eval_f Q := wp_operand f (fun v fr => Exists fp, [| v = Vptr fp |] ** Q fp fr) in
+            letI* fps, vs, ifree, free := wp_args ooe [eval_f] targs es in
+            match fps with
+            | [fp] => |> wp_fptr fty fp vs (fun v => interp ifree $ Q v free)
+            | _ => UNREACHABLE ("wp_args did not return a singleton list for pre", fps)
            end
        | _ => False
        end
@@ -1274,8 +1298,8 @@

bedrock.lang.cpp.logic.expr

      end.

-    Lemma wp_call_frame eo pfty f es Q Q' :
-      Forall ps free, Q ps free -* Q' ps free |-- wp_call eo pfty f es Q -* wp_call eo pfty f es Q'.
+    Lemma wp_call_frame eo pfty f es Q Q' :
+      Forall ps free, Q ps free -* Q' ps free |-- wp_call eo pfty f es Q -* wp_call eo pfty f es Q'.
    Proof.
      rewrite /wp_call.
      case_match; eauto.
@@ -1294,28 +1318,28 @@

bedrock.lang.cpp.logic.expr

    Qed.

-    Axiom wp_lval_call : forall f (es : list Expr) Q (ty : type),
-        wp_call (evaluation_order.order_of OOCall) (type_of f) f es (fun res free =>
-           Reduce (lval_receive ty res $ fun v => Q v free))
-        |-- wp_lval (Ecall f es ty) Q.
+    Axiom wp_lval_call : forall f (es : list Expr) Q (ty : type),
+        wp_call (evaluation_order.order_of OOCall) (type_of f) f es (fun res free =>
+           Reduce (lval_receive ty res $ fun v => Q v free))
+        |-- wp_lval (Ecall f es ty) Q.

-    Axiom wp_xval_call : forall f (es : list Expr) Q (ty : type),
-        wp_call (evaluation_order.order_of OOCall) (type_of f) f es (fun res free =>
-           Reduce (xval_receive ty res $ fun v => Q v free))
-        |-- wp_xval (Ecall f es ty) Q.
+    Axiom wp_xval_call : forall f (es : list Expr) Q (ty : type),
+        wp_call (evaluation_order.order_of OOCall) (type_of f) f es (fun res free =>
+           Reduce (xval_receive ty res $ fun v => Q v free))
+        |-- wp_xval (Ecall f es ty) Q.

-    Axiom wp_operand_call : forall ty f es Q,
-        wp_call (evaluation_order.order_of OOCall) (type_of f) f es (fun res free =>
-           operand_receive ty res $ fun v => Q v free)
-       |-- wp_operand (Ecall f es ty) Q.
+    Axiom wp_operand_call : forall ty f es Q,
+        wp_call (evaluation_order.order_of OOCall) (type_of f) f es (fun res free =>
+           operand_receive ty res $ fun v => Q v free)
+       |-- wp_operand (Ecall f es ty) Q.

-    Axiom wp_init_call : forall f es Q (addr : ptr) ty,
-        (letI* res, free := wp_call (evaluation_order.order_of OOCall) (type_of f) f es in
-             Reduce (init_receive addr res $ Q free))
-      |-- wp_init ty addr (Ecall f es ty) Q.
+    Axiom wp_init_call : forall f es Q (addr : ptr) ty,
+        (letI* res, free := wp_call (evaluation_order.order_of OOCall) (type_of f) f es in
+             Reduce (init_receive addr res $ Q free))
+      |-- wp_init ty addr (Ecall f es ty) Q.

@@ -1339,26 +1363,26 @@

bedrock.lang.cpp.logic.expr

-    Definition dispatch (ct : dispatch_type) (fty : functype) (fn : obj_name) (this_type : type)
-      (obj : ptr) (args : list ptr) (Q : ptr -> epred) : mpred :=
-      let fty := normalize_type fty in
-      match ct with
+    Definition dispatch (ct : dispatch_type) (fty : functype) (fn : obj_name) (this_type : type)
+      (obj : ptr) (args : list ptr) (Q : ptr -> epred) : mpred :=
+      let fty := normalize_type fty in
+      match ct with
      | Virtual =>
-          match decompose_type this_type with
+          match decompose_type this_type with
          | (tq, Tnamed cls) =>
-              letI* fimpl_addr, impl_class, thisp := resolve_virtual obj cls fn in
-              let this_type := tqualified tq (Tnamed impl_class) in
-              |> mspec this_type fty fimpl_addr (thisp :: args) Q
+              letI* fimpl_addr, impl_class, thisp := resolve_virtual obj cls fn in
+              let this_type := tqualified tq (Tnamed impl_class) in
+              |> mspec this_type fty fimpl_addr (thisp :: args) Q
          | _ => False
          end
-      | Direct => |> mspec this_type fty (_global fn) (obj :: args) Q
+      | Direct => |> mspec this_type fty (_global fn) (obj :: args) Q
      end.

-    Lemma dispatch_frame ct fty fn this_type obj args Q Q' :
-      (Forall p, Q p -* Q' p)
-      |-- dispatch ct fty fn this_type obj args Q -*
-          dispatch ct fty fn this_type obj args Q'.
+    Lemma dispatch_frame ct fty fn this_type obj args Q Q' :
+      (Forall p, Q p -* Q' p)
+      |-- dispatch ct fty fn this_type obj args Q -*
+          dispatch ct fty fn this_type obj args Q'.
    Proof.
      rewrite /dispatch.
      iIntros "Q".
@@ -1387,25 +1411,25 @@

bedrock.lang.cpp.logic.expr


-    Definition wp_mcall (invoke : ptr -> list ptr -> (ptr -> epred) -> mpred)
-      ooe (obj : Expr) (fty : functype) (es : list Expr)
-      (Q : ptr -> FreeTemps -> epred) : mpred :=
-      let fty := normalize_type fty in
-      match arg_types fty with
+    Definition wp_mcall (invoke : ptr -> list ptr -> (ptr -> epred) -> mpred)
+      ooe (obj : Expr) (fty : functype) (es : list Expr)
+      (Q : ptr -> FreeTemps -> epred) : mpred :=
+      let fty := normalize_type fty in
+      match arg_types fty with
      | Some targs =>
-        letI* this, args, ifree, free := wp_args ooe [wp_glval obj] targs es in
-        match this with
-        | [this] => invoke this args (fun v => interp ifree $ Q v free)
+        letI* this, args, ifree, free := wp_args ooe [wp_glval obj] targs es in
+        match this with
+        | [this] => invoke this args (fun v => interp ifree $ Q v free)
        | _ => False
        end
      | _ => False
      end.

-    Lemma wp_mcall_frame f this this_type fty es Q Q' :
-      Forall p free, Q p free -* Q' p free
-      |-- (Forall p ps Q Q', (Forall p, Q p -* Q' p) -* f p ps Q -* f p ps Q') -*
-          wp_mcall f this this_type fty es Q -* wp_mcall f this this_type fty es Q'.
+    Lemma wp_mcall_frame f this this_type fty es Q Q' :
+      Forall p free, Q p free -* Q' p free
+      |-- (Forall p ps Q Q', (Forall p, Q p -* Q' p) -* f p ps Q -* f p ps Q') -*
+          wp_mcall f this this_type fty es Q -* wp_mcall f this this_type fty es Q'.
    Proof.
      rewrite /wp_mcall.
      case_match; eauto.
@@ -1420,28 +1444,28 @@

bedrock.lang.cpp.logic.expr

    Qed.

-    Axiom wp_lval_member_call : forall ct ty fty f obj es Q,
-        wp_mcall (dispatch ct fty f (type_of obj)) (evaluation_order.order_of OOCall) obj fty es (fun res free =>
-           lval_receive ty res $ fun v => Q v free)
-        |-- wp_lval (Emember_call (inl (f, ct, fty)) obj es ty) Q.
+    Axiom wp_lval_member_call : forall ct ty fty f obj es Q,
+        wp_mcall (dispatch ct fty f (type_of obj)) (evaluation_order.order_of OOCall) obj fty es (fun res free =>
+           lval_receive ty res $ fun v => Q v free)
+        |-- wp_lval (Emember_call (inl (f, ct, fty)) obj es ty) Q.

-    Axiom wp_xval_member_call : forall ct ty fty f obj es Q,
-        wp_mcall (dispatch ct fty f (type_of obj)) (evaluation_order.order_of OOCall) obj fty es (fun res free =>
-           xval_receive ty res $ fun v => Q v free)
-        |-- wp_xval (Emember_call (inl (f, ct, fty)) obj es ty) Q.
+    Axiom wp_xval_member_call : forall ct ty fty f obj es Q,
+        wp_mcall (dispatch ct fty f (type_of obj)) (evaluation_order.order_of OOCall) obj fty es (fun res free =>
+           xval_receive ty res $ fun v => Q v free)
+        |-- wp_xval (Emember_call (inl (f, ct, fty)) obj es ty) Q.

-    Axiom wp_operand_member_call : forall ct ty fty f obj es Q,
-        wp_mcall (dispatch ct fty f (type_of obj)) (evaluation_order.order_of OOCall) obj fty es (fun res free =>
-           operand_receive ty res $ fun v => Q v free)
-        |-- wp_operand (Emember_call (inl (f, ct, fty)) obj es ty) Q.
+    Axiom wp_operand_member_call : forall ct ty fty f obj es Q,
+        wp_mcall (dispatch ct fty f (type_of obj)) (evaluation_order.order_of OOCall) obj fty es (fun res free =>
+           operand_receive ty res $ fun v => Q v free)
+        |-- wp_operand (Emember_call (inl (f, ct, fty)) obj es ty) Q.

-    Axiom wp_init_member_call : forall ct f fty es (addr : ptr) ty obj Q,
-        (letI* res, free := wp_mcall (dispatch ct fty f (type_of obj)) (evaluation_order.order_of OOCall) obj fty es in
-           init_receive addr res $ Q free)
-        |-- wp_init ty addr (Emember_call (inl (f, ct, fty)) obj es ty) Q.
+    Axiom wp_init_member_call : forall ct f fty es (addr : ptr) ty obj Q,
+        (letI* res, free := wp_mcall (dispatch ct fty f (type_of obj)) (evaluation_order.order_of OOCall) obj fty es in
+           init_receive addr res $ Q free)
+        |-- wp_init ty addr (Emember_call (inl (f, ct, fty)) obj es ty) Q.

@@ -1455,20 +1479,20 @@

bedrock.lang.cpp.logic.expr

-    Definition wp_operator_call oo oi es Q :=
-      match oi with
+    Definition wp_operator_call oo oi es Q :=
+      match oi with
      | operator_impl.Func f fty =>
-          let fty := normalize_type fty in
-          match arg_types fty with
+          let fty := normalize_type fty in
+          match arg_types fty with
          | Some targs =>
-            letI* fps, vs, ifree, free := wp_args (evaluation_order.order_of oo) [] targs es in
-            |> wp_fptr fty (_global f) vs (fun v => interp ifree $ Q v free)
+            letI* fps, vs, ifree, free := wp_args (evaluation_order.order_of oo) [] targs es in
+            |> wp_fptr fty (_global f) vs (fun v => interp ifree $ Q v free)
          | None => False
          end
       | operator_impl.MFunc fn ct fty =>
-           match es with
+           match es with
           | eobj :: es =>
-               wp_mcall (dispatch ct fty fn (type_of eobj)) (evaluation_order.order_of oo) eobj fty es Q
+               wp_mcall (dispatch ct fty fn (type_of eobj)) (evaluation_order.order_of oo) eobj fty es Q
           | _ => False
           end
      end%I.
@@ -1477,28 +1501,28 @@

bedrock.lang.cpp.logic.expr

    (* TODO: prove wp_operator_call_frame *)

-    Axiom wp_operand_operator_call : forall oo oi es ty Q,
-        (letI* res, free := wp_operator_call oo oi es in
-         operand_receive ty res $ fun v => Q v free)
-     |-- wp_operand (Eoperator_call oo oi es ty) Q.
-    Axiom wp_lval_operator_call : forall oo oi es ty Q,
-        (letI* res, free := wp_operator_call oo oi es in
-         lval_receive ty res $ fun v => Q v free)
-     |-- wp_lval (Eoperator_call oo oi es ty) Q.
-    Axiom wp_xval_operator_call : forall oo oi es ty Q,
-        (letI* res, free := wp_operator_call oo oi es in
-         xval_receive ty res $ fun v => Q v free)
-     |-- wp_xval (Eoperator_call oo oi es ty) Q.
-    Axiom wp_init_operator_call : forall addr oo oi es ty Q,
-        (letI* res, free := wp_operator_call oo oi es in
-         init_receive addr res $ Q free)
-     |-- wp_init ty addr (Eoperator_call oo oi es ty) Q.
+    Axiom wp_operand_operator_call : forall oo oi es ty Q,
+        (letI* res, free := wp_operator_call oo oi es in
+         operand_receive ty res $ fun v => Q v free)
+     |-- wp_operand (Eoperator_call oo oi es ty) Q.
+    Axiom wp_lval_operator_call : forall oo oi es ty Q,
+        (letI* res, free := wp_operator_call oo oi es in
+         lval_receive ty res $ fun v => Q v free)
+     |-- wp_lval (Eoperator_call oo oi es ty) Q.
+    Axiom wp_xval_operator_call : forall oo oi es ty Q,
+        (letI* res, free := wp_operator_call oo oi es in
+         xval_receive ty res $ fun v => Q v free)
+     |-- wp_xval (Eoperator_call oo oi es ty) Q.
+    Axiom wp_init_operator_call : forall addr oo oi es ty Q,
+        (letI* res, free := wp_operator_call oo oi es in
+         init_receive addr res $ Q free)
+     |-- wp_init ty addr (Eoperator_call oo oi es ty) Q.

    (* null *)
-    Axiom wp_null : forall Q,
-      Q (Vptr nullptr) FreeTemps.id
-      |-- wp_operand Enull Q.
+    Axiom wp_null : forall Q,
+      Q (Vptr nullptr) FreeTemps.id
+      |-- wp_operand Enull Q.

@@ -1514,10 +1538,10 @@

bedrock.lang.cpp.logic.expr

the destructor would potentially do.
-    Axiom end_provides_storage : forall storage_ptr obj_ptr aty sz,
-       size_of aty = Some sz ->
-       provides_storage storage_ptr obj_ptr aty ** obj_ptr |-> anyR aty (cQp.mut 1)
-         ={}=∗ (storage_ptr |-> blockR sz (cQp.m 1)).
+    Axiom end_provides_storage : forall storage_ptr obj_ptr aty sz,
+       size_of aty = Some sz ->
+       provides_storage storage_ptr obj_ptr aty ** obj_ptr |-> anyR aty (cQp.mut 1)
+         ={}=∗ (storage_ptr |-> blockR sz (cQp.m 1)).

@@ -1541,18 +1565,18 @@

bedrock.lang.cpp.logic.expr

       so these nodes should effectively be no-ops, though there are certain
       places in the AST that has odd evaluation semantics
     *)
-    Axiom wp_lval_clean : forall e Q,
-          wp_lval e (fun p frees => interp frees $ Q p FreeTemps.id)
-      |-- wp_lval (Eandclean e) Q.
-    Axiom wp_xval_clean : forall e Q,
-          wp_xval e (fun p frees => interp frees $ Q p FreeTemps.id)
-      |-- wp_xval (Eandclean e) Q.
-    Axiom wp_operand_clean : forall e Q,
-          wp_operand e (fun v frees => interp frees $ Q v FreeTemps.id)
-      |-- wp_operand (Eandclean e) Q.
-    Axiom wp_init_clean : forall ty e addr Q,
-          wp_init ty addr e (fun frees => interp frees $ Q FreeTemps.id)
-      |-- wp_init ty addr (Eandclean e) Q.
+    Axiom wp_lval_clean : forall e Q,
+          wp_lval e (fun p frees => interp frees $ Q p FreeTemps.id)
+      |-- wp_lval (Eandclean e) Q.
+    Axiom wp_xval_clean : forall e Q,
+          wp_xval e (fun p frees => interp frees $ Q p FreeTemps.id)
+      |-- wp_xval (Eandclean e) Q.
+    Axiom wp_operand_clean : forall e Q,
+          wp_operand e (fun v frees => interp frees $ Q v FreeTemps.id)
+      |-- wp_operand (Eandclean e) Q.
+    Axiom wp_init_clean : forall ty e addr Q,
+          wp_init ty addr e (fun frees => interp frees $ Q FreeTemps.id)
+      |-- wp_init ty addr (Eandclean e) Q.

@@ -1563,18 +1587,18 @@

bedrock.lang.cpp.logic.expr

-    Axiom wp_xval_temp : forall e Q,
-        (let ty := type_of e in
-         Forall a : ptr,
-         wp_initialize ty a e (fun frees => Q a (FreeTemps.delete ty a >*> frees)))
-        |-- wp_xval (Ematerialize_temp e Xvalue) Q.
+    Axiom wp_xval_temp : forall e Q,
+        (let ty := type_of e in
+         Forall a : ptr,
+         wp_initialize ty a e (fun frees => Q a (FreeTemps.delete ty a >*> frees)))
+        |-- wp_xval (Ematerialize_temp e Xvalue) Q.

-    Axiom wp_lval_temp : forall e Q,
-        (let ty := type_of e in
-         Forall a : ptr,
-         wp_initialize ty a e (fun frees => Q a (FreeTemps.delete ty a >*> frees)))
-        |-- wp_lval (Ematerialize_temp e Lvalue) Q.
+    Axiom wp_lval_temp : forall e Q,
+        (let ty := type_of e in
+         Forall a : ptr,
+         wp_initialize ty a e (fun frees => Q a (FreeTemps.delete ty a >*> frees)))
+        |-- wp_lval (Ematerialize_temp e Lvalue) Q.

@@ -1626,14 +1650,14 @@

bedrock.lang.cpp.logic.expr

-    Axiom wp_operand_pseudo_destructor : forall e ty Q,
-        (letI* v, free := wp_glval e in
-         v |-> anyR ty (cQp.mut 1) ** (v |-> tblockR ty (cQp.mut 1) -* Q Vvoid free))
-        |-- wp_operand (Epseudo_destructor false ty e) Q.
-    Axiom wp_operand_pseudo_destructor_arrow : forall e ty ety (_ : (unptr $ type_of e) = Some ety) Q,
-        (letI* v, free := wp_glval (Ederef e ety) in
-         v |-> anyR ty (cQp.mut 1) ** (v |-> tblockR ty (cQp.mut 1) -* Q Vvoid free))
-        |-- wp_operand (Epseudo_destructor true ty e) Q.
+    Axiom wp_operand_pseudo_destructor : forall e ty Q,
+        (letI* v, free := wp_glval e in
+         v |-> anyR ty (cQp.mut 1) ** (v |-> tblockR ty (cQp.mut 1) -* Q Vvoid free))
+        |-- wp_operand (Epseudo_destructor false ty e) Q.
+    Axiom wp_operand_pseudo_destructor_arrow : forall e ty ety (_ : (unptr $ type_of e) = Some ety) Q,
+        (letI* v, free := wp_glval (Ederef e ety) in
+         v |-> anyR ty (cQp.mut 1) ** (v |-> tblockR ty (cQp.mut 1) -* Q Vvoid free))
+        |-- wp_operand (Epseudo_destructor true ty e) Q.

    (* Eimplicit_init nodes reflect implicit /value initializations/ which are inserted
@@ -1648,8 +1672,8 @@

bedrock.lang.cpp.logic.expr

     *)


-    Definition zero_init_val (ty : type) : option val :=
-      match representation_type tu ty with
+    Definition zero_init_val (ty : type) : option val :=
+      match representation_type tu ty with
      | Tnullptr | Tptr _ => Some $ Vptr nullptr
      (* | Tmember_pointer _ _ *)
      | Tchar_ _ => Some $ Vchar 0
@@ -1659,14 +1683,14 @@

bedrock.lang.cpp.logic.expr

      end.

-    Lemma zero_init_val_is_scalar ty v : zero_init_val ty = Some v -> scalar_type ty = true.
+    Lemma zero_init_val_is_scalar ty v : zero_init_val ty = Some v -> scalar_type ty = true.
    Proof.
      rewrite /zero_init_val/scalar_type/representation_type /=. destruct (drop_qualifiers ty) eqn:Hdrop => //; eauto.
    Qed.

-    Lemma well_typed_zero_init_val (MOD : tu resolve) : forall ty v,
-        zero_init_val ty = Some v -> has_type_prop v ty.
+    Lemma well_typed_zero_init_val (MOD : tu resolve) : forall ty v,
+        zero_init_val ty = Some v -> has_type_prop v ty.
    Proof.
      rewrite /zero_init_val/representation_type. intros.
      eapply has_type_prop_drop_qualifiers; revert H.
@@ -1691,19 +1715,19 @@

bedrock.lang.cpp.logic.expr

    Qed.

-    Lemma zero_init_val_erase_drop ty :
-      zero_init_val (erase_qualifiers ty) = zero_init_val (drop_qualifiers ty).
+    Lemma zero_init_val_erase_drop ty :
+      zero_init_val (erase_qualifiers ty) = zero_init_val (drop_qualifiers ty).
    Proof. by induction ty. Qed.

-    Axiom wp_operand_implicit_init : forall ty v Q,
-          zero_init_val ty = Some v ->
-          Q v FreeTemps.id
-      |-- wp_operand (Eimplicit_init ty) Q.
+    Axiom wp_operand_implicit_init : forall ty v Q,
+          zero_init_val ty = Some v ->
+          Q v FreeTemps.id
+      |-- wp_operand (Eimplicit_init ty) Q.

-    Definition marg_types (t : functype) : option (list type * function_arity) :=
-      match t with
+    Definition marg_types (t : functype) : option (list type * function_arity) :=
+      match t with
      | @Tfunction cc ar _ (_ :: args) =>
          (* we drop the first argument which is for this *)
          Some (args, ar)
@@ -1711,45 +1735,45 @@

bedrock.lang.cpp.logic.expr

      end.

-    Definition type_of_ctor tu obj : option type :=
-      match tu.(symbols) !! obj with
+    Definition type_of_ctor tu obj : option type :=
+      match tu.(symbols) !! obj with
      | Some (Oconstructor ctor as v) => Some (type_of_value v)
      | _ => None
      end.

-    Axiom wp_init_constructor : forall cls ty cv (this : ptr) cnd es Q,
-      decompose_type ty = (cv, Tnamed cls) ->
+    Axiom wp_init_constructor : forall cls ty cv (this : ptr) cnd es Q,
+      decompose_type ty = (cv, Tnamed cls) ->
        (* NOTE because the AST does not include the types of the arguments of
           the constructor, we have to look up the type in the environment.
         *)

-           match type_of_ctor tu cnd with
+           match type_of_ctor tu cnd with
           | Some ctor_type =>
             match marg_types ctor_type with
             | Some arg_types =>
-                letI* _, argps, ifree, free := wp_args evaluation_order.nd nil arg_types es in
-                |> (this |-> tblockR (Tnamed cls) (cQp.mut 1) -*
+                letI* _, argps, ifree, free := wp_args evaluation_order.nd nil arg_types es in
+                |> (this |-> tblockR (Tnamed cls) (cQp.mut 1) -*
                   (* ^^ The semantics currently has constructors take ownership of a tblockR *)
-                   letI* resultp := wp_fptr ctor_type (_global cnd) (this :: argps) in
-                   letI* := interp ifree in
+                   letI* resultp := wp_fptr ctor_type (_global cnd) (this :: argps) in
+                   letI* := interp ifree in
                    (* in the semantics, constructors return void *)
-                    resultp |-> primR Tvoid (cQp.mut 1) Vvoid **
-                    let Q := Q free in
-                    if q_const cv
-                    then wp_make_const tu this (Tnamed cls) Q
-                    else Q)
+                    resultp |-> primR Tvoid (cQp.mut 1) Vvoid **
+                    let Q := Q free in
+                    if q_const cv
+                    then wp_make_const tu this (Tnamed cls) Q
+                    else Q)
             | _ => False (* unreachable b/c we got a constructor *)
             end
-           | _ => ERROR ("Constructor not found.", cnd)
+           | _ => ERROR ("Constructor not found.", cnd)
           end
-      |-- wp_init ty this (Econstructor cnd es ty) Q.
+      |-- wp_init ty this (Econstructor cnd es ty) Q.

-    Fixpoint wp_array_init (ety : type) (base : ptr) (es : list Expr) (idx : Z)
-      (Q : FreeTemps -> mpred) : mpred :=
-      match es with
+    Fixpoint wp_array_init (ety : type) (base : ptr) (es : list Expr) (idx : Z)
+      (Q : FreeTemps -> mpred) : mpred :=
+      match es with
      | nil =>
-        Q FreeTemps.id
+        Q FreeTemps.id
      | e :: rest =>
          (* NOTE: We nest the recursive calls to `wp_array_init` within
               the continuation of the `wp_initialize` statement to
@@ -1757,15 +1781,15 @@

bedrock.lang.cpp.logic.expr

               sequence-points between all of the elements of an
               initializer list (c.f. http://eel.is/c++draft/dcl.init.list4) *)

-         letI* free := wp_initialize ety (base .[ erase_qualifiers ety ! idx ]) e in
-         interp free $ wp_array_init ety base rest (Z.succ idx) Q
+         letI* free := wp_initialize ety (base .[ erase_qualifiers ety ! idx ]) e in
+         interp free $ wp_array_init ety base rest (Z.succ idx) Q
      end.

-    Lemma wp_array_init_frame ety base : forall es ix Q Q',
-      (Forall f, Q f -* Q' f)
-      |-- wp_array_init ety base es ix Q -*
-          wp_array_init ety base es ix Q'.
+    Lemma wp_array_init_frame ety base : forall es ix Q Q',
+      (Forall f, Q f -* Q' f)
+      |-- wp_array_init ety base es ix Q -*
+          wp_array_init ety base es ix Q'.
    Proof.
      induction es; simpl; intros; iIntros "X".
      { iIntros "A"; iApply "X"; iApply "A"; done. }
@@ -1774,9 +1798,9 @@

bedrock.lang.cpp.logic.expr

    Qed.

-    Definition fill_initlist (desiredsz : N) (es : list Expr) (f : Expr) : list Expr :=
-      let actualsz := N.of_nat (length es) in
-      es ++ replicateN (desiredsz - actualsz) f.
+    Definition fill_initlist (desiredsz : N) (es : list Expr) (f : Expr) : list Expr :=
+      let actualsz := N.of_nat (length es) in
+      es ++ replicateN (desiredsz - actualsz) f.

@@ -1786,19 +1810,19 @@

bedrock.lang.cpp.logic.expr

that is being initialized, see wp_init_initlist_array
-    Definition wp_array_init_fill (ety : type) (base : ptr) (es : list Expr) (f : option Expr) (sz : N)
-               (Q : FreeTemps -> mpred) : mpred :=
-      let len := N.of_nat (length es) in
-      let Q free :=
-          base |-> type_ptrR (Tarray (erase_qualifiers ety) sz) -* Q free
+    Definition wp_array_init_fill (ety : type) (base : ptr) (es : list Expr) (f : option Expr) (sz : N)
+               (Q : FreeTemps -> mpred) : mpred :=
+      let len := N.of_nat (length es) in
+      let Q free :=
+          base |-> type_ptrR (Tarray (erase_qualifiers ety) sz) -* Q free
      in
-      match (len ?= sz)%N with
+      match (len ?= sz)%N with
      | Lt =>
-          match f with
+          match f with
          | None => False
-          | Some fill => wp_array_init ety base (fill_initlist sz es fill) 0 Q
+          | Some fill => wp_array_init ety base (fill_initlist sz es fill) 0 Q
          end
-      | Eq => wp_array_init ety base es 0 Q
+      | Eq => wp_array_init ety base es 0 Q
      (* <http://eel.is/c++draft/dcl.init.general16.5> Programs which contain more initializer expressions than @@ -1808,10 +1832,10 @@

bedrock.lang.cpp.logic.expr

      end.

-    Lemma wp_array_init_fill_frame ety base es f sz Q Q' :
-      (Forall f, Q f -* Q' f)
-      |-- wp_array_init_fill ety base es f sz Q -*
-          wp_array_init_fill ety base es f sz Q'.
+    Lemma wp_array_init_fill_frame ety base es f sz Q Q' :
+      (Forall f, Q f -* Q' f)
+      |-- wp_array_init_fill ety base es f sz Q -*
+          wp_array_init_fill ety base es f sz Q'.
    Proof.
      rewrite /wp_array_init_fill.
      case_match; eauto.
@@ -1832,11 +1856,11 @@

bedrock.lang.cpp.logic.expr

-    Definition is_array_of (aty ety : type) : Prop :=
-      match aty with
-      | Tincomplete_array ety' => ety = ety'
-      | Tvariable_array ety' => ety = ety'
-      | Tarray ety' _ => ety = ety'
+    Definition is_array_of (aty ety : type) : Prop :=
+      match aty with
+      | Tincomplete_array ety' => ety = ety'
+      | Tvariable_array ety' => ety = ety'
+      | Tarray ety' _ => ety = ety'
      | _ => False
      end.
@@ -1853,10 +1877,10 @@

bedrock.lang.cpp.logic.expr

-    Axiom wp_init_initlist_array : forall ls fill ty ety (sz : N) (base : ptr) Q, (* sz' <= sz *)
-          is_array_of ty ety ->
-          wp_array_init_fill ety base ls fill sz Q
-      |-- wp_init (Tarray ety sz) base (Einitlist ls fill ty) Q.
+    Axiom wp_init_initlist_array : forall ls fill ty ety (sz : N) (base : ptr) Q, (* sz' <= sz *)
+          is_array_of ty ety ->
+          wp_array_init_fill ety base ls fill sz Q
+      |-- wp_init (Tarray ety sz) base (Einitlist ls fill ty) Q.

    (* https://eel.is/c++draft/dcl.initgeneral-7.2 says that "To @@ -1880,38 +1904,38 @@

bedrock.lang.cpp.logic.expr

    initialization. For this reason, the rule for default initalization
    simply defers to the rule for initialization with an empty initializer
    list. *)

-    Axiom wp_init_default_array : forall ty ety sz base ctorname args Q,
-          is_array_of ty ety ->
-          wp_array_init_fill ety base [] (Some $ Econstructor ctorname args ety) sz Q
-      |-- wp_init (Tarray ety sz) base (Econstructor ctorname args ty) Q.
+    Axiom wp_init_default_array : forall ty ety sz base ctorname args Q,
+          is_array_of ty ety ->
+          wp_array_init_fill ety base [] (Some $ Econstructor ctorname args ety) sz Q
+      |-- wp_init (Tarray ety sz) base (Econstructor ctorname args ty) Q.

-    Axiom wp_operand_initlist_default : forall t Q,
-          match get_default t with
+    Axiom wp_operand_initlist_default : forall t Q,
+          match get_default t with
          | None => False
-          | Some v => Q v FreeTemps.id
+          | Some v => Q v FreeTemps.id
          end
-      |-- wp_operand (Einitlist nil None t) Q.
+      |-- wp_operand (Einitlist nil None t) Q.

-    Axiom wp_operand_initlist_prim : forall t e Q,
-          (if prim_initializable t
-           then wp_operand e Q
+    Axiom wp_operand_initlist_prim : forall t e Q,
+          (if prim_initializable t
+           then wp_operand e Q
           else False)
-      |-- wp_operand (Einitlist (e :: nil) None t) Q.
+      |-- wp_operand (Einitlist (e :: nil) None t) Q.

-    Definition struct_inits (s : Struct) (es : list Expr) : option (list Initializer) :=
-      let info :=
-          map (fun b e => {| init_path := InitBase b.1
-                        ; init_type := Tnamed b.1
-                        ; init_init := e |}) s.(s_bases) ++
-          map (fun m e => {| init_path := InitField m.(mem_name)
-                        ; init_type := m.(mem_type)
-                        ; init_init := e |}) s.(s_fields)
+    Definition struct_inits (s : Struct) (es : list Expr) : option (list Initializer) :=
+      let info :=
+          map (fun b e => {| init_path := InitBase b.1
+                        ; init_type := Tnamed b.1
+                        ; init_init := e |}) s.(s_bases) ++
+          map (fun m e => {| init_path := InitField m.(mem_name)
+                        ; init_type := m.(mem_type)
+                        ; init_init := e |}) s.(s_fields)
      in
-      if bool_decide (length info = length es) then
-        Some $ List.map (fun '(f,e) => f e) $ combine info es
+      if bool_decide (length info = length es) then
+        Some $ List.map (fun '(f,e) => f e) $ combine info es
      else None.

@@ -1919,16 +1943,16 @@

bedrock.lang.cpp.logic.expr

       See https://eel.is/c++draft/dcl.init.aggr5. However, the cpp2v frontend desugars all of these to initialize exactly one element. *)
-    Definition union_inits (u : decl.Union) (es : list Expr)
+    Definition union_inits (u : decl.Union) (es : list Expr)
      : option (list Initializer) :=
-      match u.(u_fields) , es with
+      match u.(u_fields) , es with
      | m :: _ , e :: nil =>
-          let inits :=
+          let inits :=
            {| init_path := InitField m.(mem_name)
            ; init_type := m.(mem_type)
            ; init_init := e |} :: nil
          in
-          Some inits
+          Some inits
      | _ , _ => None
      end.
@@ -1955,31 +1979,31 @@

bedrock.lang.cpp.logic.expr

-    Axiom wp_init_initlist_agg : forall cls (base : ptr) cv es ty Q,
-        decompose_type ty = (cv, Tnamed cls) ->
-        (let do_const Q :=
-           if q_const cv
-           then wp_make_const tu base (Tnamed cls) Q
-           else Q
+    Axiom wp_init_initlist_agg : forall cls (base : ptr) cv es ty Q,
+        decompose_type ty = (cv, Tnamed cls) ->
+        (let do_const Q :=
+           if q_const cv
+           then wp_make_const tu base (Tnamed cls) Q
+           else Q
         in
-         match tu.(types) !! cls with
+         match tu.(types) !! cls with
         | Some (Gstruct s) =>
-             match struct_inits s es with
+             match struct_inits s es with
             | Some inits =>
-                 letI* := wp_struct_initializer_list tu s ρ cls base inits in
-                   do_const (Q FreeTemps.id)
+                 letI* := wp_struct_initializer_list tu s ρ cls base inits in
+                   do_const (Q FreeTemps.id)
             | _ => False
             end
         | Some (Gunion u) =>
-            match union_inits u es with
+            match union_inits u es with
            | Some inits =>
-                letI* := wp_union_initializer_list tu u ρ cls base inits in
-                do_const (Q FreeTemps.id)
+                letI* := wp_union_initializer_list tu u ρ cls base inits in
+                do_const (Q FreeTemps.id)
            | _ => False
            end
         | _ => False
         end)
-      |-- wp_init ty base (Einitlist es None ty) Q.
+      |-- wp_init ty base (Einitlist es None ty) Q.

  End with_resolve.
@@ -1987,7 +2011,7 @@

bedrock.lang.cpp.logic.expr


  (* `Earrayloop_init` needs to extend the region, so we need to start a new section. *)
  Section with_resolve__arrayloop.
-    Context `{Σ : cpp_logic} {σ : genv}.
+    Context `{Σ : cpp_logic} {σ : genv}.
    Variable (tu : translation_unit).

@@ -2029,37 +2053,37 @@

bedrock.lang.cpp.logic.expr

       injective and we don't expect the N to be very large in practice so we pick
       a very naive encoding.
     *)
-    Definition N_to_bs (n : N) : bs :=
+    Definition N_to_bs (n : N) : bs :=
      N.peano_rect (fun _ => bs)
                   BS.EmptyString
-                   (fun _ x => BS.String "1" x) n.
+                   (fun _ x => BS.String "1" x) n.

-    Definition arrayloop_loop_index (n : N) : bs := "!loop_index" ++ N_to_bs n.
-    Definition opaque_val (n : N) : bs := "%opaque" ++ N_to_bs n.
+    Definition arrayloop_loop_index (n : N) : bs := "!loop_index" ++ N_to_bs n.
+    Definition opaque_val (n : N) : bs := "%opaque" ++ N_to_bs n.

    (* Maybe we can `Rbind (opaque n) p`, and then add `_opaque` to encapsulate looking this up in the region;
       the new premise would be (after Loc:=ptr goes in) `Q _opaque` *)


-    Axiom wp_lval_opaque_ref : forall n ρ ty Q,
-          wp_lval tu ρ (Evar (opaque_val n) ty) Q
-      |-- wp_lval tu ρ (Eopaque_ref n Lvalue ty) Q.
+    Axiom wp_lval_opaque_ref : forall n ρ ty Q,
+          wp_lval tu ρ (Evar (opaque_val n) ty) Q
+      |-- wp_lval tu ρ (Eopaque_ref n Lvalue ty) Q.

-    Axiom wp_xval_opaque_ref : forall n ρ ty Q,
-          wp_lval tu ρ (Evar (opaque_val n) ty) Q
-      |-- wp_xval tu ρ (Eopaque_ref n Xvalue ty) Q.
+    Axiom wp_xval_opaque_ref : forall n ρ ty Q,
+          wp_lval tu ρ (Evar (opaque_val n) ty) Q
+      |-- wp_xval tu ρ (Eopaque_ref n Xvalue ty) Q.

    (* Maybe do something similar to what was suggested for `wp_lval_opaque_ref` above. *)
-    Axiom wp_operand_arrayloop_index : forall ρ level ty Q,
-          Exists v,
-            ((Exists q, _local ρ (arrayloop_loop_index level)
-                               |-> primR (erase_qualifiers ty) q v) **
-              True) //\\ Q v FreeTemps.id
-      |-- wp_operand tu ρ (Earrayloop_index level ty) Q.
+    Axiom wp_operand_arrayloop_index : forall ρ level ty Q,
+          Exists v,
+            ((Exists q, _local ρ (arrayloop_loop_index level)
+                               |-> primR (erase_qualifiers ty) q v) **
+              True) //\\ Q v FreeTemps.id
+      |-- wp_operand tu ρ (Earrayloop_index level ty) Q.

    (* The following loop is essentially the following:
@@ -2083,44 +2107,44 @@

bedrock.lang.cpp.logic.expr

                      _arrayloop_init level sz' ρ (S idx) targetp init ty Q)
         end*)

    Definition _arrayloop_init
-               (ρ : region) (level : N)
-               (targetp : ptr) (init : Expr)
-               (ty : type) (Q : epred)
+               (ρ : region) (level : N)
+               (targetp : ptr) (init : Expr)
+               (ty : type) (Q : epred)
               (* The arguments above this comment are constant throughout the recursion.

                  The arguments below this line will change during the recursion.
                *)

-               (sz : N) (idx : N)
+               (sz : N) (idx : N)
      : mpred :=
-      let loop_index := _local ρ (arrayloop_loop_index level) in
+      let loop_index := _local ρ (arrayloop_loop_index level) in
      N.peano_rect (fun _ : N => N -> mpred)
-                   (fun _ => Q)
-                   (fun _ rest idx =>
+                   (fun _ => Q)
+                   (fun _ rest idx =>
                      (* NOTE The abstract machine only provides 1/2 of the ownership
                           to the program to make it read-only.
                         NOTE that no "correct" program will ever modify this variable
                           anyways. *)

-                      loop_index |-> primR Tu64 (cQp.c 1) idx -*
-                      wp_initialize tu ρ ty (targetp .[ erase_qualifiers ty ! idx ]) init
-                              (fun free => interp free $
-                                 loop_index |-> primR Tu64 (cQp.c 1) idx **
-                                 rest (N.succ idx))) sz idx.
- -
-    Axiom wp_init_arrayloop_init : forall oname level sz ρ (trg : ptr) src init ety ty Q,
-          has_type_prop (Vn sz) Tu64 ->
-          is_array_of ty ety ->
-          wp_glval tu ρ src
-                   (fun p free =>
-                      Forall idxp,
-                      trg |-> validR -*
-                      _arrayloop_init (Rbind (opaque_val oname) p
-                                             (Rbind (arrayloop_loop_index level) idxp ρ))
-                                      level trg init ety
-                                      (trg |-> type_ptrR (Tarray ety sz) -* Q free)
-                                      sz 0)
-      |-- wp_init tu ρ (Tarray ety sz) trg
-                    (Earrayloop_init oname src level sz init ty) Q.
+                      loop_index |-> primR Tu64 (cQp.c 1) idx -*
+                      wp_initialize tu ρ ty (targetp .[ erase_qualifiers ty ! idx ]) init
+                              (fun free => interp free $
+                                 loop_index |-> primR Tu64 (cQp.c 1) idx **
+                                 rest (N.succ idx))) sz idx.
+ +
+    Axiom wp_init_arrayloop_init : forall oname level sz ρ (trg : ptr) src init ety ty Q,
+          has_type_prop (Vn sz) Tu64 ->
+          is_array_of ty ety ->
+          wp_glval tu ρ src
+                   (fun p free =>
+                      Forall idxp,
+                      trg |-> validR -*
+                      _arrayloop_init (Rbind (opaque_val oname) p
+                                             (Rbind (arrayloop_loop_index level) idxp ρ))
+                                      level trg init ety
+                                      (trg |-> type_ptrR (Tarray ety sz) -* Q free)
+                                      sz 0)
+      |-- wp_init tu ρ (Tarray ety sz) trg
+                    (Earrayloop_init oname src level sz init ty) Q.

    (* This is here, rather than being next to Eif because the evaluation
@@ -2129,17 +2153,17 @@

bedrock.lang.cpp.logic.expr

       terms of the opaque value, but, it does not seem possible for the opaque value to
       be used in this expression.
     *)

-    Definition wp_cond2 {T} (vc : ValCat) (wp : translation_unit -> region -> Expr -> (T -> FreeTemps.t -> epred) -> mpred) : Prop :=
-      forall tu ρ n ty common tst th el (Q : T -> FreeTemps -> mpred),
-        Forall p,
-           wp_initialize tu ρ (type_of common) p common (fun free =>
-           let ρ' := Rbind (opaque_val n) p ρ in
-           wp_test tu ρ' tst (fun c free'' =>
-             let free := (free'' >*> FreeTemps.delete ty p >*> free)%free in
-             if c
-             then wp tu ρ' th (fun v free' => Q v (free' >*> free))
-             else wp tu ρ' el (fun v free' => Q v (free' >*> free))))
-        |-- wp tu ρ (Eif2 n common tst th el vc ty) Q.
+    Definition wp_cond2 {T} (vc : ValCat) (wp : translation_unit -> region -> Expr -> (T -> FreeTemps.t -> epred) -> mpred) : Prop :=
+      forall tu ρ n ty common tst th el (Q : T -> FreeTemps -> mpred),
+        Forall p,
+           wp_initialize tu ρ (type_of common) p common (fun free =>
+           let ρ' := Rbind (opaque_val n) p ρ in
+           wp_test tu ρ' tst (fun c free'' =>
+             let free := (free'' >*> FreeTemps.delete ty p >*> free)%free in
+             if c
+             then wp tu ρ' th (fun v free' => Q v (free' >*> free))
+             else wp tu ρ' el (fun v free' => Q v (free' >*> free))))
+        |-- wp tu ρ (Eif2 n common tst th el vc ty) Q.

    Axiom wp_lval_condition2 : Reduce (wp_cond2 Lvalue wp_lval).
@@ -2162,16 +2186,16 @@

bedrock.lang.cpp.logic.expr

       end of the full expression because (in this trace), `C(1)` would be
       constructing a temporary.
     *)
-    Axiom wp_init_condition2 : forall tu ρ n ty common tst th el vc p Q,
-        Forall p,
-           wp_initialize tu ρ (type_of common) p common (fun free =>
-           let ρ' := Rbind (opaque_val n) p ρ in
-           wp_test tu ρ' tst (fun c free'' =>
-             let free := (free'' >*> FreeTemps.delete ty p >*> free)%free in
-             if c
-             then wp_init tu ρ' ty p th (fun free' => Q (free' >*> free))
-             else wp_init tu ρ' ty p el (fun free' => Q (free' >*> free))))
-        |-- wp_init tu ρ ty p (Eif2 n common tst th el vc ty) Q.
+    Axiom wp_init_condition2 : forall tu ρ n ty common tst th el vc p Q,
+        Forall p,
+           wp_initialize tu ρ (type_of common) p common (fun free =>
+           let ρ' := Rbind (opaque_val n) p ρ in
+           wp_test tu ρ' tst (fun c free'' =>
+             let free := (free'' >*> FreeTemps.delete ty p >*> free)%free in
+             if c
+             then wp_init tu ρ' ty p th (fun free' => Q (free' >*> free))
+             else wp_init tu ρ' ty p el (fun free' => Q (free' >*> free))))
+        |-- wp_init tu ρ ty p (Eif2 n common tst th el vc ty) Q.

  End with_resolve__arrayloop.
diff --git a/docs/_static/coqdoc/indexpage.html b/docs/_static/coqdoc/indexpage.html index 4dc285ca..aa18d1f2 100644 --- a/docs/_static/coqdoc/indexpage.html +++ b/docs/_static/coqdoc/indexpage.html @@ -66,7 +66,7 @@ Z _ other -(9687 entries) +(9689 entries) Notation Index @@ -290,7 +290,7 @@ Z _ other -(604 entries) +(605 entries) Projection Index @@ -514,7 +514,7 @@ Z _ other -(1470 entries) +(1471 entries)
@@ -3407,6 +3407,7 @@

Global Index

expr_notations [library]
Expr.AddConst [constructor, in bedrock.lang.cpp.logic.expr]
Expr.arrayloop_loop_index [definition, in bedrock.lang.cpp.logic.expr]
+Expr.can_represent_null [definition, in bedrock.lang.cpp.logic.expr]
Expr.classify_cast [definition, in bedrock.lang.cpp.logic.expr]
Expr.dispatch [definition, in bedrock.lang.cpp.logic.expr]
Expr.dispatch_frame [lemma, in bedrock.lang.cpp.logic.expr]
@@ -3513,6 +3514,7 @@

Global Index

Expr.wp_operand_cast_reinterpret [axiom, in bedrock.lang.cpp.logic.expr]
Expr.wp_operand_cast_user [axiom, in bedrock.lang.cpp.logic.expr]
Expr.wp_init_cast_user [axiom, in bedrock.lang.cpp.logic.expr]
+Expr.wp_operand_cast_null_int [axiom, in bedrock.lang.cpp.logic.expr]
Expr.wp_operand_cast_null [axiom, in bedrock.lang.cpp.logic.expr]
Expr.wp_operand_cast_integral [axiom, in bedrock.lang.cpp.logic.expr]
Expr.wp_operand_cast_bitcast [axiom, in bedrock.lang.cpp.logic.expr]
@@ -14898,6 +14900,7 @@

Axiom Index

Expr.wp_operand_cast_reinterpret [in bedrock.lang.cpp.logic.expr]
Expr.wp_operand_cast_user [in bedrock.lang.cpp.logic.expr]
Expr.wp_init_cast_user [in bedrock.lang.cpp.logic.expr]
+Expr.wp_operand_cast_null_int [in bedrock.lang.cpp.logic.expr]
Expr.wp_operand_cast_null [in bedrock.lang.cpp.logic.expr]
Expr.wp_operand_cast_integral [in bedrock.lang.cpp.logic.expr]
Expr.wp_operand_cast_bitcast [in bedrock.lang.cpp.logic.expr]
@@ -19196,6 +19199,7 @@

Definition Index

Expr_ind [in bedrock.lang.cpp.syntax.expr]
Expr_rect [in bedrock.lang.cpp.syntax.expr]
Expr.arrayloop_loop_index [in bedrock.lang.cpp.logic.expr]
+Expr.can_represent_null [in bedrock.lang.cpp.logic.expr]
Expr.classify_cast [in bedrock.lang.cpp.logic.expr]
Expr.dispatch [in bedrock.lang.cpp.logic.expr]
Expr.fill_initlist [in bedrock.lang.cpp.logic.expr]
@@ -20286,7 +20290,7 @@

Definition Index

Z _ other -(9687 entries) +(9689 entries) Notation Index @@ -20510,7 +20514,7 @@

Definition Index

Z _ other -(604 entries) +(605 entries) Projection Index @@ -20734,7 +20738,7 @@

Definition Index

Z _ other -(1470 entries) +(1471 entries)