Skip to content

Commit 7161f47

Browse files
Rollup merge of rust-lang#156892 - Dnreikronos:fix/e0621-perpetual-borrow-suggestion, r=mejrs
Suppress E0621 perpetual borrow suggestion Fixes rust-lang#156682 E0621 suggests `&'a mut Buffer<'a>` when you write `&mut Buffer<'a>` and the compiler wants a named lifetime on the outer reference. That ties both lifetimes together and makes the value unusable after the call. Usually it's not the info that the user actually needs. When the suggested fix would produce `&'a [mut] T` where `'a` also appears inside `T`, with the changes being implemented on this PR we now suppress the `help:` suggestion and instead emit a `help:` linking to the nomicon's borrow-splitting chapter, which explains the actual fix. Detection uses the pre-fold parameter type and only fires for mutable references, avoiding false positives on trait objects (`&dyn Foo` folds to `&'a (dyn Foo + 'a)`) and shared references (`&'a S<'a>` is often intentional). What we had before the changes: ``` help: add explicit lifetime `'a` to the type of `buffer` | 5 | pub fn foo<'a>(buffer: &'a mut Buffer<'a>) { | ++ ``` What we are going to have now after: ``` error[E0621]: explicit lifetime required in the type of `buffer` | 5 | 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 ```
2 parents 94d6ea6 + 00b8189 commit 7161f47

7 files changed

Lines changed: 108 additions & 4 deletions

File tree

compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//! where one region is named and the other is anonymous.
33
44
use rustc_errors::Diag;
5+
use rustc_middle::ty;
56
use tracing::debug;
67

78
use crate::error_reporting::infer::nice_region_error::NiceRegionError;
@@ -72,16 +73,34 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
7273
{
7374
return None;
7475
}
76+
let orig_ty = anon_param_info.orig_param_ty;
77+
// Don't suggest naming the outer lifetime when it already appears in the pointee
78+
// (e.g. `&'a mut Buffer<'a>`); point at borrow splitting instead.
79+
let suggestion_would_alias_lifetime =
80+
if let ty::Ref(_, orig_inner_ty, ty::Mutability::Mut) = orig_ty.kind() {
81+
self.tcx().any_free_region_meets(orig_inner_ty, |r| r == named)
82+
} else {
83+
false
84+
};
85+
7586
let named = named.to_string();
87+
let new_ty_span = if suggestion_would_alias_lifetime { None } else { Some(new_ty_span) };
7688
let err = match param.pat.simple_ident() {
7789
Some(simple_ident) => ExplicitLifetimeRequired::WithIdent {
7890
span,
7991
simple_ident,
8092
named,
8193
new_ty_span,
8294
new_ty,
95+
link_nomicon: suggestion_would_alias_lifetime,
96+
},
97+
None => ExplicitLifetimeRequired::WithParamType {
98+
span,
99+
named,
100+
new_ty_span,
101+
new_ty,
102+
link_nomicon: suggestion_would_alias_lifetime,
83103
},
84-
None => ExplicitLifetimeRequired::WithParamType { span, named, new_ty_span, new_ty },
85104
};
86105
Some(self.tcx().sess.dcx().create_err(err))
87106
}

compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ pub struct AnonymousParamInfo<'tcx> {
1616
pub param: &'tcx hir::Param<'tcx>,
1717
/// The type corresponding to the anonymous region parameter.
1818
pub param_ty: Ty<'tcx>,
19+
/// The original type before region replacement.
20+
pub orig_param_ty: Ty<'tcx>,
1921
/// The `ty::LateParamRegionKind` corresponding to the anonymous region.
2022
pub kind: ty::LateParamRegionKind,
2123
/// The `Span` of the parameter type.
@@ -94,7 +96,14 @@ pub fn find_param_with_region<'tcx>(
9496
let ty_hir_id = fn_decl.inputs[index].hir_id;
9597
let param_ty_span = tcx.hir_span(ty_hir_id);
9698
let is_first = index == 0;
97-
AnonymousParamInfo { param, param_ty: new_param_ty, param_ty_span, kind, is_first }
99+
AnonymousParamInfo {
100+
param,
101+
param_ty: new_param_ty,
102+
orig_param_ty: ty,
103+
param_ty_span,
104+
kind,
105+
is_first,
106+
}
98107
})
99108
})
100109
}

