Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -72,16 +73,34 @@ 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,
simple_ident,
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))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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,
}
})
})
}
Expand Down
14 changes: 12 additions & 2 deletions compiler/rustc_trait_selection/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -868,8 +868,13 @@ pub(crate) enum ExplicitLifetimeRequired<'a> {
applicability = "unspecified",
style = "verbose"
)]
new_ty_span: Span,
new_ty_span: Option<Span>,
new_ty: Ty<'a>,
#[help(
"see <https://doc.rust-lang.org/nomicon/borrow-splitting.html> \
for more information about lifetime errors related to mutable references"
)]
link_nomicon: bool,
},
#[diag("explicit lifetime required in parameter type", code = E0621)]
WithParamType {
Expand All @@ -883,8 +888,13 @@ pub(crate) enum ExplicitLifetimeRequired<'a> {
applicability = "unspecified",
style = "verbose"
)]
new_ty_span: Span,
new_ty_span: Option<Span>,
new_ty: Ty<'a>,
#[help(
"see <https://doc.rust-lang.org/nomicon/borrow-splitting.html> \
for more information about lifetime errors related to mutable references"
)]
link_nomicon: bool,
},
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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 <https://doc.rust-lang.org/nomicon/borrow-splitting.html> 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 <https://doc.rust-lang.org/nomicon/borrow-splitting.html> 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`.
Loading