Skip to content

Commit 5d2fe07

Browse files
committed
let_and_return: lint more cases in edition ≥ 2024
1 parent 657dda7 commit 5d2fe07

7 files changed

+923
-6
lines changed

clippy_lints/src/matches/significant_drop_in_scrutinee.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ impl<'a, 'tcx> SigDropChecker<'a, 'tcx> {
199199
return false;
200200
}
201201

202-
let result = match ty.kind() {
202+
match ty.kind() {
203203
rustc_middle::ty::Adt(adt, args) => {
204204
// if some field has significant drop,
205205
adt.all_fields()
@@ -223,9 +223,7 @@ impl<'a, 'tcx> SigDropChecker<'a, 'tcx> {
223223
rustc_middle::ty::Tuple(tys) => tys.iter().any(|ty| self.has_sig_drop_attr_impl(ty)),
224224
rustc_middle::ty::Array(ty, _) | rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr_impl(*ty),
225225
_ => false,
226-
};
227-
228-
result
226+
}
229227
}
230228
}
231229

clippy_lints/src/returns.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use rustc_middle::ty::adjustment::Adjust;
2121
use rustc_middle::ty::{self, GenericArgKind, Ty};
2222
use rustc_session::declare_lint_pass;
2323
use rustc_span::def_id::LocalDefId;
24+
use rustc_span::edition::Edition;
2425
use rustc_span::{BytePos, Pos, Span, sym};
2526
use std::borrow::Cow;
2627
use std::fmt::Display;
@@ -235,7 +236,7 @@ impl<'tcx> LateLintPass<'tcx> for Return {
235236
&& let Some(initexpr) = &local.init
236237
&& let PatKind::Binding(_, local_id, _, _) = local.pat.kind
237238
&& path_to_local_id(retexpr, local_id)
238-
&& !last_statement_borrows(cx, initexpr)
239+
&& (cx.sess().edition() >= Edition::Edition2024 || !last_statement_borrows(cx, initexpr))
239240
&& !initexpr.span.in_external_macro(cx.sess().source_map())
240241
&& !retexpr.span.in_external_macro(cx.sess().source_map())
241242
&& !local.span.from_expansion()
Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
//@revisions: edition2021 edition2024
2+
//@[edition2021] edition:2021
3+
//@[edition2024] edition:2024
4+
5+
#![allow(unused)]
6+
#![warn(clippy::let_and_return)]
7+
8+
use std::cell::RefCell;
9+
10+
fn test() -> i32 {
11+
let _y = 0; // no warning
12+
13+
5
14+
//~^ ERROR: returning the result of a `let` binding from a block
15+
//~| NOTE: `-D clippy::let-and-return` implied by `-D warnings`
16+
}
17+
18+
fn test_inner() -> i32 {
19+
if true {
20+
21+
5
22+
//~^ ERROR: returning the result of a `let` binding from a block
23+
} else {
24+
0
25+
}
26+
}
27+
28+
fn test_nowarn_1() -> i32 {
29+
let mut x = 5;
30+
x += 1;
31+
x
32+
}
33+
34+
fn test_nowarn_2() -> i32 {
35+
let x = 5;
36+
x + 1
37+
}
38+
39+
fn test_nowarn_3() -> (i32, i32) {
40+
// this should technically warn, but we do not compare complex patterns
41+
let (x, y) = (5, 9);
42+
(x, y)
43+
}
44+
45+
fn test_nowarn_4() -> i32 {
46+
// this should technically warn, but not b/c of clippy::let_and_return, but b/c of useless type
47+
let x: i32 = 5;
48+
x
49+
}
50+
51+
fn test_nowarn_5(x: i16) -> u16 {
52+
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
53+
let x = x as u16;
54+
x
55+
}
56+
57+
// False positive example
58+
trait Decode {
59+
fn decode<D: std::io::Read>(d: D) -> Result<Self, ()>
60+
where
61+
Self: Sized;
62+
}
63+
64+
macro_rules! tuple_encode {
65+
($($x:ident),*) => (
66+
impl<$($x: Decode),*> Decode for ($($x),*) {
67+
#[inline]
68+
#[allow(non_snake_case)]
69+
fn decode<D: std::io::Read>(mut d: D) -> Result<Self, ()> {
70+
// Shouldn't trigger lint
71+
Ok(($({let $x = Decode::decode(&mut d)?; $x }),*))
72+
}
73+
}
74+
);
75+
}
76+
77+
fn issue_3792() -> String {
78+
use std::io::{self, BufRead, Stdin};
79+
80+
let stdin = io::stdin();
81+
// `Stdin::lock` returns `StdinLock<'static>` so `line` doesn't borrow from `stdin`
82+
// https://github.com/rust-lang/rust/pull/93965
83+
84+
stdin.lock().lines().next().unwrap().unwrap()
85+
//~^ ERROR: returning the result of a `let` binding from a block
86+
}
87+
88+
tuple_encode!(T0, T1, T2, T3, T4, T5, T6, T7);
89+
90+
mod no_lint_if_stmt_borrows {
91+
use std::cell::RefCell;
92+
use std::rc::{Rc, Weak};
93+
struct Bar;
94+
95+
impl Bar {
96+
fn new() -> Self {
97+
Bar {}
98+
}
99+
fn baz(&self) -> u32 {
100+
0
101+
}
102+
}
103+
104+
fn issue_3324(value: Weak<RefCell<Bar>>) -> u32 {
105+
let value = value.upgrade().unwrap();
106+
let ret = value.borrow().baz();
107+
ret
108+
//~[edition2024]^ ERROR: returning the result of a `let` binding from a block
109+
}
110+
111+
fn borrows_in_closure(value: Weak<RefCell<Bar>>) -> u32 {
112+
fn f(mut x: impl FnMut() -> u32) -> impl FnMut() -> u32 {
113+
x
114+
}
115+
116+
let value = value.upgrade().unwrap();
117+
let ret = f(|| value.borrow().baz())();
118+
ret
119+
//~[edition2024]^ ERROR: returning the result of a `let` binding from a block
120+
}
121+
122+
mod free_function {
123+
struct Inner;
124+
125+
struct Foo<'a> {
126+
inner: &'a Inner,
127+
}
128+
129+
impl Drop for Foo<'_> {
130+
fn drop(&mut self) {}
131+
}
132+
133+
impl<'a> Foo<'a> {
134+
fn new(inner: &'a Inner) -> Self {
135+
Self { inner }
136+
}
137+
138+
fn value(&self) -> i32 {
139+
42
140+
}
141+
}
142+
143+
fn some_foo(inner: &Inner) -> Foo<'_> {
144+
Foo { inner }
145+
}
146+
147+
fn test() -> i32 {
148+
let x = Inner {};
149+
let value = some_foo(&x).value();
150+
value
151+
//~[edition2024]^ ERROR: returning the result of a `let` binding from a block
152+
}
153+
154+
fn test2() -> i32 {
155+
let x = Inner {};
156+
let value = Foo::new(&x).value();
157+
value
158+
//~[edition2024]^ ERROR: returning the result of a `let` binding from a block
159+
}
160+
}
161+
}
162+
163+
mod issue_5729 {
164+
use std::sync::Arc;
165+
166+
trait Foo {}
167+
168+
trait FooStorage {
169+
fn foo_cloned(&self) -> Arc<dyn Foo>;
170+
}
171+
172+
struct FooStorageImpl<T: Foo> {
173+
foo: Arc<T>,
174+
}
175+
176+
impl<T: Foo + 'static> FooStorage for FooStorageImpl<T> {
177+
fn foo_cloned(&self) -> Arc<dyn Foo> {
178+
179+
(Arc::clone(&self.foo)) as _
180+
//~^ ERROR: returning the result of a `let` binding from a block
181+
}
182+
}
183+
}
184+
185+
mod issue_11335 {
186+
pub enum E<T> {
187+
A(T),
188+
B(T),
189+
}
190+
191+
impl<T> E<T> {
192+
pub fn inner(&self) -> &T {
193+
194+
195+
(match self {
196+
E::A(x) => x,
197+
E::B(x) => x,
198+
}) as _
199+
//~^ ERROR: returning the result of a `let` binding from a block
200+
}
201+
}
202+
}
203+
204+
// https://github.com/rust-lang/rust-clippy/issues/11167
205+
macro_rules! fn_in_macro {
206+
($b:block) => {
207+
fn f() -> usize $b
208+
}
209+
}
210+
fn_in_macro!({
211+
return 1;
212+
});
213+
214+
fn issue9150() -> usize {
215+
let x = 1;
216+
#[cfg(any())]
217+
panic!("can't see me");
218+
x
219+
}
220+
221+
fn issue12801() {
222+
fn left_is_if() -> String {
223+
224+
(if true { "a".to_string() } else { "b".to_string() } + "c")
225+
//~^ ERROR: returning the result of a `let` binding from a block
226+
}
227+
228+
fn no_par_needed() -> String {
229+
230+
"c".to_string() + if true { "a" } else { "b" }
231+
//~^ ERROR: returning the result of a `let` binding from a block
232+
}
233+
234+
fn conjunctive_blocks() -> String {
235+
236+
({ "a".to_string() } + "b" + { "c" } + "d")
237+
//~^ ERROR: returning the result of a `let` binding from a block
238+
}
239+
240+
#[allow(clippy::overly_complex_bool_expr)]
241+
fn other_ops() {
242+
let _ = || {
243+
244+
(if true { 2 } else { 3 } << 4)
245+
//~^ ERROR: returning the result of a `let` binding from a block
246+
};
247+
let _ = || {
248+
249+
({ true } || { false } && { 2 <= 3 })
250+
//~^ ERROR: returning the result of a `let` binding from a block
251+
};
252+
}
253+
}
254+
255+
fn issue14164() -> Result<u32, ()> {
256+
let v = std::cell::RefCell::new(Some(vec![1]));
257+
let r = match &*v.borrow() {
258+
Some(v) => Ok(Ok(v[0])),
259+
None => Ok(Ok(0)),
260+
}?;
261+
r
262+
//~[edition2024]^ ERROR: returning the result of a `let` binding from a block
263+
}
264+
265+
fn main() {}

0 commit comments

Comments
 (0)