diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs index 73a04d78519c8..ad8cc5d279af1 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs @@ -2,6 +2,7 @@ //! where one region is named and the other is anonymous. use rustc_errors::Diag; +use rustc_middle::ty; use tracing::debug; use crate::error_reporting::infer::nice_region_error::NiceRegionError; @@ -72,7 +73,18 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { { return None; } + let orig_ty = anon_param_info.orig_param_ty; + // Don't suggest naming the outer lifetime when it already appears in the pointee + // (e.g. `&'a mut Buffer<'a>`); point at borrow splitting instead. + let suggestion_would_alias_lifetime = + if let ty::Ref(_, orig_inner_ty, ty::Mutability::Mut) = orig_ty.kind() { + self.tcx().any_free_region_meets(orig_inner_ty, |r| r == named) + } else { + false + }; + let named = named.to_string(); + let new_ty_span = if suggestion_would_alias_lifetime { None } else { Some(new_ty_span) }; let err = match param.pat.simple_ident() { Some(simple_ident) => ExplicitLifetimeRequired::WithIdent { span, @@ -80,8 +92,15 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { named, new_ty_span, new_ty, + link_nomicon: suggestion_would_alias_lifetime, + }, + None => ExplicitLifetimeRequired::WithParamType { + span, + named, + new_ty_span, + new_ty, + link_nomicon: suggestion_would_alias_lifetime, }, - None => ExplicitLifetimeRequired::WithParamType { span, named, new_ty_span, new_ty }, }; Some(self.tcx().sess.dcx().create_err(err)) } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs index 3ec97ce76ef07..50eeb3a243266 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs @@ -16,6 +16,8 @@ pub struct AnonymousParamInfo<'tcx> { pub param: &'tcx hir::Param<'tcx>, /// The type corresponding to the anonymous region parameter. pub param_ty: Ty<'tcx>, + /// The original type before region replacement. + pub orig_param_ty: Ty<'tcx>, /// The `ty::LateParamRegionKind` corresponding to the anonymous region. pub kind: ty::LateParamRegionKind, /// The `Span` of the parameter type. @@ -94,7 +96,14 @@ pub fn find_param_with_region<'tcx>( let ty_hir_id = fn_decl.inputs[index].hir_id; let param_ty_span = tcx.hir_span(ty_hir_id); let is_first = index == 0; - AnonymousParamInfo { param, param_ty: new_param_ty, param_ty_span, kind, is_first } + AnonymousParamInfo { + param, + param_ty: new_param_ty, + orig_param_ty: ty, + param_ty_span, + kind, + is_first, + } }) }) } diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 5a926dc46c707..662480587fdd2 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -868,8 +868,13 @@ pub(crate) enum ExplicitLifetimeRequired<'a> { applicability = "unspecified", style = "verbose" )] - new_ty_span: Span, + new_ty_span: Option, new_ty: Ty<'a>, + #[help( + "see \ + for more information about lifetime errors related to mutable references" + )] + link_nomicon: bool, }, #[diag("explicit lifetime required in parameter type", code = E0621)] WithParamType { @@ -883,8 +888,13 @@ pub(crate) enum ExplicitLifetimeRequired<'a> { applicability = "unspecified", style = "verbose" )] - new_ty_span: Span, + new_ty_span: Option, new_ty: Ty<'a>, + #[help( + "see \ + for more information about lifetime errors related to mutable references" + )] + link_nomicon: bool, }, } diff --git a/tests/ui/lifetimes/lifetime-errors/e0621-mut-ref-aliases-pointee-lifetime-distinct.rs b/tests/ui/lifetimes/lifetime-errors/e0621-mut-ref-aliases-pointee-lifetime-distinct.rs new file mode 100644 index 0000000000000..a6995df36567c --- /dev/null +++ b/tests/ui/lifetimes/lifetime-errors/e0621-mut-ref-aliases-pointee-lifetime-distinct.rs @@ -0,0 +1,10 @@ +// Regression test for #156682 +// When the suggested type would NOT alias the outer reference's lifetime with one +// already used inside the pointee, the normal suggestion should still apply. + +pub fn push<'a>(x: &mut Vec<&'a u8>, y: &u8) { + x.push(y); + //~^ ERROR explicit lifetime required in the type of `y` +} + +fn main() {} diff --git a/tests/ui/lifetimes/lifetime-errors/e0621-mut-ref-aliases-pointee-lifetime-distinct.stderr b/tests/ui/lifetimes/lifetime-errors/e0621-mut-ref-aliases-pointee-lifetime-distinct.stderr new file mode 100644 index 0000000000000..fdc087aa4d979 --- /dev/null +++ b/tests/ui/lifetimes/lifetime-errors/e0621-mut-ref-aliases-pointee-lifetime-distinct.stderr @@ -0,0 +1,14 @@ +error[E0621]: explicit lifetime required in the type of `y` + --> $DIR/e0621-mut-ref-aliases-pointee-lifetime-distinct.rs:6:5 + | +LL | x.push(y); + | ^^^^^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `y` + | +LL | pub fn push<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { + | ++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0621`. diff --git a/tests/ui/lifetimes/lifetime-errors/e0621-mut-ref-aliases-pointee-lifetime.rs b/tests/ui/lifetimes/lifetime-errors/e0621-mut-ref-aliases-pointee-lifetime.rs new file mode 100644 index 0000000000000..5b78d566bf98c --- /dev/null +++ b/tests/ui/lifetimes/lifetime-errors/e0621-mut-ref-aliases-pointee-lifetime.rs @@ -0,0 +1,23 @@ +// Regression test for #156682 +// E0621 should not suggest `&'a mut Buffer<'a>`, which would alias the outer +// reference's lifetime with one already used inside the pointee. + +pub struct Buffer<'a> { + buf: &'a mut [u8], +} + +pub fn foo<'a>(buffer: &mut Buffer<'a>) { + buffer.buf = &mut buffer.buf[..]; + //~^ ERROR explicit lifetime required in the type of `buffer` +} + +pub struct Wrapper<'a> { + inner: Buffer<'a>, +} + +pub fn baz<'a>(wrapper: &mut Wrapper<'a>) { + wrapper.inner.buf = &mut wrapper.inner.buf[..]; + //~^ ERROR explicit lifetime required in the type of `wrapper` +} + +fn main() {} diff --git a/tests/ui/lifetimes/lifetime-errors/e0621-mut-ref-aliases-pointee-lifetime.stderr b/tests/ui/lifetimes/lifetime-errors/e0621-mut-ref-aliases-pointee-lifetime.stderr new file mode 100644 index 0000000000000..488c96061a3e9 --- /dev/null +++ b/tests/ui/lifetimes/lifetime-errors/e0621-mut-ref-aliases-pointee-lifetime.stderr @@ -0,0 +1,19 @@ +error[E0621]: explicit lifetime required in the type of `buffer` + --> $DIR/e0621-mut-ref-aliases-pointee-lifetime.rs:10:5 + | +LL | buffer.buf = &mut buffer.buf[..]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required + | + = help: see for more information about lifetime errors related to mutable references + +error[E0621]: explicit lifetime required in the type of `wrapper` + --> $DIR/e0621-mut-ref-aliases-pointee-lifetime.rs:19:5 + | +LL | wrapper.inner.buf = &mut wrapper.inner.buf[..]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required + | + = help: see for more information about lifetime errors related to mutable references + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0621`.