Skip to content

Commit a028651

Browse files
committed
fix: missing_const_for_fn FP on unstable const traits
1 parent 81643e2 commit a028651

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

0 commit comments

Comments
 (0)