Skip to content

Commit 1e5237f

Browse files
authored
fix: missing_const_for_fn FP on unstable const traits (#14294)
Closes #14020 Closes #14290 Closes #14091 Add checks for unstable const traits. changelog: [`missing_const_for_fn`] fix FP on unstable const traits
2 parents d1d0fee + a028651 commit 1e5237f

File tree

2 files changed

+112
-16
lines changed

2 files changed

+112
-16
lines changed

clippy_utils/src/qualify_min_const_fn.rs

+24-16
Original file line numberDiff line numberDiff line change
@@ -395,24 +395,32 @@ fn check_terminator<'tcx>(
395395

396396
fn is_stable_const_fn(cx: &LateContext<'_>, def_id: DefId, msrv: Msrv) -> bool {
397397
cx.tcx.is_const_fn(def_id)
398-
&& cx.tcx.lookup_const_stability(def_id).is_none_or(|const_stab| {
399-
if let rustc_attr_parsing::StabilityLevel::Stable { since, .. } = const_stab.level {
400-
// Checking MSRV is manually necessary because `rustc` has no such concept. This entire
401-
// function could be removed if `rustc` provided a MSRV-aware version of `is_stable_const_fn`.
402-
// as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262.
398+
&& cx
399+
.tcx
400+
.lookup_const_stability(def_id)
401+
.or_else(|| {
402+
cx.tcx
403+
.trait_of_item(def_id)
404+
.and_then(|trait_def_id| cx.tcx.lookup_const_stability(trait_def_id))
405+
})
406+
.is_none_or(|const_stab| {
407+
if let rustc_attr_parsing::StabilityLevel::Stable { since, .. } = const_stab.level {
408+
// Checking MSRV is manually necessary because `rustc` has no such concept. This entire
409+
// function could be removed if `rustc` provided a MSRV-aware version of `is_stable_const_fn`.
410+
// as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262.
403411

404-
let const_stab_rust_version = match since {
405-
StableSince::Version(version) => version,
406-
StableSince::Current => RustcVersion::CURRENT,
407-
StableSince::Err => return false,
408-
};
412+
let const_stab_rust_version = match since {
413+
StableSince::Version(version) => version,
414+
StableSince::Current => RustcVersion::CURRENT,
415+
StableSince::Err => return false,
416+
};
409417

410-
msrv.meets(cx, const_stab_rust_version)
411-
} else {
412-
// Unstable const fn, check if the feature is enabled.
413-
cx.tcx.features().enabled(const_stab.feature) && msrv.current(cx).is_none()
414-
}
415-
})
418+
msrv.meets(cx, const_stab_rust_version)
419+
} else {
420+
// Unstable const fn, check if the feature is enabled.
421+
cx.tcx.features().enabled(const_stab.feature) && msrv.current(cx).is_none()
422+
}
423+
})
416424
}
417425

418426
fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>) -> bool {

tests/ui/missing_const_for_fn/cant_be_const.rs

+88
Original file line numberDiff line numberDiff line change
@@ -218,3 +218,91 @@ mod with_ty_alias {
218218
fn mut_add(x: &mut i32) {
219219
*x += 1;
220220
}
221+
222+
#[clippy::msrv = "1.87"]
223+
mod issue14020 {
224+
use std::ops::Add;
225+
226+
fn f<T: Add>(a: T, b: T) -> <T as Add>::Output {
227+
a + b
228+
}
229+
}
230+
231+
#[clippy::msrv = "1.87"]
232+
mod issue14290 {
233+
use std::ops::{Deref, DerefMut};
234+
235+
struct Wrapper<T> {
236+
t: T,
237+
}
238+
239+
impl<T> Deref for Wrapper<T> {
240+
type Target = T;
241+
242+
fn deref(&self) -> &Self::Target {
243+
&self.t
244+
}
245+
}
246+
impl<T> DerefMut for Wrapper<T> {
247+
fn deref_mut(&mut self) -> &mut Self::Target {
248+
&mut self.t
249+
}
250+
}
251+
252+
struct Example(bool);
253+
254+
fn do_something(mut a: Wrapper<Example>) {
255+
a.0 = !a.0;
256+
}
257+
258+
pub struct Stream(Vec<u8>);
259+
260+
impl Stream {
261+
pub fn bytes(&self) -> &[u8] {
262+
&self.0
263+
}
264+
}
265+
}
266+
267+
#[clippy::msrv = "1.87"]
268+
mod issue14091 {
269+
use std::mem::ManuallyDrop;
270+
271+
struct BucketSlotGuard<'a> {
272+
id: u32,
273+
free_list: &'a mut Vec<u32>,
274+
}
275+
276+
impl BucketSlotGuard<'_> {
277+
fn into_inner(self) -> u32 {
278+
let this = ManuallyDrop::new(self);
279+
this.id
280+
}
281+
}
282+
283+
use std::ops::{Deref, DerefMut};
284+
285+
struct Wrap<T>(T);
286+
287+
impl<T> Deref for Wrap<T> {
288+
type Target = T;
289+
fn deref(&self) -> &T {
290+
&self.0
291+
}
292+
}
293+
294+
impl<T> DerefMut for Wrap<T> {
295+
fn deref_mut(&mut self) -> &mut T {
296+
&mut self.0
297+
}
298+
}
299+
300+
fn smart_two_field(v: &mut Wrap<(i32, i32)>) {
301+
let _a = &mut v.0;
302+
let _b = &mut v.1;
303+
}
304+
305+
fn smart_destructure(v: &mut Wrap<(i32, i32)>) {
306+
let (ref mut _head, ref mut _tail) = **v;
307+
}
308+
}

0 commit comments

Comments
 (0)