diff options
| author | Jason Newcomb <jsnewcomb@pm.me> | 2025-06-03 14:03:51 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-06-03 14:03:51 +0000 |
| commit | eafef8473605f2f9fc5689ef4ba70fc590930d52 (patch) | |
| tree | bf18a2562e0ef4cb75520cceaabdf50da3fc7da3 | |
| parent | 716eadf674f84ba932a0d3b27c18cd07e9839925 (diff) | |
| parent | 43b7d87be1da241ba25d04b1c53508d88fb2eb25 (diff) | |
| download | rust-eafef8473605f2f9fc5689ef4ba70fc590930d52.tar.gz rust-eafef8473605f2f9fc5689ef4ba70fc590930d52.zip | |
`missing_const_for_fn`: consider constness of instance (#14759)
When determining when a function or method can be called from a `const` context, the determination must be made on the instance, not on the declaration. This makes a difference, for example, with `const_trait` traits whose implementations may or may not be `const`. changelog: [`missing_const_for_fn`]: when checking if a function or method can be called from a `const` context, look at the concrete implementation rather than at the trait definition Fixes rust-lang/rust-clippy#14658 r? @Jarcho
| -rw-r--r-- | clippy_utils/src/qualify_min_const_fn.rs | 12 | ||||
| -rw-r--r-- | tests/ui/missing_const_for_fn/const_trait.fixed | 36 | ||||
| -rw-r--r-- | tests/ui/missing_const_for_fn/const_trait.rs | 36 | ||||
| -rw-r--r-- | tests/ui/missing_const_for_fn/const_trait.stderr | 17 |
4 files changed, 99 insertions, 2 deletions
diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 5b4ec12cbec..cac3bb70d29 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -18,7 +18,7 @@ use rustc_middle::mir::{ }; use rustc_middle::traits::{BuiltinImplSource, ImplSource, ObligationCause}; use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, GenericArgKind, Instance, TraitRef, Ty, TyCtxt}; use rustc_span::Span; use rustc_span::symbol::sym; use rustc_trait_selection::traits::{ObligationCtxt, SelectionContext}; @@ -349,7 +349,15 @@ fn check_terminator<'tcx>( } | TerminatorKind::TailCall { func, args, fn_span: _ } => { let fn_ty = func.ty(body, cx.tcx); - if let ty::FnDef(fn_def_id, _) = *fn_ty.kind() { + if let ty::FnDef(fn_def_id, fn_substs) = fn_ty.kind() { + // FIXME: when analyzing a function with generic parameters, we may not have enough information to + // resolve to an instance. However, we could check if a host effect predicate can guarantee that + // this can be made a `const` call. + let fn_def_id = match Instance::try_resolve(cx.tcx, cx.typing_env(), *fn_def_id, fn_substs) { + Ok(Some(fn_inst)) => fn_inst.def_id(), + Ok(None) => return Err((span, format!("cannot resolve instance for {func:?}").into())), + Err(_) => return Err((span, format!("error during instance resolution of {func:?}").into())), + }; if !is_stable_const_fn(cx, fn_def_id, msrv) { return Err(( span, diff --git a/tests/ui/missing_const_for_fn/const_trait.fixed b/tests/ui/missing_const_for_fn/const_trait.fixed new file mode 100644 index 00000000000..7e0d4fccaae --- /dev/null +++ b/tests/ui/missing_const_for_fn/const_trait.fixed @@ -0,0 +1,36 @@ +#![feature(const_trait_impl)] +#![warn(clippy::missing_const_for_fn)] + +// Reduced test case from https://github.com/rust-lang/rust-clippy/issues/14658 + +#[const_trait] +trait ConstTrait { + fn method(self); +} + +impl ConstTrait for u32 { + fn method(self) {} +} + +impl const ConstTrait for u64 { + fn method(self) {} +} + +fn cannot_be_const() { + 0u32.method(); +} + +//~v missing_const_for_fn +const fn can_be_const() { + 0u64.method(); +} + +// False negative, see FIXME comment in `clipy_utils::qualify_min_const` +fn could_be_const_but_does_not_trigger<T>(t: T) +where + T: const ConstTrait, +{ + t.method(); +} + +fn main() {} diff --git a/tests/ui/missing_const_for_fn/const_trait.rs b/tests/ui/missing_const_for_fn/const_trait.rs new file mode 100644 index 00000000000..439da4622d7 --- /dev/null +++ b/tests/ui/missing_const_for_fn/const_trait.rs @@ -0,0 +1,36 @@ +#![feature(const_trait_impl)] +#![warn(clippy::missing_const_for_fn)] + +// Reduced test case from https://github.com/rust-lang/rust-clippy/issues/14658 + +#[const_trait] +trait ConstTrait { + fn method(self); +} + +impl ConstTrait for u32 { + fn method(self) {} +} + +impl const ConstTrait for u64 { + fn method(self) {} +} + +fn cannot_be_const() { + 0u32.method(); +} + +//~v missing_const_for_fn +fn can_be_const() { + 0u64.method(); +} + +// False negative, see FIXME comment in `clipy_utils::qualify_min_const` +fn could_be_const_but_does_not_trigger<T>(t: T) +where + T: const ConstTrait, +{ + t.method(); +} + +fn main() {} diff --git a/tests/ui/missing_const_for_fn/const_trait.stderr b/tests/ui/missing_const_for_fn/const_trait.stderr new file mode 100644 index 00000000000..b994b88fac6 --- /dev/null +++ b/tests/ui/missing_const_for_fn/const_trait.stderr @@ -0,0 +1,17 @@ +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/const_trait.rs:24:1 + | +LL | / fn can_be_const() { +LL | | 0u64.method(); +LL | | } + | |_^ + | + = note: `-D clippy::missing-const-for-fn` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_const_for_fn)]` +help: make the function `const` + | +LL | const fn can_be_const() { + | +++++ + +error: aborting due to 1 previous error + |
