diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 89e032b222fec..10e9bde0d972b 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -597,6 +597,14 @@ impl Span { if !expn_data.is_root() { Some(expn_data.call_site) } else { None } } + /// Walk down the expansion ancestors to find a span that's contained within `outer`. + pub fn find_ancestor_inside(mut self, outer: Span) -> Option { + while !outer.contains(self) { + self = self.parent()?; + } + Some(self) + } + /// Edition of the crate from which this span came. pub fn edition(self) -> edition::Edition { self.ctxt().edition() diff --git a/compiler/rustc_typeck/src/check/method/prelude2021.rs b/compiler/rustc_typeck/src/check/method/prelude2021.rs index 1347f56258ea1..05f1b3740aeb1 100644 --- a/compiler/rustc_typeck/src/check/method/prelude2021.rs +++ b/compiler/rustc_typeck/src/check/method/prelude2021.rs @@ -156,15 +156,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { segment.ident.name )); - let (self_adjusted, precise) = self.adjust_expr(pick, self_expr); + let (self_adjusted, precise) = self.adjust_expr(pick, self_expr, sp); if precise { let args = args .iter() .skip(1) .map(|arg| { + let span = arg.span.find_ancestor_inside(sp).unwrap_or_default(); format!( ", {}", - self.sess().source_map().span_to_snippet(arg.span).unwrap() + self.sess().source_map().span_to_snippet(span).unwrap() ) }) .collect::(); @@ -272,11 +273,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { method_name.name )); - let mut self_ty_name = self - .sess() - .source_map() - .span_to_snippet(self_ty_span) - .unwrap_or_else(|_| self_ty.to_string()); + let mut self_ty_name = self_ty_span + .find_ancestor_inside(span) + .and_then(|span| self.sess().source_map().span_to_snippet(span).ok()) + .unwrap_or_else(|| self_ty.to_string()); // Get the number of generics the self type has (if an Adt) unless we can determine that // the user has written the self type with generics already which we (naively) do by looking @@ -370,7 +370,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Creates a string version of the `expr` that includes explicit adjustments. /// Returns the string and also a bool indicating whther this is a *precise* /// suggestion. - fn adjust_expr(&self, pick: &Pick<'tcx>, expr: &hir::Expr<'tcx>) -> (String, bool) { + fn adjust_expr( + &self, + pick: &Pick<'tcx>, + expr: &hir::Expr<'tcx>, + outer: Span, + ) -> (String, bool) { let derefs = "*".repeat(pick.autoderefs); let autoref = match pick.autoref_or_ptr_adjustment { @@ -379,12 +384,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "", }; - let (expr_text, precise) = - if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) { - (expr_text, true) - } else { - ("(..)".to_string(), false) - }; + let (expr_text, precise) = if let Some(expr_text) = expr + .span + .find_ancestor_inside(outer) + .and_then(|span| self.sess().source_map().span_to_snippet(span).ok()) + { + (expr_text, true) + } else { + ("(..)".to_string(), false) + }; let adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = pick.autoref_or_ptr_adjustment diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 75fd545060c4a..a25d0f8064404 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -680,15 +680,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { migrated_variables_concat ); - let mut closure_body_span = self.tcx.hir().span(body_id.hir_id); - // If the body was entirely expanded from a macro // invocation, i.e. the body is not contained inside the // closure span, then we walk up the expansion until we // find the span before the expansion. - while !closure_body_span.is_dummy() && !closure_span.contains(closure_body_span) { - closure_body_span = closure_body_span.parent().unwrap_or(DUMMY_SP); - } + let closure_body_span = self.tcx.hir().span(body_id.hir_id) + .find_ancestor_inside(closure_span) + .unwrap_or(DUMMY_SP); if let Ok(s) = self.tcx.sess.source_map().span_to_snippet(closure_body_span) { let mut lines = s.lines(); diff --git a/src/test/ui/rust-2021/future-prelude-collision-macros.fixed b/src/test/ui/rust-2021/future-prelude-collision-macros.fixed new file mode 100644 index 0000000000000..a97dc176e1b8b --- /dev/null +++ b/src/test/ui/rust-2021/future-prelude-collision-macros.fixed @@ -0,0 +1,45 @@ +// run-rustfix +// edition:2018 +// check-pass +#![warn(rust_2021_prelude_collisions)] +#![allow(unreachable_code)] + +macro_rules! foo { + () => {{ + 123; + S + }}; +} + +trait MyTry { + fn try_into(self, _: u8); +} + +struct S; + +impl MyTry for S { + fn try_into(self, _: u8) {} +} + +trait TryFromU8: Sized { + fn try_from(_: u8); +} + +impl TryFromU8 for u32 { + fn try_from(_: u8) {} +} + +macro_rules! bar { + () => { + u32 + }; +} + +fn main() { + MyTry::try_into(foo!(), todo!()); + //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021 + //~| WARNING this is accepted in the current edition + ::try_from(0); + //~^ WARNING trait-associated function `try_from` will become ambiguous in Rust 2021 + //~| WARNING this is accepted in the current edition +} diff --git a/src/test/ui/rust-2021/future-prelude-collision-macros.rs b/src/test/ui/rust-2021/future-prelude-collision-macros.rs new file mode 100644 index 0000000000000..82484b5b3688d --- /dev/null +++ b/src/test/ui/rust-2021/future-prelude-collision-macros.rs @@ -0,0 +1,45 @@ +// run-rustfix +// edition:2018 +// check-pass +#![warn(rust_2021_prelude_collisions)] +#![allow(unreachable_code)] + +macro_rules! foo { + () => {{ + 123; + S + }}; +} + +trait MyTry { + fn try_into(self, _: u8); +} + +struct S; + +impl MyTry for S { + fn try_into(self, _: u8) {} +} + +trait TryFromU8: Sized { + fn try_from(_: u8); +} + +impl TryFromU8 for u32 { + fn try_from(_: u8) {} +} + +macro_rules! bar { + () => { + u32 + }; +} + +fn main() { + foo!().try_into(todo!()); + //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021 + //~| WARNING this is accepted in the current edition + ::try_from(0); + //~^ WARNING trait-associated function `try_from` will become ambiguous in Rust 2021 + //~| WARNING this is accepted in the current edition +} diff --git a/src/test/ui/rust-2021/future-prelude-collision-macros.stderr b/src/test/ui/rust-2021/future-prelude-collision-macros.stderr new file mode 100644 index 0000000000000..4c3543ca782e8 --- /dev/null +++ b/src/test/ui/rust-2021/future-prelude-collision-macros.stderr @@ -0,0 +1,25 @@ +warning: trait method `try_into` will become ambiguous in Rust 2021 + --> $DIR/future-prelude-collision-macros.rs:39:5 + | +LL | foo!().try_into(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `MyTry::try_into(foo!(), todo!())` + | +note: the lint level is defined here + --> $DIR/future-prelude-collision-macros.rs:4:9 + | +LL | #![warn(rust_2021_prelude_collisions)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021! + = note: for more information, see + +warning: trait-associated function `try_from` will become ambiguous in Rust 2021 + --> $DIR/future-prelude-collision-macros.rs:42:5 + | +LL | ::try_from(0); + | ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `::try_from` + | + = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021! + = note: for more information, see + +warning: 2 warnings emitted +