about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs3
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs58
-rw-r--r--src/test/ui/nll/issue-98170.rs25
-rw-r--r--src/test/ui/nll/issue-98170.stderr44
4 files changed, 125 insertions, 5 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
index 9d81330745f..d359d7efb62 100644
--- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
@@ -62,7 +62,8 @@ impl OutlivesSuggestionBuilder {
             | RegionNameSource::AnonRegionFromUpvar(..)
             | RegionNameSource::AnonRegionFromOutput(..)
             | RegionNameSource::AnonRegionFromYieldTy(..)
-            | RegionNameSource::AnonRegionFromAsyncFn(..) => {
+            | RegionNameSource::AnonRegionFromAsyncFn(..)
+            | RegionNameSource::AnonRegionFromImplSignature(..) => {
                 debug!("Region {:?} is NOT suggestable", name);
                 false
             }
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 1db4b902f71..8f3699553d9 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -6,7 +6,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_middle::ty::print::RegionHighlightMode;
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, RegionVid, Ty};
+use rustc_middle::ty::{self, DefIdTree, RegionVid, Ty};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 
@@ -45,6 +45,8 @@ pub(crate) enum RegionNameSource {
     AnonRegionFromYieldTy(Span, String),
     /// An anonymous region from an async fn.
     AnonRegionFromAsyncFn(Span),
+    /// An anonymous region from an impl self type or trait
+    AnonRegionFromImplSignature(Span, &'static str),
 }
 
 /// Describes what to highlight to explain to the user that we're giving an anonymous region a
@@ -75,7 +77,8 @@ impl RegionName {
             | RegionNameSource::AnonRegionFromUpvar(..)
             | RegionNameSource::AnonRegionFromOutput(..)
             | RegionNameSource::AnonRegionFromYieldTy(..)
-            | RegionNameSource::AnonRegionFromAsyncFn(..) => false,
+            | RegionNameSource::AnonRegionFromAsyncFn(..)
+            | RegionNameSource::AnonRegionFromImplSignature(..) => false,
         }
     }
 
@@ -87,7 +90,8 @@ impl RegionName {
             | RegionNameSource::SynthesizedFreeEnvRegion(span, _)
             | RegionNameSource::AnonRegionFromUpvar(span, _)
             | RegionNameSource::AnonRegionFromYieldTy(span, _)
-            | RegionNameSource::AnonRegionFromAsyncFn(span) => Some(span),
+            | RegionNameSource::AnonRegionFromAsyncFn(span)
+            | RegionNameSource::AnonRegionFromImplSignature(span, _) => Some(span),
             RegionNameSource::AnonRegionFromArgument(ref highlight)
             | RegionNameSource::AnonRegionFromOutput(ref highlight, _) => match *highlight {
                 RegionNameHighlight::MatchedHirTy(span)
@@ -166,6 +170,12 @@ impl RegionName {
             RegionNameSource::AnonRegionFromYieldTy(span, type_name) => {
                 diag.span_label(*span, format!("yield type is {type_name}"));
             }
+            RegionNameSource::AnonRegionFromImplSignature(span, location) => {
+                diag.span_label(
+                    *span,
+                    format!("lifetime `{self}` appears in the `impl`'s {location}"),
+                );
+            }
             RegionNameSource::Static => {}
         }
     }
@@ -240,7 +250,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
             .or_else(|| self.give_name_if_anonymous_region_appears_in_arguments(fr))
             .or_else(|| self.give_name_if_anonymous_region_appears_in_upvars(fr))
             .or_else(|| self.give_name_if_anonymous_region_appears_in_output(fr))
-            .or_else(|| self.give_name_if_anonymous_region_appears_in_yield_ty(fr));
+            .or_else(|| self.give_name_if_anonymous_region_appears_in_yield_ty(fr))
+            .or_else(|| self.give_name_if_anonymous_region_appears_in_impl_signature(fr));
 
         if let Some(ref value) = value {
             self.region_names.try_borrow_mut().unwrap().insert(fr, value.clone());
@@ -847,4 +858,43 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
             source: RegionNameSource::AnonRegionFromYieldTy(yield_span, type_name),
         })
     }
