Change:
The tokens generated by procmacro (e.g. from ) use , which makes some suggestions produce invalid output: It's a bit tricky, because this callsite span does point into the current crate (to ), so this situaiton isn't detected in the same way as external .
Looks like should be used in more places. That one detects this span by checking if is a dummy or imported.
I'm working on a fix specifically for these typeck/borrowing suggestions. Not sure how many other suggestions have the same problem.
this is a prevalent problem. We need to add metadata to spans to distinguish call sites explicitly in an easy way and always ignore suggestions in them.

Discussion:
use rustc_hir as hir; use rustc_hir::lang_items::LangItem; use rustc_hir::{is_range_literal, Node}; <ins> use rustc_middle::lint::in_external_macro; </ins> use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut}; use rustc_span::symbol::sym;

checked_ty: Ty<'tcx>, expected: Ty<'tcx>, ) -> Option<(Span, &'static str, String, Applicability)> { <del> let sm = self.sess().source_map(); </del> <ins> let sess = self.sess(); </ins> let sp = expr.span; <del> if sm.is_imported(sp) { // Ignore if span is from within a macro #41858, #58298. We previously used the macro // call span, but that breaks down when the type error comes from multiple calls down. </del> <ins> // If the span is from an external macro, there's no suggestion we can make. if in_external_macro(sess, sp) { </ins> return None; } <ins> let sm = sess.source_map(); </ins> let replace_prefix = |s: &str, old: &str, new: &str| { s.strip_prefix(old).map(|stripped| new.to_string() + stripped) };

let is_struct_pat_shorthand_field = self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, sp); <del> // If the span is from a macro, then it's hard to extract the text // and make a good suggestion, so don't bother. let is_macro = sp.from_expansion() && sp.desugaring_kind().is_none(); </del> // `ExprKind::DropTemps` is semantically irrelevant for these suggestions. let expr = expr.peel_drop_temps();

hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref expr), _, &ty::Ref(_, checked, _), <del> ) if { self.infcx.can_sub(self.param_env, checked, &expected).is_ok() && !is_macro } => { </del> <ins> ) if self.infcx.can_sub(self.param_env, checked, &expected).is_ok() => { </ins> // We have `&T`, check if what was expected was `T`. If so, // we may want to suggest removing a `&`. if sm.is_imported(expr.span) {

} return None; } <del> if let Ok(code) = sm.span_to_snippet(expr.span) { return Some(( sp, "consider removing the borrow", code, Applicability::MachineApplicable, )); </del> <ins> if sp.contains(expr.span) { if let Ok(code) = sm.span_to_snippet(expr.span) { return Some(( sp, "consider removing the borrow", code, Applicability::MachineApplicable, )); } </ins> } } (

} } } <del> _ if sp == expr.span && !is_macro => { </del> <ins> _ if sp == expr.span => { </ins> if let Some(steps) = self.deref_steps(checked_ty, expected) { let expr = expr.peel_blocks();

<ins> // force-host // no-prefer-dynamic #![crate_type = "proc-macro"] #![feature(proc_macro_quote)] extern crate proc_macro; use proc_macro::{quote, TokenStream}; #[proc_macro_attribute] pub fn hello(_: TokenStream, _: TokenStream) -> TokenStream { quote!( fn f(_: &mut i32) {} fn g() { f(123); } ) } </ins>

<ins> // run-check // aux-build:proc-macro-type-error.rs extern crate proc_macro_type_error; use proc_macro_type_error::hello; #[hello] //~ERROR mismatched types fn abc() {} fn x(_: &mut i32) {} macro_rules! bla { () => { x(123); //~^ ERROR mismatched types //~| SUGGESTION &mut 123 }; ($v:expr) => { x($v) } } fn main() { bla!(); bla!(456); //~^ ERROR mismatched types //~| SUGGESTION &mut 456 } </ins>

<ins> error[E0308]: mismatched types --> $DIR/suggest-ref-macro.rs:8:1 | LL | #[hello] | ^^^^^^^^ expected `&mut i32`, found integer | = note: this error originates in the attribute macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> $DIR/suggest-ref-macro.rs:15:11 | LL |         x(123); |           ^^^ |           | |           expected `&mut i32`, found integer |           help: consider mutably borrowing here: `&mut 123` ... LL |     bla!(); |     ------- in this macro invocation | = note: this error originates in the macro `bla` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> $DIR/suggest-ref-macro.rs:26:10 | LL |     bla!(456); |          ^^^ |          | |          expected `&mut i32`, found integer |          help: consider mutably borrowing here: `&mut 456` error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0308`. </ins>