From 43e758798c34581b313fae54d28e95fca628b167 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 27 Aug 2018 15:13:59 -0400 Subject: [PATCH] avoid propagating outlives obligations on locals if we can --- .../borrow_check/nll/region_infer/mod.rs | 17 +++++++ src/test/ui/nll/issue-53570.rs | 46 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 src/test/ui/nll/issue-53570.rs diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 46b3c708695..cb15c88bb3e 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -701,6 +701,23 @@ impl<'tcx> RegionInferenceContext<'tcx> { // `ClosureOutlivesRequirement`. let r_scc = self.constraint_sccs.scc(*lower_bound); for ur in self.scc_values.universal_regions_outlived_by(r_scc) { + // Check whether we can already prove that the "subject" outlives `ur`. + // If so, we don't have to propagate this requirement to our caller. + // + // To continue the example from the function, if we are trying to promote + // a requirement that `T: 'X`, and we know that `'X = '1 + '2` (i.e., the union + // `'1` and `'2`), then in this loop `ur` will be `'1` (and `'2`). So here + // we check whether `T: '1` is something we *can* prove. If so, no need + // to propagate that requirement. + // + // This is needed because -- particularly in the case + // where `ur` is a local bound -- we are sometimes in a + // position to prove things that our caller cannot. See + // #53570 for an example. + if self.eval_region_test(mir, ur, &type_test.test) { + continue; + } + debug!("try_promote_type_test: ur={:?}", ur); let non_local_ub = self.universal_region_relations.non_local_upper_bound(ur); diff --git a/src/test/ui/nll/issue-53570.rs b/src/test/ui/nll/issue-53570.rs new file mode 100644 index 00000000000..9617e40ec39 --- /dev/null +++ b/src/test/ui/nll/issue-53570.rs @@ -0,0 +1,46 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for #53570. Here, we need to propagate that `T: 'a` +// but in some versions of NLL we were propagating a stronger +// requirement that `T: 'static`. This arose because we actually had +// to propagate both that `T: 'a` but also `T: 'b` where `'b` is the +// higher-ranked lifetime that appears in the type of the closure +// parameter `x` -- since `'b` cannot be expressed in the caller's +// space, that got promoted th `'static`. +// +// compile-pass + +#![feature(nll)] +#![feature(rustc_attrs)] +#![allow(dead_code)] + +use std::cell::{RefCell, Ref}; + +trait AnyVec<'a> { +} + +trait GenericVec { + fn unwrap<'a, 'b>(vec: &'b AnyVec<'a>) -> &'b [T] where T: 'a; +} + +struct Scratchpad<'a> { + buffers: RefCell>>, +} + +impl<'a> Scratchpad<'a> { + fn get>(&self) -> Ref<[T]> + where T: 'a + { + Ref::map(self.buffers.borrow(), |x| T::unwrap(x.as_ref())) + } +} + +fn main() { }