about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_utils/src/qualify_min_const_fn.rs12
-rw-r--r--tests/ui/missing_const_for_fn/const_trait.fixed36
-rw-r--r--tests/ui/missing_const_for_fn/const_trait.rs36
-rw-r--r--tests/ui/missing_const_for_fn/const_trait.stderr17
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
+