Skip to content

Commit eafef84

Browse files
authored
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
2 parents 716eadf + 43b7d87 commit eafef84

File tree

4 files changed

+99
-2
lines changed

4 files changed

+99
-2
lines changed

clippy_utils/src/qualify_min_const_fn.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use rustc_middle::mir::{
1818
};
1919
use rustc_middle::traits::{BuiltinImplSource, ImplSource, ObligationCause};
2020
use rustc_middle::ty::adjustment::PointerCoercion;
21-
use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt};
21+
use rustc_middle::ty::{self, GenericArgKind, Instance, TraitRef, Ty, TyCtxt};
2222
use rustc_span::Span;
2323
use rustc_span::symbol::sym;
2424
use rustc_trait_selection::traits::{ObligationCtxt, SelectionContext};
@@ -349,7 +349,15 @@ fn check_terminator<'tcx>(
349349
}
350350
| TerminatorKind::TailCall { func, args, fn_span: _ } => {
351351
let fn_ty = func.ty(body, cx.tcx);
352-
if let ty::FnDef(fn_def_id, _) = *fn_ty.kind() {
352+
if let ty::FnDef(fn_def_id, fn_substs) = fn_ty.kind() {
353+
// FIXME: when analyzing a function with generic parameters, we may not have enough information to
354+
// resolve to an instance. However, we could check if a host effect predicate can guarantee that
355+
// this can be made a `const` call.
356+
let fn_def_id = match Instance::try_resolve(cx.tcx, cx.typing_env(), *fn_def_id, fn_substs) {
357+
Ok(Some(fn_inst)) => fn_inst.def_id(),
358+
Ok(None) => return Err((span, format!("cannot resolve instance for {func:?}").into())),
359+
Err(_) => return Err((span, format!("error during instance resolution of {func:?}").into())),
360+
};
353361
if !is_stable_const_fn(cx, fn_def_id, msrv) {
354362
return Err((
355363
span,
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#![feature(const_trait_impl)]
2+
#![warn(clippy::missing_const_for_fn)]
3+
4+
// Reduced test case from https://github.com/rust-lang/rust-clippy/issues/14658
5+
6+
#[const_trait]
7+
trait ConstTrait {
8+
fn method(self);
9+
}
10+
11+
impl ConstTrait for u32 {
12+
fn method(self) {}
13+
}
14+
15+
impl const ConstTrait for u64 {
16+
fn method(self) {}
17+
}
18+
19+
fn cannot_be_const() {
20+
0u32.method();
21+
}
22+
23+
//~v missing_const_for_fn
24+
const fn can_be_const() {
25+
0u64.method();
26+
}
27+
28+
// False negative, see FIXME comment in `clipy_utils::qualify_min_const`
29+
fn could_be_const_but_does_not_trigger<T>(t: T)
30+
where
31+
T: const ConstTrait,
32+
{
33+
t.method();
34+
}
35+
36+
fn main() {}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#![feature(const_trait_impl)]
2+
#![warn(clippy::missing_const_for_fn)]
3+
4+
// Reduced test case from https://github.com/rust-lang/rust-clippy/issues/14658
5+
6+
#[const_trait]
7+
trait ConstTrait {
8+
fn method(self);
9+
}
10+
11+
impl ConstTrait for u32 {
12+
fn method(self) {}
13+
}
14+
15+
impl const ConstTrait for u64 {
16+
fn method(self) {}
17+
}
18+
19+
fn cannot_be_const() {
20+
0u32.method();
21+
}
22+
23+
//~v missing_const_for_fn
24+
fn can_be_const() {
25+
0u64.method();
26+
}
27+
28+
// False negative, see FIXME comment in `clipy_utils::qualify_min_const`
29+
fn could_be_const_but_does_not_trigger<T>(t: T)
30+
where
31+
T: const ConstTrait,
32+
{
33+
t.method();
34+
}
35+
36+
fn main() {}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error: this could be a `const fn`
2+
--> tests/ui/missing_const_for_fn/const_trait.rs:24:1
3+
|
4+
LL | / fn can_be_const() {
5+
LL | | 0u64.method();
6+
LL | | }
7+
| |_^
8+
|
9+
= note: `-D clippy::missing-const-for-fn` implied by `-D warnings`
10+
= help: to override `-D warnings` add `#[allow(clippy::missing_const_for_fn)]`
11+
help: make the function `const`
12+
|
13+
LL | const fn can_be_const() {
14+
| +++++
15+
16+
error: aborting due to 1 previous error
17+

0 commit comments

Comments
 (0)