Skip to content

Commit 38d12a9

Browse files
committed
Auto merge of rust-lang#12681 - y21:issue12677, r=Jarcho
Let `qualify_min_const_fn` deal with drop terminators Fixes rust-lang#12677 The `method_accepts_droppable` check that was there seemed overly conservative. > 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. Accepting parameters that implement `Drop` should still be fine as long as the parameter isn't actually dropped, as is the case in the linked issue where the droppable is moved into the return place. This more accurate analysis ("is there a `drop` terminator") is already done by `qualify_min_const_fn` [here](https://github.com/rust-lang/rust-clippy/blob/f5e250180c342bb52808c9a934c962a8fe40afc7/clippy_utils/src/qualify_min_const_fn.rs#L298), so I don't think this additional check is really necessary? Fixing the other, second case in the linked issue was only slightly more involved, since `Vec::new()` is a function call that has the ability to panic, so there must be a `drop()` terminator for cleanup, however we should be able to freely ignore that. [Const checking ignores cleanup blocks](https://github.com/rust-lang/rust/blob/master/compiler/rustc_const_eval/src/transform/check_consts/check.rs#L382-L388), so we should, too? r? `@Jarcho` ---- changelog: [`missing_const_for_fn`]: continue linting on fns with parameters implementing `Drop` if they're not actually dropped
2 parents 740b72e + c3d3a3f commit 38d12a9

File tree

4 files changed

+65
-23
lines changed

4 files changed

+65
-23
lines changed

clippy_lints/src/missing_const_for_fn.rs

+2-19
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use clippy_config::msrvs::{self, Msrv};
22
use clippy_utils::diagnostics::span_lint;
33
use clippy_utils::qualify_min_const_fn::is_min_const_fn;
4-
use clippy_utils::ty::has_drop;
54
use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, trait_ref_of_method};
65
use rustc_hir as hir;
76
use rustc_hir::def_id::CRATE_DEF_ID;
@@ -121,10 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
121120
}
122121
},
123122
FnKind::Method(_, sig, ..) => {
124-
if trait_ref_of_method(cx, def_id).is_some()
125-
|| already_const(sig.header)
126-
|| method_accepts_droppable(cx, def_id)
127-
{
123+
if trait_ref_of_method(cx, def_id).is_some() || already_const(sig.header) {
128124
return;
129125
}
130126
},
@@ -151,26 +147,13 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
151147

152148
let mir = cx.tcx.optimized_mir(def_id);
153149

154-
if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, &self.msrv) {
155-
if cx.tcx.is_const_fn_raw(def_id.to_def_id()) {
156-
cx.tcx.dcx().span_err(span, err);
157-
}
158-
} else {
150+
if let Ok(()) = is_min_const_fn(cx.tcx, mir, &self.msrv) {
159151
span_lint(cx, MISSING_CONST_FOR_FN, span, "this could be a `const fn`");
160152
}
161153
}
162154
extract_msrv_attr!(LateContext);
163155
}
164156

165-
/// Returns true if any of the method parameters is a type that implements `Drop`. The method
166-
/// can't be made const then, because `drop` can't be const-evaluated.
167-
fn method_accepts_droppable(cx: &LateContext<'_>, def_id: LocalDefId) -> bool {
168-
let sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder();
169-
170-
// If any of the params are droppable, return true
171-
sig.inputs().iter().any(|&ty| has_drop(cx, ty))
172-
}
173-
174157
// We don't have to lint on something that's already `const`
175158
#[must_use]
176159
fn already_const(header: hir::FnHeader) -> bool {

clippy_utils/src/qualify_min_const_fn.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,13 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv)
4040
)?;
4141

4242
for bb in &*body.basic_blocks {
43-
check_terminator(tcx, body, bb.terminator(), msrv)?;
44-
for stmt in &bb.statements {
45-
check_statement(tcx, body, def_id, stmt, msrv)?;
43+
// Cleanup blocks are ignored entirely by const eval, so we can too:
44+
// https://github.com/rust-lang/rust/blob/1dea922ea6e74f99a0e97de5cdb8174e4dea0444/compiler/rustc_const_eval/src/transform/check_consts/check.rs#L382
45+
if !bb.is_cleanup {
46+
check_terminator(tcx, body, bb.terminator(), msrv)?;
47+
for stmt in &bb.statements {
48+
check_statement(tcx, body, def_id, stmt, msrv)?;
49+
}
4650
}
4751
}
4852
Ok(())

tests/ui/missing_const_for_fn/could_be_const.rs

+30
Original file line numberDiff line numberDiff line change
@@ -141,3 +141,33 @@ mod msrv {
141141
let _ = unsafe { bar.val };
142142
}
143143
}
144+
145+
mod issue12677 {
146+
pub struct Wrapper {
147+
pub strings: Vec<String>,
148+
}
149+
150+
impl Wrapper {
151+
#[must_use]
152+
pub fn new(strings: Vec<String>) -> Self {
153+
Self { strings }
154+
}
155+
156+
#[must_use]
157+
pub fn empty() -> Self {
158+
Self { strings: Vec::new() }
159+
}
160+
}
161+
162+
pub struct Other {
163+
pub text: String,
164+
pub vec: Vec<String>,
165+
}
166+
167+
impl Other {
168+
pub fn new(text: String) -> Self {
169+
let vec = Vec::new();
170+
Self { text, vec }
171+
}
172+
}
173+
}

tests/ui/missing_const_for_fn/could_be_const.stderr

+26-1
Original file line numberDiff line numberDiff line change
@@ -130,5 +130,30 @@ LL | | let _ = unsafe { bar.val };
130130
LL | | }
131131
| |_____^
132132

133-
error: aborting due to 14 previous errors
133+
error: this could be a `const fn`
134+
--> tests/ui/missing_const_for_fn/could_be_const.rs:152:9
135+
|
136+
LL | / pub fn new(strings: Vec<String>) -> Self {
137+
LL | | Self { strings }
138+
LL | | }
139+
| |_________^
140+
141+
error: this could be a `const fn`
142+
--> tests/ui/missing_const_for_fn/could_be_const.rs:157:9
143+
|
144+
LL | / pub fn empty() -> Self {
145+
LL | | Self { strings: Vec::new() }
146+
LL | | }
147+
| |_________^
148+
149+
error: this could be a `const fn`
150+
--> tests/ui/missing_const_for_fn/could_be_const.rs:168:9
151+
|
152+
LL | / pub fn new(text: String) -> Self {
153+
LL | | let vec = Vec::new();
154+
LL | | Self { text, vec }
155+
LL | | }
156+
| |_________^
157+
158+
error: aborting due to 17 previous errors
134159

0 commit comments

Comments
 (0)