From eb9af1543271e22a02003c20352e5c1b803af213 Mon Sep 17 00:00:00 2001 From: Alex Celeste Date: Wed, 21 May 2025 14:58:17 +0100 Subject: [PATCH 1/6] Rework the guideline description to remove the incorrect claim that an explicit Amplification section exists (instead, whatever paragraph immediately opens the guideline is just normative). We can continue to call it that but the subheading is not necessary. --- src/process/style-guideline.rst | 42 +++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/src/process/style-guideline.rst b/src/process/style-guideline.rst index 194b89a..e82dae3 100644 --- a/src/process/style-guideline.rst +++ b/src/process/style-guideline.rst @@ -92,10 +92,6 @@ We will examine each part: :scope: module :tags: numerics - Code must not rely on Rust's implicit integer wrapping behavior that occurs in release builds. - Instead, explicitly handle potential overflows using the standard library's checked, - saturating, or wrapping operations. - ``guideline`` Title ------------------- @@ -308,15 +304,27 @@ what it covers. Content **SHOULD** aim to be as short and self-contained as possible, while still explaining the scope of the guideline. -Content **SHOULD NOT** cover the rationale for the guideline, which is done in the ``rationale`` section. +Guideline content consists of an Amplification and any Exceptions, which are normative, +supported by a Rationale and examples, which are not normative. Amplification ^^^^^^^^^^^^^ -Guideline Content **MAY** contain a section titled *Amplification* followed by text that provides a more -precise description of the guideline title. An amplification is normative; if it conflicts with the -``guideline`` Title, the amplification **MUST** take precedence. This mechanism is convenient as it allows -a complicated concept to be conveyed using a short Title. +The *Amplification* is the block of text that **MAY** appear immediately below the guideline +attribute block, before any other subheadings. +If it is provided, the Amplification is normative; if it conflicts with the ``guideline`` Title, +the Amplification **MUST** take precedence. This mechanism is convenient as it allows a complicated +concept to be conveyed using a short Title and refined by the text below. + +Content in the Amplification **SHOULD NOT** cover the rationale for the guideline or any +non-normative explanations, which **SHOULD** be provided in the ``rationale`` and examples sections +where helpful. + +:: + + Code must not rely on Rust's implicit integer wrapping behavior that occurs in release builds. + Instead, explicitly handle potential overflows using the standard library's checked, + saturating, or wrapping operations. Exception ^^^^^^^^^ @@ -327,9 +335,17 @@ some guidelines to be simplified. It is important to note that an exception is a a guideline does not apply. Code that complies with a guideline by virtue of an exception does not require a deviation. +If it is provided, the Exception is normative; if it conflicts with the ``guideline`` Title or the +Amplification, the Exception takes precedence over both. Depending on the individual guideline, it +may be clearer to have an Amplification or Title with an explicit Exception overriding parts of +their description, or it may be clearer to express excepted cases as integrated sentences in the +Amplification. This decision is editorial. + ``rationale`` ============= +Each Guideline **MUST** provide a *Rationale* for its inclusion and enforcement. + :: .. rationale:: @@ -363,7 +379,13 @@ The ``status`` option of a ``rationale`` **MUST** match the ``status`` of its pa Rationale Content ----------------- -TODO(pete.levasseur) +The content of the rationale **SHOULD** provide the relevant context for why this guideline is useful. +The Rationale **SHOULD** make reference to any undefined behaviours or known errors associated +with the subject of the guideline. +The Rationale **MAY** make reference to other guidelines or to external documents cited in the +References. + +The Rationale **SHOULD** be supported by code examples wherever concise examples are possible. ``non_compliant_example`` ========================= From 7fe2a12f2642943f76ccc9e26056ad4cf6960e21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Eris=20Celeste=20n=C3=A9e=20Gilding?= Date: Tue, 27 May 2025 09:34:26 +0100 Subject: [PATCH 2/6] Update src/process/style-guideline.rst Co-authored-by: Pete LeVasseur --- src/process/style-guideline.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/process/style-guideline.rst b/src/process/style-guideline.rst index e82dae3..918c59b 100644 --- a/src/process/style-guideline.rst +++ b/src/process/style-guideline.rst @@ -380,7 +380,7 @@ Rationale Content ----------------- The content of the rationale **SHOULD** provide the relevant context for why this guideline is useful. -The Rationale **SHOULD** make reference to any undefined behaviours or known errors associated +The Rationale **SHOULD** make reference to any undefined behaviors or known errors associated with the subject of the guideline. The Rationale **MAY** make reference to other guidelines or to external documents cited in the References. From 6b3757546275835a3dc965b5002f90c8d9d537f2 Mon Sep 17 00:00:00 2001 From: Alex Celeste Date: Wed, 4 Jun 2025 15:51:12 +0100 Subject: [PATCH 3/6] Provide initial examples of MISRA vs CERT style rules --- src/coding-guidelines/expressions.rst | 242 ++++++++++++++++++++++++++ src/conf.py | 4 + src/process/style-guideline.rst | 3 + 3 files changed, 249 insertions(+) diff --git a/src/coding-guidelines/expressions.rst b/src/coding-guidelines/expressions.rst index b73b172..baf21b4 100644 --- a/src/coding-guidelines/expressions.rst +++ b/src/coding-guidelines/expressions.rst @@ -81,3 +81,245 @@ Expressions } fn with_base(_: &Base) { ... } + + +.. guideline:: The ``as`` operator should not be used with numeric operands + :id: gui_ADHABsmK9FXz + :category: advisory + :status: draft + :release: + :fls: fls_otaxe9okhdr1 + :decidability: decidable + :scope: module + :tags: subset, reduce-human-error + + The binary operator ``as`` should not be used with: + + * a numeric type, including all supported integer, floating, and machine-dependent arithmetic types; or + * ``bool``; or + * ``char`` + + 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. + + .. rationale:: + :id: rat_v56bjjcveLxQ + :status: draft + + Although the conversions performed by ``as`` between numeric types are all well-defined, ``as`` coerces + the value to fit in the destination type, which may result in unexpected data loss if the value needs to + be truncated, rounded, or produce a nearest possible non-equal value. + + Although some conversions are lossless, others are not symmetrical. Instead of relying on either a defined + lossy behaviour or risking loss of precision, the code can communicate intent by using ``Into`` or ``From`` + and ``TryInto`` or ``TryFrom`` to signal which conversions are intended to perfectly preserve the original + value, and which are intended to be fallible. + + 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 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::mem::transmute`` will communicate the intent to perform + an unsafe operation. + + .. non_compliant_example:: + :id: non_compl_ex_hzGUYoMnK59w + :status: draft + + ``as`` used here can change the value range or lose precision. + Even when it doesn't, nothing enforces the correct behaviour or communicates whether + we intend to allow lossy conversions, or only expect valid conversions. + + .. code-block:: rust + + fn f1 (x:u16, y:i32, z:u64, w:u8) { + let a = w as char; // non-compliant + let b = y as u32; // non-compliant - changes value range + let c = x as i64; // non-compliant - could use .into() + + let d = y as f32; // non-compliant - lossy + let e = d as f64; // non-compliant - could use .into() + let f = e as f32; // non-compliant - lossy + + let g = e as i64; // non-compliant - lossy despite object size + + 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 p2 = a1 as * const u32; // non-compliant - prefer transmute + let p3 = a2 as * const u32; // non-compliant, and probably invalid + } + + .. compliant_example:: + :id: compl_ex_uilHTIOgxD37 + :status: draft + + Valid conversions that are guaranteed to preserve exact values can be communicated + 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. + + .. code-block:: rust + + fn f2 (x:u16, y:i32, z:u64, w:u8) { + let a:char = w.into (); + let b:Result = y.try_into (); // produce an error on range clip + let c:i64 = x.into (); + + let d = f32::from (x); // u16 is within range, u32 is not + let e = f64::from (d); + // let f = f32::from (e); // no From exists + + // let g = ... // no From exists + + 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 + + let p2:* const u32 = std::mem::transmute (a1); // OK + let p3:* const u32 = std::mem::transmute (a1); // OK + } + + unsafe { + let f1:f64 = std::mem::transmute (z); // does something entirely different + } + } + + +.. guideline:: An integer shall not be converted to a pointer + :id: gui_PM8Vpf7lZ51U + :category: required + :status: draft + :release: + :fls: fls_59mpteeczzo + :decidability: decidable + :scope: module + :tags: subset, undefined-behavior + + The ``as`` operator shall not be used with an expression of numeric type as the left operand, + and any pointer type as the right operand. + + ``std::mem::transmute`` shall not be used with any numeric type (including floating tyoes) as the + argument to the ``Src`` parameter, and any pointer type as the argument to the ``Dst`` parameter. + + .. rationale:: + :id: rat_YqhEiWTj9z6L + :status: draft + + A pointer created from an arbitrary arithmetic expression may designate an invalid address, + including an address that does not point to a valid object, an address that points to an + object of the wrong type, or an address that is not properly aligned. Use of such a pointer + to access memory will result in undefined behavior. + + The ``as`` operator also does not check that the size of the source operand is the same as + the size of a pointer, which may lead to unexpected results if the address computation was + originally performed in a differently-sized address space. + + .. non_compliant_example:: + :id: non_compl_ex_0ydPk7VENSrA + :status: draft + + Any use of ``as`` or ``transmute`` to create a pointer from an arithmetic address value + is non-compliant: + + .. code-block:: rust + + fn f1 (x:u16, y:i32, z:u64, w:usize) { + let p1 = x as * const u32; // not compliant + let p2 = y as * const u32; // not compliant + let p3 = z as * const u32; // not compliant + let p4 = w as * const u32; // not compliant despite being the right size + + let f:f64 = 10.0; + // let p5 = f as * const u32; // not valid + + unsafe { + // let p5:* const u32 = std::mem::transmute (x); // not valid + // let p6:* const u32 = std::mem::transmute (y); // not valid + + let p7:* const u32 = std::mem::transmute (z); // not compliant + let p8:* const u32 = std::mem::transmute (w); // not compliant + + let p9:* const u32 = std::mem::transmute (f); // not compliant, and very strange + } + } + + .. compliant_example:: + :id: compl_ex_oneKuF52yzrx + :status: draft + + There is no compliant example of this operation. + + +.. guideline:: An integer shall not be converted to an invalid pointer + :id: gui_iv9yCMHRgpE0 + :category: required + :status: draft + :release: + :fls: fls_9wgldua1u8yt + :decidability: undecidable + :scope: system + :tags: defect, undefined-behavior + + An expression of numeric type shall not be converted to a pointer if the resulting pointer + is incorrectly aligned, does not point to an entity of the referenced type, or is an invalid representation. + + .. rationale:: + :id: rat_OhxKm751axKw + :status: draft + + The mapping between pointers and integers must be consistent with the addressing structure of the + execution environment. Issues may arise, for example, on architectures that have a segmented memory model. + + .. non_compliant_example:: + :id: non_compl_ex_CkytKjRQezfQ + :status: draft + + This example makes assumptions about the layout of the address space that do not hold on all platforms. + The manipulated address may have discarded part of the original address space, and the flag may + silently interfere with the address value. On platforms where pointers are 64-bits this may have + particularly unexpected results. + + .. code-block:: rust + + fn f1 (flag:u32, ptr:* const u32) { + /* ... */ + let mut rep = ptr as usize; + rep = (rep & 0x7fffff) | ((flag as usize) << 23); + let p2 = rep as * const u32; + } + + .. compliant_example:: + :id: compl_ex_oBoluiKSvREu + :status: draft + + This compliant solution uses a struct to provide storage for both the pointer and the flag value. + This solution is portable to machines of different word sizes, both smaller and larger than 32 bits, + working even when pointers cannot be represented in any integer type. + + .. code-block:: rust + + struct PtrFlag { + pointer:* const u32, + flag:u32 + } + + fn f2 (flag:u32, ptr:* const u32) { + let ptrflag = PtrFlag { + pointer: ptr, + flag: flag + }; + /* ... */ + } + diff --git a/src/conf.py b/src/conf.py index a656c28..224926e 100644 --- a/src/conf.py +++ b/src/conf.py @@ -99,6 +99,10 @@ dict(name="readability", description="Readability-related guideline"), dict(name="reduce-human-error", description="Reducing human error guideline"), dict(name="numerics", description="Numerics-related guideline"), + dict(name="undefined-behavior", description="Numerics-related guideline"), + + dict(name="defect", description="Guideline associated with the language-subset profile"), + dict(name="subset", description="Guideline associated with the defect-prevention profile"), ] needs_categories = [ diff --git a/src/process/style-guideline.rst b/src/process/style-guideline.rst index 918c59b..f6b0b2d 100644 --- a/src/process/style-guideline.rst +++ b/src/process/style-guideline.rst @@ -457,6 +457,9 @@ than the current guideline. ``compliant_example`` ===================== +A compliant example **MAY** be omitted when the guideline forbids an action entirely, i.e. there +is no compliant way to achieve the goal of the non-compliant code. + :: .. compliant_example:: From 66fe8afb3c95141766e0c46c3b2c38ab251f3230 Mon Sep 17 00:00:00 2001 From: Alex Celeste Date: Wed, 9 Jul 2025 00:58:35 +0100 Subject: [PATCH 4/6] apply reviewer feedback --- src/coding-guidelines/expressions.rst | 79 +++++++++++++++------------ 1 file changed, 43 insertions(+), 36 deletions(-) diff --git a/src/coding-guidelines/expressions.rst b/src/coding-guidelines/expressions.rst index baf21b4..6bd0b71 100644 --- a/src/coding-guidelines/expressions.rst +++ b/src/coding-guidelines/expressions.rst @@ -115,14 +115,15 @@ Expressions Although some conversions are lossless, others are not symmetrical. Instead of relying on either a defined lossy behaviour or risking loss of precision, the code can communicate intent by using ``Into`` or ``From`` and ``TryInto`` or ``TryFrom`` to signal which conversions are intended to perfectly preserve the original - value, and which are intended to be fallible. + 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 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::mem::transmute`` will communicate the intent to perform + If a conversion in this direction is needed, :std:``std::mem::transmute`` will communicate the intent to perform an unsafe operation. .. non_compliant_example:: @@ -135,9 +136,9 @@ Expressions .. code-block:: rust - fn f1 (x:u16, y:i32, z:u64, w:u8) { + fn f1(x: u16, y: i32, z: u64, w: u8) { let a = w as char; // non-compliant - let b = y as u32; // non-compliant - changes value range + let b = y as u32; // non-compliant - changes value range, converting negative values let c = x as i64; // non-compliant - could use .into() let d = y as f32; // non-compliant - lossy @@ -146,13 +147,13 @@ Expressions let g = e as i64; // non-compliant - lossy despite object size - 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 p2 = a1 as * const u32; // non-compliant - prefer transmute - let p3 = a2 as * const u32; // non-compliant, and probably invalid + let p3 = a2 as * const u32; // non-compliant (and most likely not in a valid address range) } .. compliant_example:: @@ -167,39 +168,42 @@ Expressions .. code-block:: rust - fn f2 (x:u16, y:i32, z:u64, w:u8) { - let a:char = w.into (); - let b:Result = y.try_into (); // produce an error on range clip - let c:i64 = x.into (); + fn f2(x: u16, y: i32, z: u64, w: u8) { + let a: char = w.into(); + let b: Result = y.try_into(); // produce an error on range clip + let c: i64 = x.into(); - let d = f32::from (x); // u16 is within range, u32 is not - let e = f64::from (d); - // let f = f32::from (e); // no From exists + let d = f32::from(x); // u16 is within range, u32 is not + let e = f64::from(d); + // let f = f32::from(e); // no From exists // let g = ... // no From exists - let h:u32 = 0; - let p1:* const u32 = &h; + 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 + 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 - let p2:* const u32 = std::mem::transmute (a1); // OK - let p3:* const u32 = std::mem::transmute (a1); // OK + let p2: * const u32 = std::mem::transmute(a1); // OK + let p3: * const u32 = std::mem::transmute(a1); // OK } unsafe { - let f1:f64 = std::mem::transmute (z); // does something entirely different + // 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 = std::mem::transmute(z); } } .. guideline:: An integer shall not be converted to a pointer :id: gui_PM8Vpf7lZ51U - :category: required + :category: :status: draft :release: :fls: fls_59mpteeczzo @@ -210,8 +214,8 @@ Expressions The ``as`` operator shall not be used with an expression of numeric type as the left operand, and any pointer type as the right operand. - ``std::mem::transmute`` shall not be used with any numeric type (including floating tyoes) as the - argument to the ``Src`` parameter, and any pointer type as the argument to the ``Dst`` parameter. + :std:``std::mem::transmute`` shall not be used with any numeric type (including floating point types) + as the argument to the ``Src`` parameter, and any pointer type as the argument to the ``Dst`` parameter. .. rationale:: :id: rat_YqhEiWTj9z6L @@ -226,6 +230,9 @@ Expressions the size of a pointer, which may lead to unexpected results if the address computation was originally performed in a differently-sized address space. + While ``as`` can notionally be used to create a null pointer, the functions + ``core::ptr::null`` and ``core::ptr::null_mut`` are the more idiomatic way to do this. + .. non_compliant_example:: :id: non_compl_ex_0ydPk7VENSrA :status: draft @@ -235,23 +242,23 @@ Expressions .. code-block:: rust - fn f1 (x:u16, y:i32, z:u64, w:usize) { + fn f1(x: u16, y: i32, z: u64, w: usize) { let p1 = x as * const u32; // not compliant let p2 = y as * const u32; // not compliant let p3 = z as * const u32; // not compliant let p4 = w as * const u32; // not compliant despite being the right size - let f:f64 = 10.0; + let f: f64 = 10.0; // let p5 = f as * const u32; // not valid unsafe { - // let p5:* const u32 = std::mem::transmute (x); // not valid - // let p6:* const u32 = std::mem::transmute (y); // not valid + // let p5: * const u32 = std::mem::transmute(x); // not valid + // let p6: * const u32 = std::mem::transmute(y); // not valid - let p7:* const u32 = std::mem::transmute (z); // not compliant - let p8:* const u32 = std::mem::transmute (w); // not compliant + let p7: * const u32 = std::mem::transmute(z); // not compliant + let p8: * const u32 = std::mem::transmute(w); // not compliant - let p9:* const u32 = std::mem::transmute (f); // not compliant, and very strange + let p9: * const u32 = std::mem::transmute(f); // not compliant, and very strange } } @@ -264,7 +271,7 @@ Expressions .. guideline:: An integer shall not be converted to an invalid pointer :id: gui_iv9yCMHRgpE0 - :category: required + :category: :status: draft :release: :fls: fls_9wgldua1u8yt @@ -293,7 +300,7 @@ Expressions .. code-block:: rust - fn f1 (flag:u32, ptr:* const u32) { + fn f1(flag: u32, ptr: * const u32) { /* ... */ let mut rep = ptr as usize; rep = (rep & 0x7fffff) | ((flag as usize) << 23); @@ -311,11 +318,11 @@ Expressions .. code-block:: rust struct PtrFlag { - pointer:* const u32, - flag:u32 + pointer: * const u32, + flag: u32 } - fn f2 (flag:u32, ptr:* const u32) { + fn f2(flag: u32, ptr: * const u32) { let ptrflag = PtrFlag { pointer: ptr, flag: flag From 065ed53b2c4cc0cc21d50840ba8d40cff0561cc5 Mon Sep 17 00:00:00 2001 From: Alex Celeste Date: Wed, 9 Jul 2025 01:06:14 +0100 Subject: [PATCH 5/6] apply reviewer feedback --- src/process/style-guideline.rst | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/process/style-guideline.rst b/src/process/style-guideline.rst index 6d1843a..c32fd1d 100644 --- a/src/process/style-guideline.rst +++ b/src/process/style-guideline.rst @@ -306,6 +306,8 @@ the scope of the guideline. Guideline content consists of an Amplification and any Exceptions, which are normative, supported by a Rationale and examples, which are not normative. +The justification extended explanation for the guideline **SHOULD** appear in the non-normative +Rationale rather than in the normative content. Amplification ^^^^^^^^^^^^^ @@ -430,10 +432,10 @@ The ``non_compliant_example`` is neither normative, nor exhaustive. ``guideline` ``non_compliant_example`` Code Explanation ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The Code Explanation of a `non_compliant_example` **MUST** explain in prose the reason the guideline +The Code Explanation of a ``non_compliant_example`` **MUST** explain in prose the reason the guideline when not applied results in code which is undesirable. -The Code Explanation of a `non_compliant_example` **MAY** be a simple explanation no longer than +The Code Explanation of a ``non_compliant_example`` **MAY** be a simple explanation no longer than a sentence. The Code Explanation of a ``non_compliant_example`` **SHOULD** be no longer than necessary to explain @@ -457,8 +459,11 @@ than the current guideline. ``compliant_example`` ===================== -A compliant example **MAY** be omitted when the guideline forbids an action entirely, i.e. there -is no compliant way to achieve the goal of the non-compliant code. +A compliant example **SHOULD** be omitted when the guideline forbids an action entirely, i.e. there +is no compliant way to achieve the goal of the non-compliant code, rather than giving an irrelevant +example (or encouraging strange workarounds). +When there is a clear and idiomatic compliant way to achieve the goal, a compliant example **SHOULD** +be provided after the corresponding non-compliant example. :: From af787c72ddb9a9be378f7dbf1984bdc8449e03a9 Mon Sep 17 00:00:00 2001 From: Alex Celeste Date: Tue, 15 Jul 2025 17:34:09 +0100 Subject: [PATCH 6/6] apply review comment: annotate core as well as std, and only use single ticks --- src/coding-guidelines/expressions.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/coding-guidelines/expressions.rst b/src/coding-guidelines/expressions.rst index 6bd0b71..37cc7eb 100644 --- a/src/coding-guidelines/expressions.rst +++ b/src/coding-guidelines/expressions.rst @@ -17,14 +17,14 @@ Expressions :scope: module :tags: readability, reduce-human-error - Code must not rely on Rust's type inference when doing explicit pointer casts via ``var as Type`` or ``core::mem::transmute``. - Instead, explicitly specify the complete target type in the ``as`` expression or ``core::mem::transmute`` call expression. + Code must not rely on Rust's type inference when doing explicit pointer casts via ``var as Type`` or :std:`core::mem::transmute`. + Instead, explicitly specify the complete target type in the ``as`` expression or :std:`core::mem::transmute` call expression. .. rationale:: :id: rat_h8LdJQ1MNKu9 :status: draft - ``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. + ``var as Type`` casts and :std:`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. 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. Raw pointers have a variety of invariants to manually keep track of. @@ -123,7 +123,7 @@ Expressions 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 + If a conversion in this direction is needed, :std:`std::mem::transmute` will communicate the intent to perform an unsafe operation. .. non_compliant_example:: @@ -214,7 +214,7 @@ Expressions The ``as`` operator shall not be used with an expression of numeric type as the left operand, and any pointer type as the right operand. - :std:``std::mem::transmute`` shall not be used with any numeric type (including floating point types) + :std:`std::mem::transmute` shall not be used with any numeric type (including floating point types) as the argument to the ``Src`` parameter, and any pointer type as the argument to the ``Dst`` parameter. .. rationale:: @@ -231,7 +231,7 @@ Expressions originally performed in a differently-sized address space. While ``as`` can notionally be used to create a null pointer, the functions - ``core::ptr::null`` and ``core::ptr::null_mut`` are the more idiomatic way to do this. + :std:`core::ptr::null` and :std:`core::ptr::null_mut` are the more idiomatic way to do this. .. non_compliant_example:: :id: non_compl_ex_0ydPk7VENSrA