diff options
| author | Philipp Hansch <dev@phansch.net> | 2019-08-25 15:44:22 +0200 |
|---|---|---|
| committer | Philipp Hansch <dev@phansch.net> | 2019-08-29 08:07:41 +0200 |
| commit | 1b185975544fcab53f9bd23a74cb0997e8f40607 (patch) | |
| tree | a63c78c580c45c76c1b0c3236202d6d8a27264fc | |
| parent | 4c8a941dafff56a2485258b85b33ba33e66f6258 (diff) | |
| download | rust-1b185975544fcab53f9bd23a74cb0997e8f40607.tar.gz rust-1b185975544fcab53f9bd23a74cb0997e8f40607.zip | |
Fix missing_const_for_fn false positive
We don't want to lint if any of the input parameters implement drop. (constant functions cannot evaluate destructors)
| -rw-r--r-- | clippy_lints/src/missing_const_for_fn.rs | 20 | ||||
| -rw-r--r-- | tests/ui/missing_const_for_fn/cant_be_const.rs | 22 | ||||
| -rw-r--r-- | tests/ui/missing_const_for_fn/could_be_const.rs | 15 |
3 files changed, 54 insertions, 3 deletions
diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 89398f82c9e..2f20aa9c683 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -1,10 +1,11 @@ -use crate::utils::{is_entrypoint_fn, span_lint, trait_ref_of_method}; +use crate::utils::{has_drop, is_entrypoint_fn, span_lint, trait_ref_of_method}; use rustc::hir; use rustc::hir::intravisit::FnKind; -use rustc::hir::{Body, Constness, FnDecl, HirId}; +use rustc::hir::{Body, Constness, FnDecl, HirId, HirVec}; use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintPass}; use rustc::{declare_lint_pass, declare_tool_lint}; use rustc_mir::transform::qualify_min_const_fn::is_min_const_fn; +use rustc_typeck::hir_ty_to_ty; use syntax_pos::Span; declare_clippy_lint! { @@ -94,7 +95,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingConstForFn { } }, FnKind::Method(_, sig, ..) => { - if trait_ref_of_method(cx, hir_id).is_some() || already_const(sig.header) { + if trait_ref_of_method(cx, hir_id).is_some() + || already_const(sig.header) + || method_accepts_dropable(cx, &sig.decl.inputs) + { return; } }, @@ -113,6 +117,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingConstForFn { } } +/// Returns true if any of the method parameters is a type that implements `Drop`. The method +/// can't be made const then, because `drop` can't be const-evaluated. +fn method_accepts_dropable(cx: &LateContext<'_, '_>, param_tys: &HirVec<hir::Ty>) -> bool { + // If any of the params are dropable, return true + param_tys.iter().any(|hir_ty| { + let ty_ty = hir_ty_to_ty(cx.tcx, hir_ty); + has_drop(cx, ty_ty) + }) +} + // We don't have to lint on something that's already `const` fn already_const(header: hir::FnHeader) -> bool { header.constness == Constness::Const 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 115cc954dc7..f367279906f 100644 --- a/tests/ui/missing_const_for_fn/cant_be_const.rs +++ b/tests/ui/missing_const_for_fn/cant_be_const.rs @@ -68,3 +68,25 @@ impl std::ops::Add for Point { Point(self.0 + other.0, self.1 + other.1) } } + +mod with_drop { + pub struct A; + pub struct B; + impl Drop for A { + fn drop(&mut self) {} + } + + impl A { + // This can not be const because the type implements `Drop`. + pub fn a(self) -> B { + B + } + } + + impl B { + // This can not be const because `a` implements `Drop`. + pub fn a(self, a: A) -> B { + B + } + } +} 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 139e64de1ff..9109d255ca7 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.rs +++ b/tests/ui/missing_const_for_fn/could_be_const.rs @@ -53,5 +53,20 @@ fn generic_arr<T: Copy>(t: [T; 1]) -> T { t[0] } +mod with_drop { + pub struct A; + pub struct B; + impl Drop for A { + fn drop(&mut self) {} + } + + impl B { + // This can be const, because `a` is passed by reference + pub fn b(self, a: &A) -> B { + B + } + } +} + // Should not be const fn main() {} |
