fix: assign_op_pattern FP on unstable const trait

This commit is contained in:
yanglsh 2025-05-25 02:02:11 +08:00
parent 1029572c19
commit 03af37302c
6 changed files with 90 additions and 15 deletions

View file

@ -1,8 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::Msrv;
use clippy_utils::qualify_min_const_fn::is_stable_const_fn;
use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::implements_trait;
use clippy_utils::visitors::for_each_expr_without_closures;
use clippy_utils::{binop_traits, eq_expr_value, trait_ref_of_method};
use clippy_utils::{binop_traits, eq_expr_value, is_in_const_context, trait_ref_of_method};
use core::ops::ControlFlow;
use rustc_errors::Applicability;
use rustc_hir as hir;
@ -19,6 +21,7 @@ pub(super) fn check<'tcx>(
expr: &'tcx hir::Expr<'_>,
assignee: &'tcx hir::Expr<'_>,
e: &'tcx hir::Expr<'_>,
msrv: Msrv,
) {
if let hir::ExprKind::Binary(op, l, r) = &e.kind {
let lint = |assignee: &hir::Expr<'_>, rhs: &hir::Expr<'_>| {
@ -40,6 +43,15 @@ pub(super) fn check<'tcx>(
return;
}
}
// Skip if the trait is not stable in const contexts
if is_in_const_context(cx)
&& let Some(binop_id) = cx.tcx.associated_item_def_ids(trait_id).first()
&& !is_stable_const_fn(cx, *binop_id, msrv)
{
return;
}
span_lint_and_then(
cx,
ASSIGN_OP_PATTERN,

View file

@ -919,7 +919,7 @@ impl<'tcx> LateLintPass<'tcx> for Operators {
modulo_arithmetic::check(cx, e, bin_op, lhs, rhs, false);
},
ExprKind::Assign(lhs, rhs, _) => {
assign_op_pattern::check(cx, e, lhs, rhs);
assign_op_pattern::check(cx, e, lhs, rhs, self.msrv);
self_assignment::check(cx, e, lhs, rhs);
},
ExprKind::Unary(op, arg) => {

View file

@ -393,7 +393,8 @@ fn check_terminator<'tcx>(
}
}
fn is_stable_const_fn(cx: &LateContext<'_>, def_id: DefId, msrv: Msrv) -> bool {
/// Checks if the given `def_id` is a stable const fn, in respect to the given MSRV.
pub fn is_stable_const_fn(cx: &LateContext<'_>, def_id: DefId, msrv: Msrv) -> bool {
cx.tcx.is_const_fn(def_id)
&& cx
.tcx

View file

@ -1,5 +1,6 @@
#![allow(clippy::useless_vec)]
#![warn(clippy::assign_op_pattern)]
#![feature(const_trait_impl, const_ops)]
use core::num::Wrapping;
use std::ops::{Mul, MulAssign};
@ -73,3 +74,33 @@ impl MulAssign<i64> for Wrap {
*self = *self * rhs
}
}
mod issue14871 {
use std::ops::{Add, AddAssign};
pub trait Number: Copy + Add<Self, Output = Self> + AddAssign {
const ZERO: Self;
const ONE: Self;
}
#[const_trait]
pub trait NumberConstants {
fn constant(value: usize) -> Self;
}
impl<T> const NumberConstants for T
where
T: Number + ~const core::ops::Add,
{
fn constant(value: usize) -> Self {
let mut res = Self::ZERO;
let mut count = 0;
while count < value {
res = res + Self::ONE;
count += 1;
}
res
}
}
}

View file

@ -1,5 +1,6 @@
#![allow(clippy::useless_vec)]
#![warn(clippy::assign_op_pattern)]
#![feature(const_trait_impl, const_ops)]
use core::num::Wrapping;
use std::ops::{Mul, MulAssign};
@ -73,3 +74,33 @@ impl MulAssign<i64> for Wrap {
*self = *self * rhs
}
}
mod issue14871 {
use std::ops::{Add, AddAssign};
pub trait Number: Copy + Add<Self, Output = Self> + AddAssign {
const ZERO: Self;
const ONE: Self;
}
#[const_trait]
pub trait NumberConstants {
fn constant(value: usize) -> Self;
}
impl<T> const NumberConstants for T
where
T: Number + ~const core::ops::Add,
{
fn constant(value: usize) -> Self {
let mut res = Self::ZERO;
let mut count = 0;
while count < value {
res = res + Self::ONE;
count += 1;
}
res
}
}
}

View file

@ -1,5 +1,5 @@
error: manual implementation of an assign operation
--> tests/ui/assign_ops.rs:9:5
--> tests/ui/assign_ops.rs:10:5
|
LL | a = a + 1;
| ^^^^^^^^^ help: replace it with: `a += 1`
@ -8,67 +8,67 @@ LL | a = a + 1;
= help: to override `-D warnings` add `#[allow(clippy::assign_op_pattern)]`
error: manual implementation of an assign operation
--> tests/ui/assign_ops.rs:11:5
--> tests/ui/assign_ops.rs:12:5
|
LL | a = 1 + a;
| ^^^^^^^^^ help: replace it with: `a += 1`
error: manual implementation of an assign operation
--> tests/ui/assign_ops.rs:13:5
--> tests/ui/assign_ops.rs:14:5
|
LL | a = a - 1;
| ^^^^^^^^^ help: replace it with: `a -= 1`
error: manual implementation of an assign operation
--> tests/ui/assign_ops.rs:15:5
--> tests/ui/assign_ops.rs:16:5
|
LL | a = a * 99;
| ^^^^^^^^^^ help: replace it with: `a *= 99`
error: manual implementation of an assign operation
--> tests/ui/assign_ops.rs:17:5
--> tests/ui/assign_ops.rs:18:5
|
LL | a = 42 * a;
| ^^^^^^^^^^ help: replace it with: `a *= 42`
error: manual implementation of an assign operation
--> tests/ui/assign_ops.rs:19:5
--> tests/ui/assign_ops.rs:20:5
|
LL | a = a / 2;
| ^^^^^^^^^ help: replace it with: `a /= 2`
error: manual implementation of an assign operation
--> tests/ui/assign_ops.rs:21:5
--> tests/ui/assign_ops.rs:22:5
|
LL | a = a % 5;
| ^^^^^^^^^ help: replace it with: `a %= 5`
error: manual implementation of an assign operation
--> tests/ui/assign_ops.rs:23:5
--> tests/ui/assign_ops.rs:24:5
|
LL | a = a & 1;
| ^^^^^^^^^ help: replace it with: `a &= 1`
error: manual implementation of an assign operation
--> tests/ui/assign_ops.rs:30:5
--> tests/ui/assign_ops.rs:31:5
|
LL | s = s + "bla";
| ^^^^^^^^^^^^^ help: replace it with: `s += "bla"`
error: manual implementation of an assign operation
--> tests/ui/assign_ops.rs:35:5
--> tests/ui/assign_ops.rs:36:5
|
LL | a = a + Wrapping(1u32);
| ^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a += Wrapping(1u32)`
error: manual implementation of an assign operation
--> tests/ui/assign_ops.rs:38:5
--> tests/ui/assign_ops.rs:39:5
|
LL | v[0] = v[0] + v[1];
| ^^^^^^^^^^^^^^^^^^ help: replace it with: `v[0] += v[1]`
error: manual implementation of an assign operation
--> tests/ui/assign_ops.rs:51:5
--> tests/ui/assign_ops.rs:52:5
|
LL | buf = buf + cows.clone();
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `buf += cows.clone()`