summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Hill <aa1ronham@gmail.com>2020-10-20 16:31:54 -0400
committerAaron Hill <aa1ronham@gmail.com>2020-12-17 13:24:40 -0500
commit419d3ae02849d47899f8fc221d37b05ac24f4efd (patch)
tree74e550e80e64fc42f648ff447086a03c0b870b8d
parentd23e08448332425a84ae23124bea4dbd685536ce (diff)
downloadrust-419d3ae02849d47899f8fc221d37b05ac24f4efd.tar.gz
Prefer regions with an `external_name` in `approx_universal_upper_bound`
Fixes #75785 When displaying a MIR borrowcheck error, we may need to find an upper bound for a region, which gives us a region to point to in the error message. However, a region might outlive multiple distinct universal regions, in which case the only upper bound is 'static To try to display a meaningful error message, we compute an 'approximate' upper bound by picking one of the universal regions. Currently, we pick the region with the lowest index - however, this caused us to produce a suboptimal error message in issue #75785 This PR `approx_universal_upper_bound` to prefer regions with an `external_name`. This causes us to prefer regions from function arguments/upvars, which seems to lead to a nicer error message in some cases.
-rw-r--r--compiler/rustc_mir/src/borrow_check/region_infer/mod.rs18
-rw-r--r--src/test/ui/async-await/issue-74072-lifetime-name-annotations.stderr2
-rw-r--r--src/test/ui/async-await/issue-75785-confusing-named-region.rs13
-rw-r--r--src/test/ui/async-await/issue-75785-confusing-named-region.stderr15
4 files changed, 46 insertions, 2 deletions
diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
index 3586be2804d..9d45f6fd0d3 100644
--- a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
@@ -1145,8 +1145,24 @@ impl<'tcx> RegionInferenceContext<'tcx> {
for ur in self.scc_values.universal_regions_outlived_by(r_scc) {
let new_lub = self.universal_region_relations.postdom_upper_bound(lub, ur);
debug!("approx_universal_upper_bound: ur={:?} lub={:?} new_lub={:?}", ur, lub, new_lub);
+ // The upper bound of two non-static regions is static: this
+ // means we know nothing about the relationship between these
+ // two regions. Pick a 'better' one to use when constructing
+ // a diagnostic
if ur != static_r && lub != static_r && new_lub == static_r {
- lub = std::cmp::min(ur, lub);
+ // Prefer the region with an `external_name` - this
+ // indicates that the region is early-bound, so working with
+ // it can produce a nicer error.
+ if self.region_definition(ur).external_name.is_some() {
+ lub = ur;
+ } else if self.region_definition(lub).external_name.is_some() {
+ // Leave lub unchanged
+ } else {
+ // If we get here, we don't have any reason to prefer
+ // one region over the other. Just pick the
+ // one with the lower index for now.
+ lub = std::cmp::min(ur, lub);
+ }
} else {
lub = new_lub;
}
diff --git a/src/test/ui/async-await/issue-74072-lifetime-name-annotations.stderr b/src/test/ui/async-await/issue-74072-lifetime-name-annotations.stderr
index 123c3192cff..b96cab9f0f5 100644
--- a/src/test/ui/async-await/issue-74072-lifetime-name-annotations.stderr
+++ b/src/test/ui/async-await/issue-74072-lifetime-name-annotations.stderr
@@ -2,7 +2,7 @@ error[E0506]: cannot assign to `*x` because it is borrowed
--> $DIR/issue-74072-lifetime-name-annotations.rs:9:5
|
LL | pub async fn async_fn(x: &mut i32) -> &i32 {
- | - let's call the lifetime of this reference `'1`
+ | - let's call the lifetime of this reference `'1`
LL | let y = &*x;
| --- borrow of `*x` occurs here
LL | *x += 1;
diff --git a/src/test/ui/async-await/issue-75785-confusing-named-region.rs b/src/test/ui/async-await/issue-75785-confusing-named-region.rs
new file mode 100644
index 00000000000..452614087be
--- /dev/null
+++ b/src/test/ui/async-await/issue-75785-confusing-named-region.rs
@@ -0,0 +1,13 @@
+// edition:2018
+//
+// Regression test for issue #75785
+// Tests that we don't point to a confusing named
+// region when emitting a diagnostic
+
+pub async fn async_fn(x: &mut i32) -> (&i32, &i32) {
+ let y = &*x;
+ *x += 1; //~ ERROR cannot assign to
+ (&32, y)
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/issue-75785-confusing-named-region.stderr b/src/test/ui/async-await/issue-75785-confusing-named-region.stderr
new file mode 100644
index 00000000000..3b731d9c60a
--- /dev/null
+++ b/src/test/ui/async-await/issue-75785-confusing-named-region.stderr
@@ -0,0 +1,15 @@
+error[E0506]: cannot assign to `*x` because it is borrowed
+ --> $DIR/issue-75785-confusing-named-region.rs:9:5
+ |
+LL | pub async fn async_fn(x: &mut i32) -> (&i32, &i32) {
+ | - let's call the lifetime of this reference `'1`
+LL | let y = &*x;
+ | --- borrow of `*x` occurs here
+LL | *x += 1;
+ | ^^^^^^^ assignment to borrowed `*x` occurs here
+LL | (&32, y)
+ | -------- returning this value requires that `*x` is borrowed for `'1`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.