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
This commit is contained in:
commit
eafef84736
4 changed files with 99 additions and 2 deletions
|
|
@ -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,
|
||||
|
|
|
|||
36
tests/ui/missing_const_for_fn/const_trait.fixed
Normal file
36
tests/ui/missing_const_for_fn/const_trait.fixed
Normal file
|
|
@ -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() {}
|
||||
36
tests/ui/missing_const_for_fn/const_trait.rs
Normal file
36
tests/ui/missing_const_for_fn/const_trait.rs
Normal file
|
|
@ -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() {}
|
||||
17
tests/ui/missing_const_for_fn/const_trait.stderr
Normal file
17
tests/ui/missing_const_for_fn/const_trait.stderr
Normal file
|
|
@ -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
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue