slice-from-ptr is refused with the slice-from call to write, and the pointer cast's const rule is documented as covering the outer pointer only
This commit is contained in:
parent
24761dcf54
commit
a39d96149d
21
lib/check.ml
21
lib/check.ml
@ -9285,8 +9285,12 @@ and check_call ctx ~want loc (head : Ast.expr) (args : Ast.expr list) =
|
|||||||
else, and checks nothing: the caller is promising the bytes are that
|
else, and checks nothing: the caller is promising the bytes are that
|
||||||
type, as with [slice-from]. Both backends already lower a Ptr-to-Ptr
|
type, as with [slice-from]. Both backends already lower a Ptr-to-Ptr
|
||||||
[Cast] to no instruction. Adding const is allowed; dropping it is not,
|
[Cast] to no instruction. Adding const is allowed; dropping it is not,
|
||||||
or a cast would undo the const [addr] put there. There is no cast between
|
or a cast would undo the const [addr] put there. The rule is about the
|
||||||
a pointer and an integer, and no pointer arithmetic. *)
|
outer pointer only: the cast is unchecked, so ((Ptr (Ptr u8)) q) over a
|
||||||
|
(Ptr const (Ptr const u8)) is refused for the outer const but a
|
||||||
|
(Ptr (Ptr const u8)) casts to (Ptr (Ptr u8)) — what lies deeper is the
|
||||||
|
writer's promise, like everything else the cast asserts. There is no cast
|
||||||
|
between a pointer and an integer, and no pointer arithmetic. *)
|
||||||
| Ast.Call ({ Ast.e = Ast.Var "Ptr"; _ }, _)
|
| Ast.Call ({ Ast.e = Ast.Var "Ptr"; _ }, _)
|
||||||
when (match type_of_expr head with Some _ -> true | None -> false) ->
|
when (match type_of_expr head with Some _ -> true | None -> false) ->
|
||||||
let target = resolve ctx.env (Option.get (type_of_expr head)) in
|
let target = resolve ctx.env (Option.get (type_of_expr head)) in
|
||||||
@ -12688,6 +12692,19 @@ and ordinary_call ctx ~want loc name args =
|
|||||||
says what the view is: over a Vec it borrows the storage the Vec \
|
says what the view is: over a Vec it borrows the storage the Vec \
|
||||||
owns, over an array or a string it looks at the value itself. \
|
owns, over an array or a string it looks at the value itself. \
|
||||||
Write %s" call
|
Write %s" call
|
||||||
|
else if name = "slice-from-ptr" then
|
||||||
|
(* The name this form had before; code written against it lands here.
|
||||||
|
Said as the form to write, with the reader's arguments, and not as
|
||||||
|
a rename — a first-time reader has no old name to be told about. *)
|
||||||
|
let call =
|
||||||
|
match args with
|
||||||
|
| [ p; n ] ->
|
||||||
|
"(slice-from " ^ spell_arg "p" p ^ " " ^ spell_arg "n" n ^ ")"
|
||||||
|
| _ -> "(slice-from p n)"
|
||||||
|
in
|
||||||
|
Loc.failk "check/unknown-function" loc
|
||||||
|
"there is no slice-from-ptr. A slice from a pointer and a count of \
|
||||||
|
the elements behind it is slice-from. Write %s" call
|
||||||
else if no_such_rand name <> None then
|
else if no_such_rand name <> None then
|
||||||
(* A retired randomness name, which is a name and not a near miss:
|
(* A retired randomness name, which is a name and not a near miss:
|
||||||
"did you mean rand?" for [rand-f32] would be true and would not say
|
"did you mean rand?" for [rand-f32] would be true and would not say
|
||||||
|
|||||||
@ -2541,6 +2541,11 @@ let () =
|
|||||||
rejects_check "a pointer cast of an integer"
|
rejects_check "a pointer cast of an integer"
|
||||||
"(defn f [x i64] (Ptr i32) ((Ptr i32) x))"
|
"(defn f [x i64] (Ptr i32) ((Ptr i32) x))"
|
||||||
~needle:"no conversion between an integer and a pointer";
|
~needle:"no conversion between an integer and a pointer";
|
||||||
|
rejects_check "slice-from-ptr names slice-from"
|
||||||
|
"(defn f [p (Ptr i32) n i32] i32 (length (slice-from-ptr p n)))"
|
||||||
|
~needle:"Write (slice-from p n)";
|
||||||
|
accepts "a pointer cast checks the outer const only"
|
||||||
|
"(defn f [q (Ptr (Ptr const u8))] (Ptr (Ptr u8)) ((Ptr (Ptr u8)) q))";
|
||||||
rejects_check "a pointer cast of a dyn"
|
rejects_check "a pointer cast of a dyn"
|
||||||
"(defn f [x dyn] (Ptr i32) ((Ptr i32) x))"
|
"(defn f [x dyn] (Ptr i32) ((Ptr i32) x))"
|
||||||
~needle:"A dyn value never holds a pointer";
|
~needle:"A dyn value never holds a pointer";
|
||||||
|
|||||||
@ -525,7 +525,7 @@ notation reads as exactly one data item.</p>
|
|||||||
<tr><td><code>(Map K V)</code></td><td>open addressing, owning, copies the same way. The only map spelling: braces in type position are not a type</td><td>data + len + log2cap + its allocator</td></tr>
|
<tr><td><code>(Map K V)</code></td><td>open addressing, owning, copies the same way. The only map spelling: braces in type position are not a type</td><td>data + len + log2cap + its allocator</td></tr>
|
||||||
<tr><td><code>(Pool T)</code></td><td>generational slab storage, owning, copies the same way</td><td>items + slots + its allocator</td></tr>
|
<tr><td><code>(Pool T)</code></td><td>generational slab storage, owning, copies the same way</td><td>items + slots + its allocator</td></tr>
|
||||||
<tr><td><code>(Handle T)</code></td><td>a reference into a pool that reports a dead referent</td><td>index and generation packed into an <code>i64</code></td></tr>
|
<tr><td><code>(Handle T)</code></td><td>a reference into a pool that reports a dead referent</td><td>index and generation packed into an <code>i64</code></td></tr>
|
||||||
<tr><td><code>(Ptr T)</code></td><td>raw pointer. <code>((Ptr U) p)</code> reads it as a pointer to <code>U</code>; <code>(slice-from p n)</code> makes a <code>[T]</code> of the <code>n</code> elements behind it. Neither checks the memory</td><td>a pointer</td></tr>
|
<tr><td><code>(Ptr T)</code></td><td>raw pointer. <code>((Ptr U) p)</code> reads it as a pointer to <code>U</code>, and may add <code>const</code> but not drop it (the outer pointer only: what it points at is taken on trust); <code>(slice-from p n)</code> makes a <code>[T]</code> of the <code>n</code> elements behind it. Neither checks the memory</td><td>a pointer</td></tr>
|
||||||
<tr><td><code>(Ptr const T)</code></td><td>a pointer nothing is written through: the address of read-only storage, and what a C <code>const T *</code> takes. A <code>(Ptr T)</code> converts to one, never the reverse</td><td>a pointer</td></tr>
|
<tr><td><code>(Ptr const T)</code></td><td>a pointer nothing is written through: the address of read-only storage, and what a C <code>const T *</code> takes. A <code>(Ptr T)</code> converts to one, never the reverse</td><td>a pointer</td></tr>
|
||||||
<tr><td><code>(Option T)</code></td><td><code>Some</code> / <code>None</code></td><td>tag byte + T</td></tr>
|
<tr><td><code>(Option T)</code></td><td><code>Some</code> / <code>None</code></td><td>tag byte + T</td></tr>
|
||||||
<tr><td><code>(Fn [T ...] R)</code></td><td>a function value, which may have captured</td><td>a code address and an environment pointer</td></tr>
|
<tr><td><code>(Fn [T ...] R)</code></td><td>a function value, which may have captured</td><td>a code address and an environment pointer</td></tr>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user