Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 18 additions & 33 deletions src/coding-guidelines/expressions/gui_ADHABsmK9FXz.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ The 'as' operator should not be used with numeric operands

as either the right operand or the type of the left operand.

**Exception:** ``as`` may be used with ``usize`` as the right operand and an expression of raw pointer
type as the left operand.
**Exception:** ``as`` may be used with an integer type as the right operand and an expression of floating
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i added this exception because there is no way to go from float to int otherwise. If you want i can also remove this.

point type as the left operand.

.. rationale::
:id: rat_v56bjjcveLxQ
Expand All @@ -41,13 +41,11 @@ The 'as' operator should not be used with numeric operands
value, and which are intended to be fallible. The latter cannot be used from const functions, indicating
that these should avoid using fallible conversions.

A pointer-to-address cast does not lose value, but will be truncated unless the destination type is large
enough to hold the address value. The ``usize`` type is guaranteed to be wide enough for this purpose.
A pointer-to-address or address-to-pointer cast should be performed using the exposed or strict provenance APIs
(``addr``, ``expose_provenance``, ``with_addr`` or ``with_exposed_provenance``).
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i would like to link to guideline that explains exposed and strict provenance and recommends one of them (probably strict). Depending on how strongly you want to discourage exposed i can also remove the suggestion here.


A pointer-to-address cast is not symmetrical because the resulting pointer may not point to a valid object,
may not point to an object of the right type, or may not be properly aligned.
If a conversion in this direction is needed, :std:`std::mem::transmute` will communicate the intent to perform
an unsafe operation.
Casts between pointer types should use the ``cast``, ``cast_const`` or ``cast_mut`` methods to better
communicate intent.

.. non_compliant_example::
:id: non_compl_ex_hzGUYoMnK59w
Expand All @@ -72,15 +70,15 @@ The 'as' operator should not be used with numeric operands
let _g = e as i64; // non-compliant - lossy despite object size

let b: u32 = 0;
let p1: * const u32 = &b;
let p1: *const u32 = &b;
let _a1 = p1 as usize; // compliant by exception
let _a2 = p1 as u16; // non-compliant - may lose address range
let _a3 = p1 as u64; // non-compliant - use usize to indicate intent
let _a3 = p1 as u64; // non-compliant - use .addr() or .expose_provenance()
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could also remove exposed provance suggestion if you want


let a1 = p1 as usize;
let _p2 = a1 as * const u32; // non-compliant - prefer transmute
let _p2 = a1 as *const u32; // non-compliant
let a2 = p1 as u16;
let _p3 = a2 as * const u32; // non-compliant (and most likely not in a valid address range)
let _p3 = a2 as *const u32; // non-compliant (and most likely not in a valid address range)
}
#
# fn main() {}
Expand All @@ -93,7 +91,7 @@ The 'as' operator should not be used with numeric operands
better with ``into()`` or ``from()``.
Valid conversions that risk losing value, where doing so would be an error, can
communicate this and include an error check, with ``try_into`` or ``try_from``.
Other forms of conversion may find ``transmute`` better communicates their intent.
Other forms of conversion may find explicit functions better communicate their intent.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this sentence is really general now, but there are a lot of methods depending on the type and the conversion that should be done.


.. rust-example::
:miri:
Expand All @@ -114,26 +112,13 @@ The 'as' operator should not be used with numeric operands

let h: u32 = 0;
let p1: * const u32 = &h;
let a1 = p1 as usize; // (compliant)

unsafe {
let _a2: usize = std::mem::transmute(p1); // OK
let _a3: u64 = std::mem::transmute(p1); // OK, size is checked
// let a3: u16 = std::mem::transmute(p1); // invalid, different sizes

#[allow(integer_to_ptr_transmutes)]
let _p2: * const u32 = std::mem::transmute(a1); // OK
#[allow(integer_to_ptr_transmutes)]
let _p3: * const u32 = std::mem::transmute(a1); // OK
}

unsafe {
// does something entirely different,
// reinterpreting the bits of z as the IEEE bit pattern of a double
// precision object, rather than converting the integer value
#[allow(unnecessary_transmutes)]
let _f1: f64 = std::mem::transmute(_z);
}
let a1 = p1.expose_provenance(); // compliant
let a2 = p1.addr(); // compliant, can't be turned back into a dereferencable pointer

// does something entirely different,
// reinterpreting the bits of z as the IEEE bit pattern of a double
// precision object, rather than converting the integer value
let _f1: f64 = _z.to_bits();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't know if this example is useful. It doesn't replace an as it does something completely different. But it shouldn't use transmute

}
#
# fn main() {}