diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 44ec1bd08cf..ed5f46ddc8d 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -8,6 +8,7 @@ use rustc_hir::{self as hir, Body, Constness, FnDecl, GenericParamKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; +use rustc_middle::ty; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; @@ -131,6 +132,10 @@ fn check_fn( FnKind::Closure => return, } + if fn_inputs_has_impl_trait_ty(cx, def_id) { + return; + } + let hir_id = cx.tcx.local_def_id_to_hir_id(def_id); // Const fns are not allowed as methods in a trait. @@ -185,3 +190,15 @@ fn could_be_const_with_abi(cx: &LateContext<'_>, msrv: &Msrv, abi: Abi) -> bool _ => cx.tcx.features().const_extern_fn, } } + +/// Return `true` when the given `def_id` is a function that has `impl Trait` ty as one of +/// its parameter types. +fn fn_inputs_has_impl_trait_ty(cx: &LateContext<'_>, def_id: LocalDefId) -> bool { + let inputs = cx.tcx.fn_sig(def_id).instantiate_identity().inputs().skip_binder(); + inputs.iter().any(|input| { + matches!( + input.kind(), + ty::Alias(ty::AliasTyKind::Weak, alias_ty) if cx.tcx.type_of(alias_ty.def_id).skip_binder().is_impl_trait() + ) + }) +} diff --git a/tests/ui/missing_const_for_fn/cant_be_const.rs b/tests/ui/missing_const_for_fn/cant_be_const.rs index 952ff828363..2c6e1e92da0 100644 --- a/tests/ui/missing_const_for_fn/cant_be_const.rs +++ b/tests/ui/missing_const_for_fn/cant_be_const.rs @@ -7,6 +7,7 @@ #![warn(clippy::missing_const_for_fn)] #![feature(start)] +#![feature(type_alias_impl_trait)] extern crate helper; extern crate proc_macros; @@ -190,3 +191,11 @@ extern "C-unwind" fn c_unwind() {} extern "system" fn system() {} extern "system-unwind" fn system_unwind() {} } + +mod with_ty_alias { + type Foo = impl std::fmt::Debug; + + fn foo(_: Foo) { + let _: Foo = 1; + } +} diff --git a/tests/ui/missing_const_for_fn/could_be_const.fixed b/tests/ui/missing_const_for_fn/could_be_const.fixed index 572ca52439a..2311bd0acda 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.fixed +++ b/tests/ui/missing_const_for_fn/could_be_const.fixed @@ -186,3 +186,18 @@ mod issue12677 { } } } + +mod with_ty_alias { + trait FooTrait { + type Foo: std::fmt::Debug; + fn bar(_: Self::Foo) {} + } + impl FooTrait for () { + type Foo = i32; + } + // NOTE: When checking the type of a function param, make sure it is not an alias with + // `AliasTyKind::Projection` before calling `TyCtxt::type_of` to find out what the actual type + // is. Because the associate ty could have no default, therefore would cause ICE, as demostrated + // in this test. + const fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} +} diff --git a/tests/ui/missing_const_for_fn/could_be_const.rs b/tests/ui/missing_const_for_fn/could_be_const.rs index 4d19c4d7a48..cb7733ed382 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.rs +++ b/tests/ui/missing_const_for_fn/could_be_const.rs @@ -186,3 +186,18 @@ pub fn new(text: String) -> Self { } } } + +mod with_ty_alias { + trait FooTrait { + type Foo: std::fmt::Debug; + fn bar(_: Self::Foo) {} + } + impl FooTrait for () { + type Foo = i32; + } + // NOTE: When checking the type of a function param, make sure it is not an alias with + // `AliasTyKind::Projection` before calling `TyCtxt::type_of` to find out what the actual type + // is. Because the associate ty could have no default, therefore would cause ICE, as demostrated + // in this test. + fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} +} diff --git a/tests/ui/missing_const_for_fn/could_be_const.stderr b/tests/ui/missing_const_for_fn/could_be_const.stderr index ab36e0a281a..3cae5bcbc4a 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -261,5 +261,16 @@ help: make the function `const` LL | pub const fn new(text: String) -> Self { | +++++ -error: aborting due to 19 previous errors +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:202:5 + | +LL | fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | const fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} + | +++++ + +error: aborting due to 20 previous errors