]> git.proxmox.com Git - rustc.git/blame - src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
New upstream version 1.66.0+dfsg1
[rustc.git] / src / tools / clippy / tests / ui / significant_drop_in_scrutinee.rs
CommitLineData
04454e1e
FG
1// FIXME: Ideally these suggestions would be fixed via rustfix. Blocked by rust-lang/rust#53934
2// // run-rustfix
04454e1e 3#![warn(clippy::significant_drop_in_scrutinee)]
2b03887a
FG
4#![allow(dead_code, unused_assignments)]
5#![allow(clippy::match_single_binding, clippy::single_match, clippy::uninlined_format_args)]
04454e1e 6
923072b8 7use std::num::ParseIntError;
04454e1e
FG
8use std::ops::Deref;
9use std::sync::atomic::{AtomicU64, Ordering};
923072b8 10use std::sync::RwLock;
04454e1e
FG
11use std::sync::{Mutex, MutexGuard};
12
13struct State {}
14
15impl State {
16 fn foo(&self) -> bool {
17 true
18 }
19
20 fn bar(&self) {}
21}
22
23fn should_not_trigger_lint_with_mutex_guard_outside_match() {
24 let mutex = Mutex::new(State {});
25
26 // Should not trigger lint because the temporary should drop at the `;` on line before the match
27 let is_foo = mutex.lock().unwrap().foo();
28 match is_foo {
29 true => {
30 mutex.lock().unwrap().bar();
923072b8
FG
31 },
32 false => {},
04454e1e
FG
33 };
34}
35
36fn should_not_trigger_lint_with_mutex_guard_when_taking_ownership_in_match() {
37 let mutex = Mutex::new(State {});
38
39 // Should not trigger lint because the scrutinee is explicitly returning the MutexGuard,
40 // so its lifetime should not be surprising.
41 match mutex.lock() {
42 Ok(guard) => {
43 guard.foo();
44 mutex.lock().unwrap().bar();
923072b8
FG
45 },
46 _ => {},
04454e1e
FG
47 };
48}
49
50fn should_trigger_lint_with_mutex_guard_in_match_scrutinee() {
51 let mutex = Mutex::new(State {});
52
53 // Should trigger lint because the lifetime of the temporary MutexGuard is surprising because it
54 // is preserved until the end of the match, but there is no clear indication that this is the
55 // case.
56 match mutex.lock().unwrap().foo() {
57 true => {
58 mutex.lock().unwrap().bar();
923072b8
FG
59 },
60 false => {},
04454e1e
FG
61 };
62}
63
064997fb
FG
64fn should_not_trigger_lint_with_mutex_guard_in_match_scrutinee_when_lint_allowed() {
65 let mutex = Mutex::new(State {});
66
67 // Lint should not be triggered because it is "allowed" below.
68 #[allow(clippy::significant_drop_in_scrutinee)]
69 match mutex.lock().unwrap().foo() {
70 true => {
71 mutex.lock().unwrap().bar();
72 },
73 false => {},
74 };
75}
76
04454e1e
FG
77fn should_not_trigger_lint_for_insignificant_drop() {
78 // Should not trigger lint because there are no temporaries whose drops have a significant
79 // side effect.
80 match 1u64.to_string().is_empty() {
81 true => {
82 println!("It was empty")
923072b8 83 },
04454e1e
FG
84 false => {
85 println!("It was not empty")
923072b8 86 },
04454e1e
FG
87 }
88}
89
90struct StateWithMutex {
91 m: Mutex<u64>,
92}
93
94struct MutexGuardWrapper<'a> {
95 mg: MutexGuard<'a, u64>,
96}
97
98impl<'a> MutexGuardWrapper<'a> {
99 fn get_the_value(&self) -> u64 {
100 *self.mg.deref()
101 }
102}
103
104struct MutexGuardWrapperWrapper<'a> {
105 mg: MutexGuardWrapper<'a>,
106}
107
108impl<'a> MutexGuardWrapperWrapper<'a> {
109 fn get_the_value(&self) -> u64 {
110 *self.mg.mg.deref()
111 }
112}
113
114impl StateWithMutex {
115 fn lock_m(&self) -> MutexGuardWrapper<'_> {
116 MutexGuardWrapper {
117 mg: self.m.lock().unwrap(),
118 }
119 }
120
121 fn lock_m_m(&self) -> MutexGuardWrapperWrapper<'_> {
122 MutexGuardWrapperWrapper {
123 mg: MutexGuardWrapper {
124 mg: self.m.lock().unwrap(),
125 },
126 }
127 }
128
129 fn foo(&self) -> bool {
130 true
131 }
132
133 fn bar(&self) {}
134}
135
136fn should_trigger_lint_with_wrapped_mutex() {
137 let s = StateWithMutex { m: Mutex::new(1) };
138
139 // Should trigger lint because a temporary contains a type with a significant drop and its
140 // lifetime is not obvious. Additionally, it is not obvious from looking at the scrutinee that
141 // the temporary contains such a type, making it potentially even more surprising.
142 match s.lock_m().get_the_value() {
143 1 => {
144 println!("Got 1. Is it still 1?");
145 println!("{}", s.lock_m().get_the_value());
923072b8 146 },
04454e1e
FG
147 2 => {
148 println!("Got 2. Is it still 2?");
149 println!("{}", s.lock_m().get_the_value());
923072b8
FG
150 },
151 _ => {},
04454e1e
FG
152 }
153 println!("All done!");
154}
155
156fn should_trigger_lint_with_double_wrapped_mutex() {
157 let s = StateWithMutex { m: Mutex::new(1) };
158
159 // Should trigger lint because a temporary contains a type which further contains a type with a
160 // significant drop and its lifetime is not obvious. Additionally, it is not obvious from
161 // looking at the scrutinee that the temporary contains such a type, making it potentially even
162 // more surprising.
163 match s.lock_m_m().get_the_value() {
164 1 => {
165 println!("Got 1. Is it still 1?");
166 println!("{}", s.lock_m().get_the_value());
923072b8 167 },
04454e1e
FG
168 2 => {
169 println!("Got 2. Is it still 2?");
170 println!("{}", s.lock_m().get_the_value());
923072b8
FG
171 },
172 _ => {},
04454e1e
FG
173 }
174 println!("All done!");
175}
176
177struct Counter {
178 i: AtomicU64,
179}
180
181#[clippy::has_significant_drop]
182struct CounterWrapper<'a> {
183 counter: &'a Counter,
184}
185
186impl<'a> CounterWrapper<'a> {
187 fn new(counter: &Counter) -> CounterWrapper {
188 counter.i.fetch_add(1, Ordering::Relaxed);
189 CounterWrapper { counter }
190 }
191}
192
193impl<'a> Drop for CounterWrapper<'a> {
194 fn drop(&mut self) {
195 self.counter.i.fetch_sub(1, Ordering::Relaxed);
196 }
197}
198
199impl Counter {
200 fn temp_increment(&self) -> Vec<CounterWrapper> {
201 vec![CounterWrapper::new(self), CounterWrapper::new(self)]
202 }
203}
204
205fn should_trigger_lint_for_vec() {
206 let counter = Counter { i: AtomicU64::new(0) };
207
208 // Should trigger lint because the temporary in the scrutinee returns a collection of types
209 // which have significant drops. The types with significant drops are also non-obvious when
210 // reading the expression in the scrutinee.
211 match counter.temp_increment().len() {
212 2 => {
213 let current_count = counter.i.load(Ordering::Relaxed);
214 println!("Current count {}", current_count);
215 assert_eq!(current_count, 0);
923072b8
FG
216 },
217 1 => {},
218 3 => {},
219 _ => {},
04454e1e
FG
220 };
221}
222
223struct StateWithField {
224 s: String,
225}
226
227// Should trigger lint only on the type in the tuple which is created using a temporary
228// with a significant drop. Additionally, this test ensures that the format of the tuple
229// is preserved correctly in the suggestion.
230fn should_trigger_lint_for_tuple_in_scrutinee() {
231 let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() });
232
233 {
234 match (mutex1.lock().unwrap().s.len(), true) {
235 (3, _) => {
236 println!("started");
237 mutex1.lock().unwrap().s.len();
238 println!("done");
923072b8
FG
239 },
240 (_, _) => {},
04454e1e
FG
241 };
242
243 match (true, mutex1.lock().unwrap().s.len(), true) {
244 (_, 3, _) => {
245 println!("started");
246 mutex1.lock().unwrap().s.len();
247 println!("done");
923072b8
FG
248 },
249 (_, _, _) => {},
04454e1e
FG
250 };
251
252 let mutex2 = Mutex::new(StateWithField { s: "two".to_owned() });
253 match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) {
254 (3, _, 3) => {
255 println!("started");
256 mutex1.lock().unwrap().s.len();
257 mutex2.lock().unwrap().s.len();
258 println!("done");
923072b8
FG
259 },
260 (_, _, _) => {},
04454e1e
FG
261 };
262
263 let mutex3 = Mutex::new(StateWithField { s: "three".to_owned() });
264 match mutex3.lock().unwrap().s.as_str() {
265 "three" => {
266 println!("started");
267 mutex1.lock().unwrap().s.len();
268 mutex2.lock().unwrap().s.len();
269 println!("done");
923072b8
FG
270 },
271 _ => {},
04454e1e
FG
272 };
273
04454e1e
FG
274 match (true, mutex3.lock().unwrap().s.as_str()) {
275 (_, "three") => {
276 println!("started");
277 mutex1.lock().unwrap().s.len();
278 mutex2.lock().unwrap().s.len();
279 println!("done");
923072b8
FG
280 },
281 (_, _) => {},
04454e1e
FG
282 };
283 }
284}
285
286// Should trigger lint when either side of a binary operation creates a temporary with a
287// significant drop.
288// To avoid potential unnecessary copies or creating references that would trigger the significant
289// drop problem, the lint recommends moving the entire binary operation.
290fn should_trigger_lint_for_accessing_field_in_mutex_in_one_side_of_binary_op() {
291 let mutex = Mutex::new(StateWithField { s: "state".to_owned() });
292
293 match mutex.lock().unwrap().s.len() > 1 {
294 true => {
295 mutex.lock().unwrap().s.len();
923072b8
FG
296 },
297 false => {},
04454e1e
FG
298 };
299
300 match 1 < mutex.lock().unwrap().s.len() {
301 true => {
302 mutex.lock().unwrap().s.len();
923072b8
FG
303 },
304 false => {},
04454e1e
FG
305 };
306}
307
308// Should trigger lint when both sides of a binary operation creates a temporary with a
309// significant drop.
310// To avoid potential unnecessary copies or creating references that would trigger the significant
311// drop problem, the lint recommends moving the entire binary operation.
312fn should_trigger_lint_for_accessing_fields_in_mutex_in_both_sides_of_binary_op() {
313 let mutex1 = Mutex::new(StateWithField { s: "state".to_owned() });
923072b8
FG
314 let mutex2 = Mutex::new(StateWithField {
315 s: "statewithfield".to_owned(),
316 });
04454e1e
FG
317
318 match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() {
319 true => {
923072b8
FG
320 println!(
321 "{} < {}",
322 mutex1.lock().unwrap().s.len(),
323 mutex2.lock().unwrap().s.len()
324 );
325 },
326 false => {},
04454e1e
FG
327 };
328
329 match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() {
330 true => {
923072b8
FG
331 println!(
332 "{} >= {}",
333 mutex1.lock().unwrap().s.len(),
334 mutex2.lock().unwrap().s.len()
335 );
336 },
337 false => {},
04454e1e
FG
338 };
339}
340
341fn should_not_trigger_lint_for_closure_in_scrutinee() {
342 let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() });
343
344 let get_mutex_guard = || mutex1.lock().unwrap().s.len();
345
346 // Should not trigger lint because the temporary with a significant drop will be dropped
347 // at the end of the closure, so the MutexGuard will be unlocked and not have a potentially
348 // surprising lifetime.
349 match get_mutex_guard() > 1 {
350 true => {
351 mutex1.lock().unwrap().s.len();
923072b8
FG
352 },
353 false => {},
04454e1e
FG
354 };
355}
356
357fn should_trigger_lint_for_return_from_closure_in_scrutinee() {
358 let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() });
359
360 let get_mutex_guard = || mutex1.lock().unwrap();
361
362 // Should trigger lint because the temporary with a significant drop is returned from the
363 // closure but not used directly in any match arms, so it has a potentially surprising lifetime.
364 match get_mutex_guard().s.len() > 1 {
365 true => {
366 mutex1.lock().unwrap().s.len();
923072b8
FG
367 },
368 false => {},
04454e1e
FG
369 };
370}
371
372fn should_trigger_lint_for_return_from_match_in_scrutinee() {
373 let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() });
374 let mutex2 = Mutex::new(StateWithField { s: "two".to_owned() });
375
376 let i = 100;
377
378 // Should trigger lint because the nested match within the scrutinee returns a temporary with a
379 // significant drop is but not used directly in any match arms, so it has a potentially
380 // surprising lifetime.
923072b8
FG
381 match match i {
382 100 => mutex1.lock().unwrap(),
383 _ => mutex2.lock().unwrap(),
384 }
385 .s
386 .len()
387 > 1
388 {
04454e1e
FG
389 true => {
390 mutex1.lock().unwrap().s.len();
923072b8 391 },
04454e1e
FG
392 false => {
393 println!("nothing to do here");
923072b8 394 },
04454e1e
FG
395 };
396}
397
398fn should_trigger_lint_for_return_from_if_in_scrutinee() {
399 let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() });
400 let mutex2 = Mutex::new(StateWithField { s: "two".to_owned() });
401
402 let i = 100;
403
404 // Should trigger lint because the nested if-expression within the scrutinee returns a temporary
405 // with a significant drop is but not used directly in any match arms, so it has a potentially
406 // surprising lifetime.
923072b8
FG
407 match if i > 1 {
408 mutex1.lock().unwrap()
409 } else {
410 mutex2.lock().unwrap()
411 }
412 .s
413 .len()
414 > 1
415 {
04454e1e
FG
416 true => {
417 mutex1.lock().unwrap().s.len();
923072b8
FG
418 },
419 false => {},
04454e1e
FG
420 };
421}
422
423fn should_not_trigger_lint_for_if_in_scrutinee() {
424 let mutex = Mutex::new(StateWithField { s: "state".to_owned() });
425
426 let i = 100;
427
428 // Should not trigger the lint because the temporary with a significant drop *is* dropped within
429 // the body of the if-expression nested within the match scrutinee, and therefore does not have
430 // a potentially surprising lifetime.
923072b8
FG
431 match if i > 1 {
432 mutex.lock().unwrap().s.len() > 1
433 } else {
434 false
435 } {
04454e1e
FG
436 true => {
437 mutex.lock().unwrap().s.len();
923072b8
FG
438 },
439 false => {},
04454e1e
FG
440 };
441}
442
443struct StateWithBoxedMutexGuard {
444 u: Mutex<u64>,
445}
446
447impl StateWithBoxedMutexGuard {
448 fn new() -> StateWithBoxedMutexGuard {
449 StateWithBoxedMutexGuard { u: Mutex::new(42) }
450 }
451 fn lock(&self) -> Box<MutexGuard<u64>> {
452 Box::new(self.u.lock().unwrap())
453 }
454}
455
456fn should_trigger_lint_for_boxed_mutex_guard() {
457 let s = StateWithBoxedMutexGuard::new();
458
459 // Should trigger lint because a temporary Box holding a type with a significant drop in a match
460 // scrutinee may have a potentially surprising lifetime.
461 match s.lock().deref().deref() {
462 0 | 1 => println!("Value was less than 2"),
463 _ => println!("Value is {}", s.lock().deref()),
464 };
465}
466
467struct StateStringWithBoxedMutexGuard {
468 s: Mutex<String>,
469}
470
471impl StateStringWithBoxedMutexGuard {
472 fn new() -> StateStringWithBoxedMutexGuard {
923072b8
FG
473 StateStringWithBoxedMutexGuard {
474 s: Mutex::new("A String".to_owned()),
475 }
04454e1e
FG
476 }
477 fn lock(&self) -> Box<MutexGuard<String>> {
478 Box::new(self.s.lock().unwrap())
479 }
480}
481
482fn should_trigger_lint_for_boxed_mutex_guard_holding_string() {
483 let s = StateStringWithBoxedMutexGuard::new();
484
485 let matcher = String::from("A String");
486
487 // Should trigger lint because a temporary Box holding a type with a significant drop in a match
488 // scrutinee may have a potentially surprising lifetime.
489 match s.lock().deref().deref() {
490 matcher => println!("Value is {}", s.lock().deref()),
491 _ => println!("Value was not a match"),
492 };
493}
494
04454e1e
FG
495struct StateWithIntField {
496 i: u64,
497}
498
499// Should trigger lint when either side of an assign expression contains a temporary with a
500// significant drop, because the temporary's lifetime will be extended to the end of the match.
501// To avoid potential unnecessary copies or creating references that would trigger the significant
502// drop problem, the lint recommends moving the entire binary operation.
503fn should_trigger_lint_in_assign_expr() {
504 let mutex = Mutex::new(StateWithIntField { i: 10 });
505
506 let mut i = 100;
507
508 match mutex.lock().unwrap().i = i {
509 _ => {
510 println!("{}", mutex.lock().unwrap().i);
923072b8 511 },
04454e1e
FG
512 };
513
514 match i = mutex.lock().unwrap().i {
515 _ => {
516 println!("{}", mutex.lock().unwrap().i);
923072b8 517 },
04454e1e
FG
518 };
519
520 match mutex.lock().unwrap().i += 1 {
521 _ => {
522 println!("{}", mutex.lock().unwrap().i);
923072b8 523 },
04454e1e
FG
524 };
525
526 match i += mutex.lock().unwrap().i {
527 _ => {
528 println!("{}", mutex.lock().unwrap().i);
923072b8 529 },
04454e1e
FG
530 };
531}
532
533#[derive(Debug)]
534enum RecursiveEnum {
923072b8 535 Foo(Option<Box<RecursiveEnum>>),
04454e1e
FG
536}
537
538#[derive(Debug)]
539enum GenericRecursiveEnum<T> {
923072b8 540 Foo(T, Option<Box<GenericRecursiveEnum<T>>>),
04454e1e
FG
541}
542
543fn should_not_cause_stack_overflow() {
544 // Test that when a type recursively contains itself, a stack overflow does not occur when
545 // checking sub-types for significant drops.
546 let f = RecursiveEnum::Foo(Some(Box::new(RecursiveEnum::Foo(None))));
547 match f {
548 RecursiveEnum::Foo(Some(f)) => {
549 println!("{:?}", f)
923072b8 550 },
04454e1e
FG
551 RecursiveEnum::Foo(f) => {
552 println!("{:?}", f)
923072b8 553 },
04454e1e
FG
554 }
555
556 let f = GenericRecursiveEnum::Foo(1u64, Some(Box::new(GenericRecursiveEnum::Foo(2u64, None))));
557 match f {
558 GenericRecursiveEnum::Foo(i, Some(f)) => {
559 println!("{} {:?}", i, f)
923072b8 560 },
04454e1e
FG
561 GenericRecursiveEnum::Foo(i, f) => {
562 println!("{} {:?}", i, f)
923072b8
FG
563 },
564 }
565}
566
567fn should_not_produce_lint_for_try_desugar() -> Result<u64, ParseIntError> {
568 // TryDesugar (i.e. using `?` for a Result type) will turn into a match but is out of scope
569 // for this lint
570 let rwlock = RwLock::new("1".to_string());
571 let result = rwlock.read().unwrap().parse::<u64>()?;
572 println!("{}", result);
573 rwlock.write().unwrap().push('2');
574 Ok(result)
575}
576
577struct ResultReturner {
578 s: String,
579}
580
581impl ResultReturner {
582 fn to_number(&self) -> Result<i64, ParseIntError> {
583 self.s.parse::<i64>()
584 }
585}
586
587fn should_trigger_lint_for_non_ref_move_and_clone_suggestion() {
588 let rwlock = RwLock::<ResultReturner>::new(ResultReturner { s: "1".to_string() });
589 match rwlock.read().unwrap().to_number() {
590 Ok(n) => println!("Converted to number: {}", n),
591 Err(e) => println!("Could not convert {} to number", e),
592 };
593}
594
595fn should_trigger_lint_for_read_write_lock_for_loop() {
596 // For-in loops desugar to match expressions and are prone to the type of deadlock this lint is
597 // designed to look for.
598 let rwlock = RwLock::<Vec<String>>::new(vec!["1".to_string()]);
599 for s in rwlock.read().unwrap().iter() {
600 println!("{}", s);
04454e1e
FG
601 }
602}
603
064997fb
FG
604fn do_bar(mutex: &Mutex<State>) {
605 mutex.lock().unwrap().bar();
606}
607
608fn should_trigger_lint_without_significant_drop_in_arm() {
609 let mutex = Mutex::new(State {});
610
611 // Should trigger lint because the lifetime of the temporary MutexGuard is surprising because it
612 // is preserved until the end of the match, but there is no clear indication that this is the
613 // case.
614 match mutex.lock().unwrap().foo() {
615 true => do_bar(&mutex),
616 false => {},
617 };
618}
619
620fn should_not_trigger_on_significant_iterator_drop() {
621 let lines = std::io::stdin().lines();
622 for line in lines {
623 println!("foo: {}", line.unwrap());
624 }
625}
626
04454e1e 627fn main() {}