Skip to content

Commit 28a8a6a

Browse files
committed
Auto merge of #4450 - phansch:fix_const_fn_fp, r=flip1995
Fix missing_const_for_fn false positive We don't want to lint if the type of the method implements drop. (constant functions cannot evaluate destructors) changelog: Fix `missing_const_for_fn` false positive Fixes #4449
2 parents 888b736 + 5e1fdf9 commit 28a8a6a

File tree

4 files changed

+63
-4
lines changed

4 files changed

+63
-4
lines changed

clippy_lints/src/missing_const_for_fn.rs

+17-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
use crate::utils::{is_entrypoint_fn, span_lint, trait_ref_of_method};
1+
use crate::utils::{has_drop, is_entrypoint_fn, span_lint, trait_ref_of_method};
22
use rustc::hir;
33
use rustc::hir::intravisit::FnKind;
4-
use rustc::hir::{Body, Constness, FnDecl, HirId};
4+
use rustc::hir::{Body, Constness, FnDecl, HirId, HirVec};
55
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintPass};
66
use rustc::{declare_lint_pass, declare_tool_lint};
77
use rustc_mir::transform::qualify_min_const_fn::is_min_const_fn;
8+
use rustc_typeck::hir_ty_to_ty;
89
use syntax_pos::Span;
910

1011
declare_clippy_lint! {
@@ -94,7 +95,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingConstForFn {
9495
}
9596
},
9697
FnKind::Method(_, sig, ..) => {
97-
if trait_ref_of_method(cx, hir_id).is_some() || already_const(sig.header) {
98+
if trait_ref_of_method(cx, hir_id).is_some()
99+
|| already_const(sig.header)
100+
|| method_accepts_dropable(cx, &sig.decl.inputs)
101+
{
98102
return;
99103
}
100104
},
@@ -113,6 +117,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingConstForFn {
113117
}
114118
}
115119

120+
/// Returns true if any of the method parameters is a type that implements `Drop`. The method
121+
/// can't be made const then, because `drop` can't be const-evaluated.
122+
fn method_accepts_dropable(cx: &LateContext<'_, '_>, param_tys: &HirVec<hir::Ty>) -> bool {
123+
// If any of the params are dropable, return true
124+
param_tys.iter().any(|hir_ty| {
125+
let ty_ty = hir_ty_to_ty(cx.tcx, hir_ty);
126+
has_drop(cx, ty_ty)
127+
})
128+
}
129+
116130
// We don't have to lint on something that's already `const`
117131
fn already_const(header: hir::FnHeader) -> bool {
118132
header.constness == Constness::Const

tests/ui/missing_const_for_fn/cant_be_const.rs

+22
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,25 @@ impl std::ops::Add for Point {
6868
Point(self.0 + other.0, self.1 + other.1)
6969
}
7070
}
71+
72+
mod with_drop {
73+
pub struct A;
74+
pub struct B;
75+
impl Drop for A {
76+
fn drop(&mut self) {}
77+
}
78+
79+
impl A {
80+
// This can not be const because the type implements `Drop`.
81+
pub fn a(self) -> B {
82+
B
83+
}
84+
}
85+
86+
impl B {
87+
// This can not be const because `a` implements `Drop`.
88+
pub fn a(self, a: A) -> B {
89+
B
90+
}
91+
}
92+
}

tests/ui/missing_const_for_fn/could_be_const.rs

+15
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,20 @@ fn generic_arr<T: Copy>(t: [T; 1]) -> T {
5353
t[0]
5454
}
5555

56+
mod with_drop {
57+
pub struct A;
58+
pub struct B;
59+
impl Drop for A {
60+
fn drop(&mut self) {}
61+
}
62+
63+
impl B {
64+
// This can be const, because `a` is passed by reference
65+
pub fn b(self, a: &A) -> B {
66+
B
67+
}
68+
}
69+
}
70+
5671
// Should not be const
5772
fn main() {}

tests/ui/missing_const_for_fn/could_be_const.stderr

+9-1
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,13 @@ LL | | t
4949
LL | | }
5050
| |_^
5151

52-
error: aborting due to 6 previous errors
52+
error: this could be a const_fn
53+
--> $DIR/could_be_const.rs:65:9
54+
|
55+
LL | / pub fn b(self, a: &A) -> B {
56+
LL | | B
57+
LL | | }
58+
| |_________^
59+
60+
error: aborting due to 7 previous errors
5361

0 commit comments

Comments
 (0)