rust-lang / rust-lang/rust-clippy

arithmetic_side_effects doesn't fire in non-const function located inside of const definition

Open
#13,845 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

C-bug I-false-negative
Dominant language
Rust
Stars
13.5k
Forks
2.2k
Avg merge
2d 10h
Merged PRs (30d)
32

Description

Summary

arithmetic_side_effects doesn't fire in non-const function located inside of const definition. (See below for why it is important for me.)

Lint Name

arithmetic_side_effects

Reproducer

I tried this code:

// Add alloy 0.8.1 as a dependency

#![deny(clippy::arithmetic_side_effects)]

const _: () = {
    fn f() {
        let _ = alloy::primitives::U256::from(1) + alloy::primitives::U256::from(2);
    }
};

I expected to see this happen: arithmetic_side_effects should fire.

Instead, this happened: nothing fired.

Note: it is documented that arithmetic_side_effects will not fire in const contexts. But this is not const context.

Okay, now let me describe, why this is important and how this actually breaks my workflow.

Okay, so I use crate alloy for managing my money. alloy provides type U256 for dealing with monetary values. U256 is borrowed from another crate ruint. I don't want silent overflows, I want panics on overflow, so I filled bug to ruint, hoping they will add panics-on-overflow: https://github.com/recmo/uint/issues/408 . But a developer said that they don't want to change the behavior, so I have to resort to some hacks on my side. So I decided to use clippy's lint arithmetic_side_effects to eliminate arithmetic operations with U256 in my code and use checked_add and similar instead.

But I'm not sure that arithmetic_side_effects will always work. It is possible that it will change its behavior in some next version of clippy. Notably, arithmetic_side_effects currently doesn't fire on Wrapping. It is possible that following same logic authors of clippy will disable this lint for U256, too, because U256 has wrapping behavior, too! So, I need some way to be sure that arithmetic_side_effects will always fire in the future. So, I decided to use #[expect].

So, I put this function to my code:

#![deny(clippy::arithmetic_side_effects)]

// ...

fn f() {
  #[expect(clippy::arithmetic_side_effects)]
  {
    let _ = alloy::primitives::U256::from(1) + alloy::primitives::U256::from(2);
  }
}

Okay, this works, but has some problems. First, f is not used, so it fires warning about dead code. Second, I need to invent new name for every such function, despite I don't plan to call them. And finally, such functions pollute global name space.

It is possible to put this function to some module, but then the problem reappears again, because now I have to invent some name for this module, despite I don't plan to use it.

So, I decided to use const _: () trick:

#![deny(clippy::arithmetic_side_effects)]

#[expect(clippy::arithmetic_side_effects)]
const _: () = { alloy::primitives::U256::from(1) + alloy::primitives::U256::from(2); };

But this is const context. And arithmetic_side_effects is documented not to fire in the const contexts. Moreover, this code doesn't even compile. So, I did this:

#![deny(clippy::arithmetic_side_effects)]

const _: () = {
    fn f() {
        #[expect(clippy::arithmetic_side_effects)]
        {
            let _ = alloy::primitives::U256::from(1) + alloy::primitives::U256::from(2);
        }
    }
};

Unfortunately, this code gives message this lint expectation is unfulfilled. It seems this non-const context is treated as const by clippy. This is a bug, and thus I reported it

Version
rustc 1.85.0-nightly (a224f3807 2024-12-09)
binary: rustc
commit-hash: a224f3807e58afc9353510f1d556c607d367545d
commit-date: 2024-12-09
host: x86_64-unknown-linux-gnu
release: 1.85.0-nightly
LLVM version: 19.1.5

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the arithmetic_side_effects lint and run the Rust reproducer showing a non-const function nested inside a const definition. Trace how the lint handles this context, then add coverage so the arithmetic operation is reported and its #[expect] is fulfilled there.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
devtools
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.