+
+    fn give_name_if_anonymous_region_appears_in_impl_signature(
+        &self,
+        fr: RegionVid,
+    ) -> Option<RegionName> {
+        let ty::ReEarlyBound(region) = *self.to_error_region(fr)? else {
+            return None;
+        };
+        if region.has_name() {
+            return None;
+        };
+
+        let tcx = self.infcx.tcx;
+        let body_parent_did = tcx.opt_parent(self.mir_def_id().to_def_id())?;
+        if tcx.parent(region.def_id) != body_parent_did
+            || tcx.def_kind(body_parent_did) != DefKind::Impl
+        {
+            return None;
+        }
+
+        let mut found = false;
+        tcx.fold_regions(tcx.type_of(body_parent_did), &mut true, |r: ty::Region<'tcx>, _| {
+            if *r == ty::ReEarlyBound(region) {
+                found = true;
+            }
+            r
+        });
+
+        Some(RegionName {
+            name: self.synthesize_region_name(),
+            source: RegionNameSource::AnonRegionFromImplSignature(
+                tcx.def_span(region.def_id),
+                // FIXME(compiler-errors): Does this ever actually show up
+                // anywhere other than the self type? I couldn't create an
+                // example of a `'_` in the impl's trait being referenceable.
+                if found { "self type" } else { "header" },
+            ),
+        })
+    }
 }
diff --git a/src/test/ui/nll/issue-98170.rs b/src/test/ui/nll/issue-98170.rs
new file mode 100644
index 00000000000..6bb12f52d3f
--- /dev/null
+++ b/src/test/ui/nll/issue-98170.rs
@@ -0,0 +1,25 @@
+pub struct MyStruct<'a> {
+    field: &'a [u32],
+}
+
+impl MyStruct<'_> {
+    pub fn new<'a>(field: &'a [u32]) -> MyStruct<'a> {
+        Self { field }
+        //~^ ERROR lifetime may not live long enough
+        //~| ERROR lifetime may not live long enough
+    }
+}
+
+trait Trait<'a> {
+    fn new(field: &'a [u32]) -> MyStruct<'a>;
+}
+
+impl<'a> Trait<'a> for MyStruct<'_> {
+    fn new(field: &'a [u32]) -> MyStruct<'a> {
+        Self { field }
+        //~^ ERROR lifetime may not live long enough
+        //~| ERROR lifetime may not live long enough
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/issue-98170.stderr b/src/test/ui/nll/issue-98170.stderr
new file mode 100644
index 00000000000..0d17365e71b
--- /dev/null
+++ b/src/test/ui/nll/issue-98170.stderr
@@ -0,0 +1,44 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-98170.rs:7:9
+   |
+LL | impl MyStruct<'_> {
+   |               -- lifetime `'1` appears in the `impl`'s self type
+LL |     pub fn new<'a>(field: &'a [u32]) -> MyStruct<'a> {
+   |                -- lifetime `'a` defined here
+LL |         Self { field }
+   |         ^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/issue-98170.rs:7:16
+   |
+LL | impl MyStruct<'_> {
+   |               -- lifetime `'1` appears in the `impl`'s self type
+LL |     pub fn new<'a>(field: &'a [u32]) -> MyStruct<'a> {
+   |                -- lifetime `'a` defined here
+LL |         Self { field }
+   |                ^^^^^ this usage requires that `'a` must outlive `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/issue-98170.rs:19:9
+   |
+LL | impl<'a> Trait<'a> for MyStruct<'_> {
+   |      --                         -- lifetime `'1` appears in the `impl`'s self type
+   |      |
+   |      lifetime `'a` defined here
+LL |     fn new(field: &'a [u32]) -> MyStruct<'a> {
+LL |         Self { field }
+   |         ^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/issue-98170.rs:19:16
+   |
+LL | impl<'a> Trait<'a> for MyStruct<'_> {
+   |      --                         -- lifetime `'1` appears in the `impl`'s self type
+   |      |
+   |      lifetime `'a` defined here
+LL |     fn new(field: &'a [u32]) -> MyStruct<'a> {
+LL |         Self { field }
+   |                ^^^^^ this usage requires that `'a` must outlive `'1`
+
+error: aborting due to 4 previous errors
+