diff --git a/Cargo.toml b/Cargo.toml index b539a862..b79fb6b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,11 +71,13 @@ indexing_slicing = "allow" # Too many false positives ... would be cool though match_bool = "allow" # Adds extra indentation and LOC. match_same_arms = "allow" # Collapses things that are conceptually unrelated to each other. must_use_candidate = "allow" # Useful for audit but many false positives. -# Whitelist the cast lints because sometimes casts are unavoidable. But -# every cast should contain a code comment! -cast_possible_truncation = "allow" -cast_possible_wrap = "allow" -cast_sign_loss = "allow" +# Casts are sometimes unavoidable, but every cast must be justified at the +# site with an `#[allow]` and a code comment explaining why it cannot lose +# information. Keep these enabled so that requirement is enforced rather +# than aspirational. +cast_possible_truncation = "warn" +cast_possible_wrap = "warn" +cast_sign_loss = "warn" # Exhaustive list of pedantic clippy lints assigning_clones = "warn" bool_to_int_with_if = "warn" diff --git a/codegen/src/main.rs b/codegen/src/main.rs index 926a8e5a..11844e6b 100644 --- a/codegen/src/main.rs +++ b/codegen/src/main.rs @@ -37,6 +37,9 @@ fn write_jet(jet: Elements, w: &mut W) -> io::Result<()> { write!(w, "pub fn {jet}(")?; let parameters = simplicityhl::jet::source_type(&jet); for (i, ty) in parameters.iter().enumerate() { + // Jets take a handful of parameters at most, so the index stays well + // inside `u8` (and inside the a-z range this names them from). + #[allow(clippy::cast_possible_truncation)] let identifier = (b'a' + i as u8) as char; if i == parameters.len() - 1 { write!(w, "{identifier}: {ty}")?; diff --git a/src/num.rs b/src/num.rs index 7df57905..8678505f 100644 --- a/src/num.rs +++ b/src/num.rs @@ -300,7 +300,13 @@ impl fmt::Display for U256 { // Divide by 10, starting at the most significant bytes for byte in &mut bytes { let value = carry * 256 + u32::from(*byte); - *byte = (value / 10) as u8; + // `carry` is the previous iteration's `value % 10`, so it is at + // most 9 and `value` is at most 9 * 256 + 255 = 2559. The + // quotient is therefore at most 255 and fits in a `u8`. + #[allow(clippy::cast_possible_truncation)] + { + *byte = (value / 10) as u8; + } carry = value % 10; if *byte != 0 { @@ -308,6 +314,8 @@ impl fmt::Display for U256 { } } + // `carry` is a remainder modulo 10, so it is at most 9. + #[allow(clippy::cast_possible_truncation)] digits.push(carry as u8); } @@ -335,7 +343,11 @@ impl FromStr for U256 { // Add to the least significant bytes first for byte in bytes.iter_mut().rev() { let value = u32::from(*byte) * 10 + carry; - *byte = (value % 256) as u8; + // A remainder modulo 256 is at most 255, so it fits in a `u8`. + #[allow(clippy::cast_possible_truncation)] + { + *byte = (value % 256) as u8; + } carry = value / 256; } if 0 < carry {