Skip to content

overflowing_literals lint behaves strangely with repeated negation #158295

Description

@theemathas

Code

#![allow(arithmetic_overflow)]

pub fn zero() {
    // lint
    let _ = 128_i8;
}

pub fn one() {
    // no lint
    let _ = -128_i8;
}

pub fn two() {
    // lint
    let _ = -(-128_i8);
}

pub fn three() {
    // no lint
    let _ = -(-(-128_i8));
}

Current output

error: literal out of range for `i8`
 --> src/lib.rs:5:13
  |
5 |     let _ = 128_i8;
  |             ^^^^^^
  |
  = note: the literal `128_i8` does not fit into the type `i8` whose range is `-128..=127`
  = help: consider using the type `u8` instead
  = note: `#[deny(overflowing_literals)]` on by default

error: literal out of range for `i8`
  --> src/lib.rs:15:16
   |
15 |     let _ = -(-128_i8);
   |                ^^^^^^
   |
   = note: the literal `128_i8` does not fit into the type `i8` whose range is `-128..=127`
   = help: consider using the type `u8` instead

Desired output

error: literal out of range for `i8`
 --> src/lib.rs:5:13
  |
5 |     let _ = 128_i8;
  |             ^^^^^^
  |
  = note: the literal `128_i8` does not fit into the type `i8` whose range is `-128..=127`
  = help: consider using the type `u8` instead
  = note: `#[deny(overflowing_literals)]` on by default

Rationale and extra context

The overflowing_literal lint is, I believe, supposed to consider the literal and not the surrounding context when deciding whether to lint. This is in contrast to the arithmetic_overflow lint, which only considers code that executes at run time, which excludes the negation inside a literal.

According to the reference, a negation in front of an integer does not result in an overflow. I think of this as: a negation, and only one negation, in front of an integer, is "part of" the integer. Therefore, the overflowing_literal lint should consider that when linting. It should not consider the second or third negation.

Therefore, I think that overflowing_literals should only lint on 128_i8 when there is no preceding negation at all. This is in contrast to the current behavior, which lints on 128_i8 preceded by an even number of negations.

Other cases

Rust Version

Reproducible on the playground with version 1.98.0-nightly (2026-06-22 4429659e4745016bd3f2)

Anything else?

No response

Metadata

Metadata

Assignees

Labels

A-diagnosticsArea: Messages for errors, warnings, and lintsA-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.L-overflowing_literalsLint: overflowing_literalsT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-langRelevant to the language team

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions