Skip to content

Commit aaed353

Browse files
authored
Add pointer type cast expression guideline: Avoid underscore casts (#51)
1 parent ba68051 commit aaed353

File tree

1 file changed

+76
-0
lines changed

1 file changed

+76
-0
lines changed

src/coding-guidelines/expressions.rst

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,79 @@
55

66
Expressions
77
===========
8+
9+
10+
.. guideline:: Avoid as underscore pointer casts
11+
:id: gui_HDnAZ7EZ4z6G
12+
:category: required
13+
:status: draft
14+
:release: <TODO>
15+
:fls: fls_1qhsun1vyarz
16+
:decidability: decidable
17+
:scope: module
18+
:tags: readability, reduce-human-error
19+
20+
Code must not rely on Rust's type inference when doing explicit pointer casts via ``var as Type`` or ``core::mem::transmute``.
21+
Instead, explicitly specify the complete target type in the ``as`` expression or ``core::mem::transmute`` call expression.
22+
23+
.. rationale::
24+
:id: rat_h8LdJQ1MNKu9
25+
:status: draft
26+
27+
``var as Type`` casts and ``core::mem::transmute``\s between raw pointer types are generally valid and unchecked by the compiler as long the target pointer type is a thin pointer.
28+
Not specifying the concrete target pointer type allows the compiler to infer it from the surroundings context which may result in the cast accidentally changing due to surrounding type changes resulting in semantically invalid pointer casts.
29+
30+
Raw pointers have a variety of invariants to manually keep track of.
31+
Specifying the concrete types in these scenarios allows the compiler to catch some of these potential issues for the user.
32+
33+
.. non_compliant_example::
34+
:id: non_compl_ex_V37Pl103aUW4
35+
:status: draft
36+
37+
The following code leaves it up to type inference to figure out the concrete types of the raw pointer casts, allowing changes to ``with_base``'s function signature to affect the types the function body of ``non_compliant_example`` without incurring a compiler error.
38+
39+
.. code-block:: rust
40+
41+
#[repr(C)]
42+
struct Base {
43+
position: (u32, u32)
44+
}
45+
46+
#[repr(C)]
47+
struct Extended {
48+
base: Base,
49+
scale: f32
50+
}
51+
52+
fn non_compliant_example(extended: &Extended) {
53+
let extended = extended as *const _;
54+
with_base(unsafe { &*(extended as *const _) })
55+
}
56+
57+
fn with_base(_: &Base) { ... }
58+
59+
.. compliant_example::
60+
:id: compl_ex_W08ckDrkOhkt
61+
:status: draft
62+
63+
We specify the concrete target types for our pointer casts resulting in a compilation error if the function signature of ``with_base`` is changed.
64+
65+
.. code-block:: rust
66+
67+
#[repr(C)]
68+
struct Base {
69+
position: (u32, u32)
70+
}
71+
72+
#[repr(C)]
73+
struct Extended {
74+
base: Base,
75+
scale: f32
76+
}
77+
78+
fn non_compliant_example(extended: &Extended) {
79+
let extended = extended as *const Extended;
80+
with_base(unsafe { &*(extended as *const Base) })
81+
}
82+
83+
fn with_base(_: &Base) { ... }

0 commit comments

Comments
 (0)