diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 4aa100a50e05..d3a5a5dddfbe 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -6,7 +6,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; -use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use clippy_utils::ty::{implements_trait, is_copy, is_type_diagnostic_item}; +use clippy_utils::usage::local_used_after_expr; use clippy_utils::{ eq_expr_value, fn_def_id_with_node_args, higher, is_else_clause, is_in_const_context, is_lint_allowed, is_path_lang_item, is_res_lang_ctor, pat_and_expr_can_be_question_mark, path_res, path_to_local, path_to_local_id, @@ -483,6 +484,13 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: .filter(|e| *e) .is_none() { + if !is_copy(cx, caller_ty) + && let Some(hir_id) = path_to_local(let_expr) + && local_used_after_expr(cx, hir_id, expr) + { + return; + } + let mut applicability = Applicability::MachineApplicable; let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability); let requires_semi = matches!(cx.tcx.parent_hir_node(expr.hir_id), Node::Stmt(_)); diff --git a/tests/ui/question_mark.fixed b/tests/ui/question_mark.fixed index ac81b324c204..2c5ee0245038 100644 --- a/tests/ui/question_mark.fixed +++ b/tests/ui/question_mark.fixed @@ -475,3 +475,28 @@ fn issue_15679() -> Result { Ok(0) } + +mod issue14894 { + fn use_after_question_mark(do_something_else: impl Fn() -> Result) -> Result<(), ()> { + let result = do_something_else(); + if let Err(reason) = result { + return Err(reason); + } + drop(result); + + let result = do_something_else(); + let x = result?; + drop(x); + + Ok(()) + } + + #[expect(dropping_copy_types)] + fn use_after_question_mark_but_is_copy(do_something_else: impl Fn() -> Result) -> Result<(), ()> { + let result = do_something_else(); + result?; + drop(result); + + Ok(()) + } +} diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs index b5866dac6b8f..b9ff9d1565b2 100644 --- a/tests/ui/question_mark.rs +++ b/tests/ui/question_mark.rs @@ -583,3 +583,35 @@ fn issue_15679() -> Result { Ok(0) } + +mod issue14894 { + fn use_after_question_mark(do_something_else: impl Fn() -> Result) -> Result<(), ()> { + let result = do_something_else(); + if let Err(reason) = result { + return Err(reason); + } + drop(result); + + let result = do_something_else(); + let x = match result { + //~^ question_mark + Ok(v) => v, + Err(e) => return Err(e), + }; + drop(x); + + Ok(()) + } + + #[expect(dropping_copy_types)] + fn use_after_question_mark_but_is_copy(do_something_else: impl Fn() -> Result) -> Result<(), ()> { + let result = do_something_else(); + if let Err(reason) = result { + //~^ question_mark + return Err(reason); + } + drop(result); + + Ok(()) + } +} diff --git a/tests/ui/question_mark.stderr b/tests/ui/question_mark.stderr index 1ecd936292e5..9b2896328e66 100644 --- a/tests/ui/question_mark.stderr +++ b/tests/ui/question_mark.stderr @@ -313,5 +313,25 @@ LL | | Err(err) => return Err(<&str as Into>::into(err)), LL | | }; | |_____^ help: try instead: `some_result?` -error: aborting due to 33 previous errors +error: this `match` expression can be replaced with `?` + --> tests/ui/question_mark.rs:596:17 + | +LL | let x = match result { + | _________________^ +LL | | +LL | | Ok(v) => v, +LL | | Err(e) => return Err(e), +LL | | }; + | |_________^ help: try instead: `result?` + +error: this block may be rewritten with the `?` operator + --> tests/ui/question_mark.rs:609:9 + | +LL | / if let Err(reason) = result { +LL | | +LL | | return Err(reason); +LL | | } + | |_________^ help: replace it with: `result?;` + +error: aborting due to 35 previous errors