about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs33
-rw-r--r--library/core/src/iter/traits/iterator.rs1
-rw-r--r--src/test/ui/issues/issue-81584.fixed8
-rw-r--r--src/test/ui/issues/issue-81584.rs8
-rw-r--r--src/test/ui/issues/issue-81584.stderr14
-rw-r--r--src/test/ui/static/static-reference-to-fn-2.stderr2
6 files changed, 62 insertions, 4 deletions
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
index b0b58a8d003..24b9408ffb6 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
@@ -10,16 +10,18 @@ use rustc_middle::mir::{
     FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
     ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
 };
-use rustc_middle::ty::{self, suggest_constraining_type_param, Instance, Ty};
-use rustc_span::{source_map::DesugaringKind, symbol::sym, Span};
+use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TypeFoldable};
+use rustc_span::source_map::DesugaringKind;
+use rustc_span::symbol::sym;
+use rustc_span::Span;
 
 use crate::dataflow::drop_flag_effects;
 use crate::dataflow::indexes::{MoveOutIndex, MovePathIndex};
 use crate::util::borrowck_errors;
 
 use crate::borrow_check::{
-    borrow_set::BorrowData, prefixes::IsPrefixOf, InitializationRequiringAction, MirBorrowckCtxt,
-    PrefixSet, WriteKind,
+    borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
+    InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
 };
 
 use super::{
@@ -1267,6 +1269,29 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
         if return_span != borrow_span {
             err.span_label(borrow_span, note);
+
+            let tcx = self.infcx.tcx;
+            let ty_params = ty::List::empty();
+
+            let return_ty = self.regioncx.universal_regions().unnormalized_output_ty;
+            let return_ty = tcx.erase_regions(return_ty);
+
+            // to avoid panics
+            if !return_ty.has_infer_types() {
+                if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) {
+                    if tcx.type_implements_trait((iter_trait, return_ty, ty_params, self.param_env))
+                    {
+                        if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(return_span) {
+                            err.span_suggestion_hidden(
+                                return_span,
+                                "use `.collect()` to allocate the iterator",
+                                format!("{}{}", snippet, ".collect::<Vec<_>>()"),
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+                    }
+                }
+            }
         }
 
         Some(err)
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index f28c4673cc0..e179ce01c41 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -93,6 +93,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
     message = "`{Self}` is not an iterator"
 )]
 #[doc(spotlight)]
+#[rustc_diagnostic_item = "Iterator"]
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 pub trait Iterator {
     /// The type of the elements being iterated over.
diff --git a/src/test/ui/issues/issue-81584.fixed b/src/test/ui/issues/issue-81584.fixed
new file mode 100644
index 00000000000..1cad59f1062
--- /dev/null
+++ b/src/test/ui/issues/issue-81584.fixed
@@ -0,0 +1,8 @@
+// run-rustfix
+fn main() {
+        let _ = vec![vec![0, 1], vec![2]]
+            .into_iter()
+            .map(|y| y.iter().map(|x| x + 1).collect::<Vec<_>>())
+                  //~^ ERROR cannot return value referencing function parameter `y`
+            .collect::<Vec<_>>();
+}
diff --git a/src/test/ui/issues/issue-81584.rs b/src/test/ui/issues/issue-81584.rs
new file mode 100644
index 00000000000..452288db08b
--- /dev/null
+++ b/src/test/ui/issues/issue-81584.rs
@@ -0,0 +1,8 @@
+// run-rustfix
+fn main() {
+        let _ = vec![vec![0, 1], vec![2]]
+            .into_iter()
+            .map(|y| y.iter().map(|x| x + 1))
+                  //~^ ERROR cannot return value referencing function parameter `y`
+            .collect::<Vec<_>>();
+}
diff --git a/src/test/ui/issues/issue-81584.stderr b/src/test/ui/issues/issue-81584.stderr
new file mode 100644
index 00000000000..d57f1b778df
--- /dev/null
+++ b/src/test/ui/issues/issue-81584.stderr
@@ -0,0 +1,14 @@
+error[E0515]: cannot return value referencing function parameter `y`
+  --> $DIR/issue-81584.rs:5:22
+   |
+LL |             .map(|y| y.iter().map(|x| x + 1))
+   |                      -^^^^^^^^^^^^^^^^^^^^^^
+   |                      |
+   |                      returns a value referencing data owned by the current function
+   |                      `y` is borrowed here
+   |
+   = help: use `.collect()` to allocate the iterator
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0515`.
diff --git a/src/test/ui/static/static-reference-to-fn-2.stderr b/src/test/ui/static/static-reference-to-fn-2.stderr
index 028e11a60ce..ff15884bd44 100644
--- a/src/test/ui/static/static-reference-to-fn-2.stderr
+++ b/src/test/ui/static/static-reference-to-fn-2.stderr
@@ -40,6 +40,8 @@ LL | |         statefn: &id(state1 as StateMachineFunc)
    | |                   ------------------------------ temporary value created here
 LL | |     }
    | |_____^ returns a value referencing data owned by the current function
+   |
+   = help: use `.collect()` to allocate the iterator
 
 error: aborting due to 4 previous errors