compiler/rustc_trait_selection/src/errors.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -868,8 +868,13 @@ pub(crate) enum ExplicitLifetimeRequired<'a> {
868868
applicability = "unspecified",
869869
style = "verbose"
870870
)]
871-
new_ty_span: Span,
871+
new_ty_span: Option<Span>,
872872
new_ty: Ty<'a>,
873+
#[help(
874+
"see <https://doc.rust-lang.org/nomicon/borrow-splitting.html> \
875+
for more information about lifetime errors related to mutable references"
876+
)]
877+
link_nomicon: bool,
873878
},
874879
#[diag("explicit lifetime required in parameter type", code = E0621)]
875880
WithParamType {
@@ -883,8 +888,13 @@ pub(crate) enum ExplicitLifetimeRequired<'a> {
883888
applicability = "unspecified",
884889
style = "verbose"
885890
)]
886-
new_ty_span: Span,
891+
new_ty_span: Option<Span>,
887892
new_ty: Ty<'a>,
893+
#[help(
894+
"see <https://doc.rust-lang.org/nomicon/borrow-splitting.html> \
895+
for more information about lifetime errors related to mutable references"
896+
)]
897+
link_nomicon: bool,
888898
},
889899
}
890900

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Regression test for #156682
2+
// When the suggested type would NOT alias the outer reference's lifetime with one
3+
// already used inside the pointee, the normal suggestion should still apply.
4+
5+
pub fn push<'a>(x: &mut Vec<&'a u8>, y: &u8) {
6+
x.push(y);
7+
//~^ ERROR explicit lifetime required in the type of `y`
8+
}
9+
10+
fn main() {}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0621]: explicit lifetime required in the type of `y`
2+
--> $DIR/e0621-mut-ref-aliases-pointee-lifetime-distinct.rs:6:5
3+
|
4+
LL | x.push(y);
5+
| ^^^^^^^^^ lifetime `'a` required
6+
|
7+
help: add explicit lifetime `'a` to the type of `y`
8+
|
9+
LL | pub fn push<'a>(x: &mut Vec<&'a u8>, y: &'a u8) {
10+
| ++
11+
12+
error: aborting due to 1 previous error
13+
14+
For more information about this error, try `rustc --explain E0621`.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Regression test for #156682
2+
// E0621 should not suggest `&'a mut Buffer<'a>`, which would alias the outer
3+
// reference's lifetime with one already used inside the pointee.
4+
5+
pub struct Buffer<'a> {
6+
buf: &'a mut [u8],
7+
}
8+
9+
pub fn foo<'a>(buffer: &mut Buffer<'a>) {
10+
buffer.buf = &mut buffer.buf[..];
11+
//~^ ERROR explicit lifetime required in the type of `buffer`
12+
}
13+
14+
pub struct Wrapper<'a> {
15+
inner: Buffer<'a>,
16+
}
17+
18+
pub fn baz<'a>(wrapper: &mut Wrapper<'a>) {
19+
wrapper.inner.buf = &mut wrapper.inner.buf[..];
20+
//~^ ERROR explicit lifetime required in the type of `wrapper`
21+
}
22+
23+
fn main() {}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0621]: explicit lifetime required in the type of `buffer`
2+
--> $DIR/e0621-mut-ref-aliases-pointee-lifetime.rs:10:5
3+
|
4+
LL | buffer.buf = &mut buffer.buf[..];
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required
6+
|
7+
= help: see <https://doc.rust-lang.org/nomicon/borrow-splitting.html> for more information about lifetime errors related to mutable references
8+
9+
error[E0621]: explicit lifetime required in the type of `wrapper`
10+
--> $DIR/e0621-mut-ref-aliases-pointee-lifetime.rs:19:5
11+
|
12+
LL | wrapper.inner.buf = &mut wrapper.inner.buf[..];
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required
14+
|
15+
= help: see <https://doc.rust-lang.org/nomicon/borrow-splitting.html> for more information about lifetime errors related to mutable references
16+
17+
error: aborting due to 2 previous errors
18+
19+
For more information about this error, try `rustc --explain E0621`.

0 commit comments

Comments
 (0)