From 158bf9aa443c5ea93ff4b3def8c7220632e45442 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sat, 31 Oct 2020 19:56:51 +0100 Subject: [PATCH 1/5] Fix incorrect suggestion for macro expansion in `deref_addrof` lint --- clippy_lints/src/reference.rs | 8 +++++++- tests/ui/deref_addrof.fixed | 15 ++++++++++++++- tests/ui/deref_addrof.rs | 15 ++++++++++++++- tests/ui/deref_addrof.stderr | 13 ++++++++++++- 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index 3fda00403c61..f1555ab3ec18 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -46,13 +46,19 @@ impl EarlyLintPass for DerefAddrOf { if !in_macro(addrof_target.span); then { let mut applicability = Applicability::MachineApplicable; + let sugg = if e.span.from_expansion() { + let snip = snippet_with_applicability(cx, e.span, "_", &mut applicability); + snip.trim_start_matches(|c| c == '&' || c == '*').to_string() + } else { + snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability).to_string() + }; span_lint_and_sugg( cx, DEREF_ADDROF, e.span, "immediately dereferencing a reference", "try this", - format!("{}", snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability)), + sugg, applicability, ); } diff --git a/tests/ui/deref_addrof.fixed b/tests/ui/deref_addrof.fixed index 9e5b51d6d5e6..8cdec4201fef 100644 --- a/tests/ui/deref_addrof.fixed +++ b/tests/ui/deref_addrof.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![warn(clippy::deref_addrof)] fn get_number() -> usize { 10 @@ -10,7 +11,6 @@ fn get_reference(n: &usize) -> &usize { #[allow(clippy::many_single_char_names, clippy::double_parens)] #[allow(unused_variables, unused_parens)] -#[warn(clippy::deref_addrof)] fn main() { let a = 10; let aref = &a; @@ -37,3 +37,16 @@ fn main() { let b = *aref; } + +macro_rules! m { + ($visitor: expr) => { + $visitor + }; +} + +pub struct S; +impl S { + pub fn f(&self) -> &Self { + m!(self) + } +} diff --git a/tests/ui/deref_addrof.rs b/tests/ui/deref_addrof.rs index 5641a73cbc1c..6433e63ca590 100644 --- a/tests/ui/deref_addrof.rs +++ b/tests/ui/deref_addrof.rs @@ -1,4 +1,5 @@ // run-rustfix +#![warn(clippy::deref_addrof)] fn get_number() -> usize { 10 @@ -10,7 +11,6 @@ fn get_reference(n: &usize) -> &usize { #[allow(clippy::many_single_char_names, clippy::double_parens)] #[allow(unused_variables, unused_parens)] -#[warn(clippy::deref_addrof)] fn main() { let a = 10; let aref = &a; @@ -37,3 +37,16 @@ fn main() { let b = **&aref; } + +macro_rules! m { + ($visitor: expr) => { + *&$visitor + }; +} + +pub struct S; +impl S { + pub fn f(&self) -> &Self { + m!(self) + } +} diff --git a/tests/ui/deref_addrof.stderr b/tests/ui/deref_addrof.stderr index bc51719e8a7a..1fe49ad49cd6 100644 --- a/tests/ui/deref_addrof.stderr +++ b/tests/ui/deref_addrof.stderr @@ -48,5 +48,16 @@ error: immediately dereferencing a reference LL | let b = **&aref; | ^^^^^^ help: try this: `aref` -error: aborting due to 8 previous errors +error: immediately dereferencing a reference + --> $DIR/deref_addrof.rs:43:9 + | +LL | *&$visitor + | ^^^^^^^^^^ help: try this: `$visitor` +... +LL | m!(self) + | -------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 9 previous errors From 343bdb33647627a6a001be039a107e7ef3362707 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Mon, 2 Nov 2020 17:56:54 +0100 Subject: [PATCH 2/5] Give better suggestion by working on span on `deref_addrof` lint --- clippy_lints/src/reference.rs | 36 ++++++++++++++++++++++++++++++----- tests/ui/deref_addrof.fixed | 10 ++++++++++ tests/ui/deref_addrof.rs | 12 +++++++++++- tests/ui/deref_addrof.stderr | 17 ++++++++++++++--- 4 files changed, 66 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index f1555ab3ec18..8646d6167351 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -1,9 +1,11 @@ -use crate::utils::{in_macro, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{in_macro, snippet_opt, snippet_with_applicability, span_lint_and_sugg}; use if_chain::if_chain; -use rustc_ast::ast::{Expr, ExprKind, UnOp}; +use rustc_ast::ast::{Expr, ExprKind, UnOp, Mutability}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::BytePos; +// use rustc_span::source_map::{BytePos, Span}; declare_clippy_lint! { /// **What it does:** Checks for usage of `*&` and `*&mut` in expressions. @@ -42,13 +44,37 @@ impl EarlyLintPass for DerefAddrOf { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) { if_chain! { if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind; - if let ExprKind::AddrOf(_, _, ref addrof_target) = without_parens(deref_target).kind; + if let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind; if !in_macro(addrof_target.span); then { let mut applicability = Applicability::MachineApplicable; let sugg = if e.span.from_expansion() { - let snip = snippet_with_applicability(cx, e.span, "_", &mut applicability); - snip.trim_start_matches(|c| c == '&' || c == '*').to_string() + if let Ok(macro_source) = cx.sess.source_map().span_to_snippet(e.span) { + // Remove leading whitespace from the given span + // e.g: ` $visitor` turns into `$visitor` + let trim_leading_whitespaces = |span| { + if let Some(start_no_whitespace) = snippet_opt(cx, span).and_then(|snip| { + snip.find(|c: char| !c.is_whitespace()).map(|pos| { + span.lo() + BytePos(pos as u32) + }) + }) { + e.span.with_lo(start_no_whitespace) + } else { + span + } + }; + + let rpos = if *mutability == Mutability::Mut { + macro_source.rfind("mut").expect("already checked this is a mutable reference") + "mut".len() + } else { + macro_source.rfind("&").expect("already checked this is a reference") + "&".len() + }; + let span_after_ref = e.span.with_lo(BytePos(e.span.lo().0 + rpos as u32)); + let span = trim_leading_whitespaces(span_after_ref); + snippet_with_applicability(cx, span, "_", &mut applicability).to_string() + } else { + snippet_with_applicability(cx, e.span, "_", &mut applicability).to_string() + } } else { snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability).to_string() }; diff --git a/tests/ui/deref_addrof.fixed b/tests/ui/deref_addrof.fixed index 8cdec4201fef..689e9d552234 100644 --- a/tests/ui/deref_addrof.fixed +++ b/tests/ui/deref_addrof.fixed @@ -44,9 +44,19 @@ macro_rules! m { }; } +#[rustfmt::skip] +macro_rules! m_mut { + ($visitor: expr) => { + $visitor + }; +} + pub struct S; impl S { pub fn f(&self) -> &Self { m!(self) } + pub fn f_mut(&self) -> &Self { + m_mut!(self) + } } diff --git a/tests/ui/deref_addrof.rs b/tests/ui/deref_addrof.rs index 6433e63ca590..57effce5d129 100644 --- a/tests/ui/deref_addrof.rs +++ b/tests/ui/deref_addrof.rs @@ -40,7 +40,14 @@ fn main() { macro_rules! m { ($visitor: expr) => { - *&$visitor + *& $visitor + }; +} + +#[rustfmt::skip] +macro_rules! m_mut { + ($visitor: expr) => { + *& mut $visitor }; } @@ -49,4 +56,7 @@ impl S { pub fn f(&self) -> &Self { m!(self) } + pub fn f_mut(&self) -> &Self { + m_mut!(self) + } } diff --git a/tests/ui/deref_addrof.stderr b/tests/ui/deref_addrof.stderr index 1fe49ad49cd6..52c1f7d1da8f 100644 --- a/tests/ui/deref_addrof.stderr +++ b/tests/ui/deref_addrof.stderr @@ -51,13 +51,24 @@ LL | let b = **&aref; error: immediately dereferencing a reference --> $DIR/deref_addrof.rs:43:9 | -LL | *&$visitor - | ^^^^^^^^^^ help: try this: `$visitor` +LL | *& $visitor + | ^^^^^^^^^^^ help: try this: `$visitor` ... LL | m!(self) | -------- in this macro invocation | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 9 previous errors +error: immediately dereferencing a reference + --> $DIR/deref_addrof.rs:50:9 + | +LL | *& mut $visitor + | ^^^^^^^^^^^^^^^ help: try this: `$visitor` +... +LL | m_mut!(self) + | ------------ in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 10 previous errors From ce98468158318a47f6bab3707d348e116451ad39 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Mon, 2 Nov 2020 17:59:47 +0100 Subject: [PATCH 3/5] Fix incorrect suggestion when from expansion in `try_err` lint --- clippy_lints/src/try_err.rs | 10 ++++++++-- tests/ui/try_err.fixed | 16 ++++++++++++++++ tests/ui/try_err.rs | 16 ++++++++++++++++ tests/ui/try_err.stderr | 21 ++++++++++++++++----- 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index 3e747ec4ad9e..e6d8e7521a8c 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -1,5 +1,5 @@ use crate::utils::{ - is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet, snippet_with_macro_callsite, + in_macro, is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet, snippet_with_macro_callsite, span_lint_and_sugg, }; use if_chain::if_chain; @@ -92,9 +92,13 @@ impl<'tcx> LateLintPass<'tcx> for TryErr { let expr_err_ty = cx.typeck_results().expr_ty(err_arg); - let origin_snippet = if err_arg.span.from_expansion() { + // println!("\n\n{:?}", in_macro(expr.span)); + // println!("{:#?}", snippet(cx, err_arg.span, "_")); + let origin_snippet = if err_arg.span.from_expansion() && !in_macro(expr.span) { + // println!("from expansion"); snippet_with_macro_callsite(cx, err_arg.span, "_") } else { + // println!("just a snippet"); snippet(cx, err_arg.span, "_") }; let suggestion = if err_ty == expr_err_ty { @@ -102,6 +106,8 @@ impl<'tcx> LateLintPass<'tcx> for TryErr { } else { format!("return {}{}.into(){}", prefix, origin_snippet, suffix) }; + // println!("origin_snippet: {:#?}", origin_snippet); + // println!("suggestion: {:#?}", suggestion); span_lint_and_sugg( cx, diff --git a/tests/ui/try_err.fixed b/tests/ui/try_err.fixed index 9e77dcd87316..053dd45f23e1 100644 --- a/tests/ui/try_err.fixed +++ b/tests/ui/try_err.fixed @@ -78,12 +78,28 @@ fn nested_error() -> Result { Ok(1) } +// Bad suggestion when in macro (see #6242) +macro_rules! try_validation { + ($e: expr) => {{ + match $e { + Ok(_) => 0, + Err(_) => return Err(1), + } + }}; +} + +fn calling_macro() -> Result { + try_validation!(Ok::<_, i32>(5)); + Ok(5) +} + fn main() { basic_test().unwrap(); into_test().unwrap(); negative_test().unwrap(); closure_matches_test().unwrap(); closure_into_test().unwrap(); + calling_macro().unwrap(); // We don't want to lint in external macros try_err!(); diff --git a/tests/ui/try_err.rs b/tests/ui/try_err.rs index 41bcb0a189e7..215ca6a07e62 100644 --- a/tests/ui/try_err.rs +++ b/tests/ui/try_err.rs @@ -78,12 +78,28 @@ fn nested_error() -> Result { Ok(1) } +// Bad suggestion when in macro (see #6242) +macro_rules! try_validation { + ($e: expr) => {{ + match $e { + Ok(_) => 0, + Err(_) => Err(1)?, + } + }}; +} + +fn calling_macro() -> Result { + try_validation!(Ok::<_, i32>(5)); + Ok(5) +} + fn main() { basic_test().unwrap(); into_test().unwrap(); negative_test().unwrap(); closure_matches_test().unwrap(); closure_into_test().unwrap(); + calling_macro().unwrap(); // We don't want to lint in external macros try_err!(); diff --git a/tests/ui/try_err.stderr b/tests/ui/try_err.stderr index 3f1cbc17e72d..443c8d084721 100644 --- a/tests/ui/try_err.stderr +++ b/tests/ui/try_err.stderr @@ -29,28 +29,39 @@ LL | Err(err)?; | ^^^^^^^^^ help: try this: `return Err(err.into())` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:106:9 + --> $DIR/try_err.rs:86:23 + | +LL | Err(_) => Err(1)?, + | ^^^^^^^ help: try this: `return Err(1)` +... +LL | try_validation!(Ok::<_, i32>(5)); + | --------------------------------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: returning an `Err(_)` with the `?` operator + --> $DIR/try_err.rs:122:9 | LL | Err(foo!())?; | ^^^^^^^^^^^^ help: try this: `return Err(foo!())` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:113:9 + --> $DIR/try_err.rs:129:9 | LL | Err(io::ErrorKind::WriteZero)? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:115:9 + --> $DIR/try_err.rs:131:9 | LL | Err(io::Error::new(io::ErrorKind::InvalidInput, "error"))? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:123:9 + --> $DIR/try_err.rs:139:9 | LL | Err(io::ErrorKind::NotFound)? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))` -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors From f83762b79cf23bfa91d77d6f04ec2b87b2159b07 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Mon, 2 Nov 2020 18:03:16 +0100 Subject: [PATCH 4/5] Skip rustfmt as it is wanted for this test --- clippy_lints/src/reference.rs | 23 ++++++++++------------- clippy_lints/src/try_err.rs | 6 ------ tests/ui/deref_addrof.fixed | 1 + tests/ui/deref_addrof.rs | 1 + tests/ui/deref_addrof.stderr | 4 ++-- 5 files changed, 14 insertions(+), 21 deletions(-) diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index 8646d6167351..35a1310d68b8 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -1,11 +1,10 @@ use crate::utils::{in_macro, snippet_opt, snippet_with_applicability, span_lint_and_sugg}; use if_chain::if_chain; -use rustc_ast::ast::{Expr, ExprKind, UnOp, Mutability}; +use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::BytePos; -// use rustc_span::source_map::{BytePos, Span}; declare_clippy_lint! { /// **What it does:** Checks for usage of `*&` and `*&mut` in expressions. @@ -53,31 +52,29 @@ impl EarlyLintPass for DerefAddrOf { // Remove leading whitespace from the given span // e.g: ` $visitor` turns into `$visitor` let trim_leading_whitespaces = |span| { - if let Some(start_no_whitespace) = snippet_opt(cx, span).and_then(|snip| { + snippet_opt(cx, span).and_then(|snip| { + #[allow(clippy::cast_possible_truncation)] snip.find(|c: char| !c.is_whitespace()).map(|pos| { span.lo() + BytePos(pos as u32) }) - }) { - e.span.with_lo(start_no_whitespace) - } else { - span - } + }).map_or(span, |start_no_whitespace| e.span.with_lo(start_no_whitespace)) }; let rpos = if *mutability == Mutability::Mut { macro_source.rfind("mut").expect("already checked this is a mutable reference") + "mut".len() } else { - macro_source.rfind("&").expect("already checked this is a reference") + "&".len() + macro_source.rfind('&').expect("already checked this is a reference") + "&".len() }; + #[allow(clippy::cast_possible_truncation)] let span_after_ref = e.span.with_lo(BytePos(e.span.lo().0 + rpos as u32)); let span = trim_leading_whitespaces(span_after_ref); - snippet_with_applicability(cx, span, "_", &mut applicability).to_string() + snippet_with_applicability(cx, span, "_", &mut applicability) } else { - snippet_with_applicability(cx, e.span, "_", &mut applicability).to_string() + snippet_with_applicability(cx, e.span, "_", &mut applicability) } } else { - snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability).to_string() - }; + snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability) + }.to_string(); span_lint_and_sugg( cx, DEREF_ADDROF, diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index e6d8e7521a8c..9c1185d30f21 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -92,13 +92,9 @@ impl<'tcx> LateLintPass<'tcx> for TryErr { let expr_err_ty = cx.typeck_results().expr_ty(err_arg); - // println!("\n\n{:?}", in_macro(expr.span)); - // println!("{:#?}", snippet(cx, err_arg.span, "_")); let origin_snippet = if err_arg.span.from_expansion() && !in_macro(expr.span) { - // println!("from expansion"); snippet_with_macro_callsite(cx, err_arg.span, "_") } else { - // println!("just a snippet"); snippet(cx, err_arg.span, "_") }; let suggestion = if err_ty == expr_err_ty { @@ -106,8 +102,6 @@ impl<'tcx> LateLintPass<'tcx> for TryErr { } else { format!("return {}{}.into(){}", prefix, origin_snippet, suffix) }; - // println!("origin_snippet: {:#?}", origin_snippet); - // println!("suggestion: {:#?}", suggestion); span_lint_and_sugg( cx, diff --git a/tests/ui/deref_addrof.fixed b/tests/ui/deref_addrof.fixed index 689e9d552234..0795900558b6 100644 --- a/tests/ui/deref_addrof.fixed +++ b/tests/ui/deref_addrof.fixed @@ -38,6 +38,7 @@ fn main() { let b = *aref; } +#[rustfmt::skip] macro_rules! m { ($visitor: expr) => { $visitor diff --git a/tests/ui/deref_addrof.rs b/tests/ui/deref_addrof.rs index 57effce5d129..60c4318601bc 100644 --- a/tests/ui/deref_addrof.rs +++ b/tests/ui/deref_addrof.rs @@ -38,6 +38,7 @@ fn main() { let b = **&aref; } +#[rustfmt::skip] macro_rules! m { ($visitor: expr) => { *& $visitor diff --git a/tests/ui/deref_addrof.stderr b/tests/ui/deref_addrof.stderr index 52c1f7d1da8f..e85b30fa56eb 100644 --- a/tests/ui/deref_addrof.stderr +++ b/tests/ui/deref_addrof.stderr @@ -49,7 +49,7 @@ LL | let b = **&aref; | ^^^^^^ help: try this: `aref` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:43:9 + --> $DIR/deref_addrof.rs:44:9 | LL | *& $visitor | ^^^^^^^^^^^ help: try this: `$visitor` @@ -60,7 +60,7 @@ LL | m!(self) = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:50:9 + --> $DIR/deref_addrof.rs:51:9 | LL | *& mut $visitor | ^^^^^^^^^^^^^^^ help: try this: `$visitor` From 83e75f92079909aa07306633f26f42eccfb608e1 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Thu, 5 Nov 2020 18:00:34 +0100 Subject: [PATCH 5/5] Fix incorrect suggestion for `try_err` lint when `Err` arg is itself a macro --- clippy_lints/src/try_err.rs | 9 ++++++--- tests/ui/try_err.fixed | 18 ++++++++++++++++++ tests/ui/try_err.rs | 18 ++++++++++++++++++ tests/ui/try_err.stderr | 21 ++++++++++++++++----- 4 files changed, 58 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index 9c1185d30f21..e1dec63a98a4 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -1,6 +1,6 @@ use crate::utils::{ - in_macro, is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet, snippet_with_macro_callsite, - span_lint_and_sugg, + differing_macro_contexts, in_macro, is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet, + snippet_with_macro_callsite, span_lint_and_sugg, }; use if_chain::if_chain; use rustc_errors::Applicability; @@ -91,8 +91,11 @@ impl<'tcx> LateLintPass<'tcx> for TryErr { }; let expr_err_ty = cx.typeck_results().expr_ty(err_arg); + let differing_contexts = differing_macro_contexts(expr.span, err_arg.span); - let origin_snippet = if err_arg.span.from_expansion() && !in_macro(expr.span) { + let origin_snippet = if in_macro(expr.span) && in_macro(err_arg.span) && differing_contexts { + snippet(cx, err_arg.span.ctxt().outer_expn_data().call_site, "_") + } else if err_arg.span.from_expansion() && !in_macro(expr.span) { snippet_with_macro_callsite(cx, err_arg.span, "_") } else { snippet(cx, err_arg.span, "_") diff --git a/tests/ui/try_err.fixed b/tests/ui/try_err.fixed index 053dd45f23e1..aa43e69f79e8 100644 --- a/tests/ui/try_err.fixed +++ b/tests/ui/try_err.fixed @@ -88,8 +88,26 @@ macro_rules! try_validation { }}; } +macro_rules! ret_one { + () => { + 1 + }; +} + +macro_rules! try_validation_in_macro { + ($e: expr) => {{ + match $e { + Ok(_) => 0, + Err(_) => return Err(ret_one!()), + } + }}; +} + fn calling_macro() -> Result { + // macro try_validation!(Ok::<_, i32>(5)); + // `Err` arg is another macro + try_validation_in_macro!(Ok::<_, i32>(5)); Ok(5) } diff --git a/tests/ui/try_err.rs b/tests/ui/try_err.rs index 215ca6a07e62..df3a9dc5367f 100644 --- a/tests/ui/try_err.rs +++ b/tests/ui/try_err.rs @@ -88,8 +88,26 @@ macro_rules! try_validation { }}; } +macro_rules! ret_one { + () => { + 1 + }; +} + +macro_rules! try_validation_in_macro { + ($e: expr) => {{ + match $e { + Ok(_) => 0, + Err(_) => Err(ret_one!())?, + } + }}; +} + fn calling_macro() -> Result { + // macro try_validation!(Ok::<_, i32>(5)); + // `Err` arg is another macro + try_validation_in_macro!(Ok::<_, i32>(5)); Ok(5) } diff --git a/tests/ui/try_err.stderr b/tests/ui/try_err.stderr index 443c8d084721..3905ed2476b0 100644 --- a/tests/ui/try_err.stderr +++ b/tests/ui/try_err.stderr @@ -40,28 +40,39 @@ LL | try_validation!(Ok::<_, i32>(5)); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:122:9 + --> $DIR/try_err.rs:101:23 + | +LL | Err(_) => Err(ret_one!())?, + | ^^^^^^^^^^^^^^^^ help: try this: `return Err(ret_one!())` +... +LL | try_validation_in_macro!(Ok::<_, i32>(5)); + | ------------------------------------------ in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: returning an `Err(_)` with the `?` operator + --> $DIR/try_err.rs:140:9 | LL | Err(foo!())?; | ^^^^^^^^^^^^ help: try this: `return Err(foo!())` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:129:9 + --> $DIR/try_err.rs:147:9 | LL | Err(io::ErrorKind::WriteZero)? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:131:9 + --> $DIR/try_err.rs:149:9 | LL | Err(io::Error::new(io::ErrorKind::InvalidInput, "error"))? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:139:9 + --> $DIR/try_err.rs:157:9 | LL | Err(io::ErrorKind::NotFound)? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))` -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors