about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_span/src/lib.rs8
-rw-r--r--compiler/rustc_typeck/src/check/method/prelude2021.rs36
-rw-r--r--compiler/rustc_typeck/src/check/upvar.rs8
-rw-r--r--src/test/ui/rust-2021/future-prelude-collision-macros.fixed45
-rw-r--r--src/test/ui/rust-2021/future-prelude-collision-macros.rs45
-rw-r--r--src/test/ui/rust-2021/future-prelude-collision-macros.stderr25
6 files changed, 148 insertions, 19 deletions
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 89e032b222f..10e9bde0d97 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<Span> {
+        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 1347f56258e..05f1b3740ae 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::<String>();
@@ -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 75fd545060c..a25d0f80644 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 00000000000..a97dc176e1b
--- /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<T> {
+    fn try_into(self, _: u8);
+}
+
+struct S;
+
+impl MyTry<i32> 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
+    <bar!() as TryFromU8>::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 00000000000..82484b5b368
--- /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<T> {
+    fn try_into(self, _: u8);
+}
+
+struct S;
+
+impl MyTry<i32> 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
+    <bar!()>::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 00000000000..4c3543ca782
--- /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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+
+warning: trait-associated function `try_from` will become ambiguous in Rust 2021
+  --> $DIR/future-prelude-collision-macros.rs:42:5
+   |
+LL |     <bar!()>::try_from(0);
+   |     ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `<bar!() as TryFromU8>::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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+
+warning: 2 warnings emitted
+