From d2b1bb8a9b7a0a73b8da36d12798f4e848ed7171 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 10 Apr 2022 22:15:31 -0700 Subject: [PATCH] use find_ancestor_inside to get right span in CastCheck --- compiler/rustc_typeck/src/check/cast.rs | 37 +++++++++++++------------ src/test/ui/cast/cast-macro-lhs.rs | 12 ++++++++ src/test/ui/cast/cast-macro-lhs.stderr | 11 ++++++++ 3 files changed, 42 insertions(+), 18 deletions(-) create mode 100644 src/test/ui/cast/cast-macro-lhs.rs create mode 100644 src/test/ui/cast/cast-macro-lhs.stderr diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 6091b8fee00b6..88100fcc453c3 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -55,6 +55,7 @@ use rustc_trait_selection::traits::error_reporting::report_object_safety_error; pub struct CastCheck<'tcx> { expr: &'tcx hir::Expr<'tcx>, expr_ty: Ty<'tcx>, + expr_span: Span, cast_ty: Ty<'tcx>, cast_span: Span, span: Span, @@ -207,7 +208,8 @@ impl<'a, 'tcx> CastCheck<'tcx> { cast_span: Span, span: Span, ) -> Result, ErrorGuaranteed> { - let check = CastCheck { expr, expr_ty, cast_ty, cast_span, span }; + let expr_span = expr.span.find_ancestor_inside(span).unwrap_or(expr.span); + let check = CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span }; // For better error messages, check for some obviously unsized // cases now. We do a more thorough check at the end, once @@ -240,15 +242,15 @@ impl<'a, 'tcx> CastCheck<'tcx> { error_span, format!("cannot cast `{}` as `{}`", fcx.ty_to_string(self.expr_ty), cast_ty), ); - if let Ok(snippet) = fcx.sess().source_map().span_to_snippet(self.expr.span) { + if let Ok(snippet) = fcx.sess().source_map().span_to_snippet(self.expr_span) { err.span_suggestion( - self.expr.span, + self.expr_span, "dereference the expression", format!("*{}", snippet), Applicability::MaybeIncorrect, ); } else { - err.span_help(self.expr.span, "dereference the expression with `*`"); + err.span_help(self.expr_span, "dereference the expression with `*`"); } err.emit(); } @@ -315,7 +317,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { struct_span_err!(fcx.tcx.sess, self.span, E0054, "cannot cast as `bool`"); if self.expr_ty.is_numeric() { - match fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) { + match fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) { Ok(snippet) => { err.span_suggestion( self.span, @@ -440,7 +442,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { } if sugg_mutref { err.span_label(self.span, "invalid cast"); - err.span_note(self.expr.span, "this reference is immutable"); + err.span_note(self.expr_span, "this reference is immutable"); err.span_note(self.cast_span, "trying to cast to a mutable reference type"); } else if let Some((sugg, remove_cast)) = sugg { err.span_label(self.span, "invalid cast"); @@ -449,7 +451,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { .tcx .sess .source_map() - .span_to_snippet(self.expr.span) + .span_to_snippet(self.expr_span) .map_or(false, |snip| snip.starts_with('(')); // Very crude check to see whether the expression must be wrapped @@ -458,14 +460,14 @@ impl<'a, 'tcx> CastCheck<'tcx> { let needs_parens = !has_parens && matches!(self.expr.kind, hir::ExprKind::Cast(..)); - let mut suggestion = vec![(self.expr.span.shrink_to_lo(), sugg)]; + let mut suggestion = vec![(self.expr_span.shrink_to_lo(), sugg)]; if needs_parens { suggestion[0].1 += "("; - suggestion.push((self.expr.span.shrink_to_hi(), ")".to_string())); + suggestion.push((self.expr_span.shrink_to_hi(), ")".to_string())); } if remove_cast { suggestion.push(( - self.expr.span.shrink_to_hi().to(self.cast_span), + self.expr_span.shrink_to_hi().to(self.cast_span), String::new(), )); } @@ -481,7 +483,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { ) { let mut label = true; // Check `impl From for self.cast_ty {}` for accurate suggestion: - if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) { + if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) { if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::From) { let ty = fcx.resolve_vars_if_possible(self.cast_ty); // Erase regions to avoid panic in `prove_value` when calling @@ -550,7 +552,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { if fcx.tcx.sess.is_nightly_build() { err.span_label( - self.expr.span, + self.expr_span, "consider casting this expression to `*const ()`, \ then using `core::ptr::from_raw_parts`", ); @@ -651,7 +653,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { } } _ => { - err.span_help(self.expr.span, "consider using a box or reference as appropriate"); + err.span_help(self.expr_span, "consider using a box or reference as appropriate"); } } err.emit() @@ -685,7 +687,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { #[instrument(skip(fcx), level = "debug")] pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) { - self.expr_ty = fcx.structurally_resolved_type(self.expr.span, self.expr_ty); + self.expr_ty = fcx.structurally_resolved_type(self.expr_span, self.expr_ty); self.cast_ty = fcx.structurally_resolved_type(self.cast_span, self.cast_ty); debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty); @@ -741,7 +743,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { ty::FnDef(..) => { // Attempt a coercion to a fn pointer type. let f = fcx.normalize_associated_types_in( - self.expr.span, + self.expr_span, self.expr_ty.fn_sig(fcx.tcx), ); let res = fcx.try_coerce( @@ -997,7 +999,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { )); let msg = "use `.addr()` to obtain the address of a pointer"; - if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) { + if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) { let scalar_cast = match t_c { ty::cast::IntTy::U(ty::UintTy::Usize) => String::new(), _ => format!(" as {}", self.cast_ty), @@ -1027,13 +1029,12 @@ impl<'a, 'tcx> CastCheck<'tcx> { self.expr.hir_id, self.span, |err| { - let mut err = err.build(&format!( "strict provenance disallows casting integer `{}` to pointer `{}`", self.expr_ty, self.cast_ty )); let msg = "use `.with_addr()` to adjust a valid pointer in the same allocation, to this address"; - if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) { + if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) { err.span_suggestion( self.span, msg, diff --git a/src/test/ui/cast/cast-macro-lhs.rs b/src/test/ui/cast/cast-macro-lhs.rs new file mode 100644 index 0000000000000..b509b3239bc58 --- /dev/null +++ b/src/test/ui/cast/cast-macro-lhs.rs @@ -0,0 +1,12 @@ +// Test to make sure we suggest "consider casting" on the right span + +macro_rules! foo { + () => { 0 } +} + +fn main() { + let x = foo!() as *const [u8]; + //~^ ERROR cannot cast `usize` to a pointer that is wide + //~| NOTE creating a `*const [u8]` requires both an address and a length + //~| NOTE consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts` +} diff --git a/src/test/ui/cast/cast-macro-lhs.stderr b/src/test/ui/cast/cast-macro-lhs.stderr new file mode 100644 index 0000000000000..db7ce57e15062 --- /dev/null +++ b/src/test/ui/cast/cast-macro-lhs.stderr @@ -0,0 +1,11 @@ +error[E0606]: cannot cast `usize` to a pointer that is wide + --> $DIR/cast-macro-lhs.rs:8:23 + | +LL | let x = foo!() as *const [u8]; + | ------ ^^^^^^^^^^^ creating a `*const [u8]` requires both an address and a length + | | + | consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0606`.