when using feature(nll), don't warn about AST-based region errors

Also, keep reporting AST-based region errors that are not occuring in
a fn body.
This commit is contained in:
Niko Matsakis 2017-12-20 04:54:35 -05:00
parent cfa4ffa374
commit 80c510e353
7 changed files with 120 additions and 13 deletions

View file

@ -258,10 +258,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
pub fn report_region_errors(&self,
region_scope_tree: &region::ScopeTree,
errors: &Vec<RegionResolutionError<'tcx>>) {
errors: &Vec<RegionResolutionError<'tcx>>,
will_later_be_reported_by_nll: bool) {
debug!("report_region_errors(): {} errors to start", errors.len());
if self.tcx.sess.nll() {
if will_later_be_reported_by_nll && self.tcx.sess.nll() {
// With `#![feature(nll)]`, we want to present a nice user
// experience, so don't even mention the errors from the
// AST checker.
if self.tcx.sess.features.borrow().nll {
return;
}
// But with -Znll, it's nice to have some note for later.
for error in errors {
match *error {
RegionResolutionError::ConcreteFailure(ref origin, ..) |

View file

@ -1159,10 +1159,45 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
/// result. After this, no more unification operations should be
/// done -- or the compiler will panic -- but it is legal to use
/// `resolve_type_vars_if_possible` as well as `fully_resolve`.
pub fn resolve_regions_and_report_errors(&self,
region_context: DefId,
region_map: &region::ScopeTree,
outlives_env: &OutlivesEnvironment<'tcx>) {
pub fn resolve_regions_and_report_errors(
&self,
region_context: DefId,
region_map: &region::ScopeTree,
outlives_env: &OutlivesEnvironment<'tcx>,
) {
self.resolve_regions_and_report_errors_inner(
region_context,
region_map,
outlives_env,
false,
)
}
/// Like `resolve_regions_and_report_errors`, but skips error
/// reporting if NLL is enabled. This is used for fn bodies where
/// the same error may later be reported by the NLL-based
/// inference.
pub fn resolve_regions_and_report_errors_unless_nll(
&self,
region_context: DefId,
region_map: &region::ScopeTree,
outlives_env: &OutlivesEnvironment<'tcx>,
) {
self.resolve_regions_and_report_errors_inner(
region_context,
region_map,
outlives_env,
true,
)
}
fn resolve_regions_and_report_errors_inner(
&self,
region_context: DefId,
region_map: &region::ScopeTree,
outlives_env: &OutlivesEnvironment<'tcx>,
will_later_be_reported_by_nll: bool,
) {
assert!(self.is_tainted_by_errors() || self.region_obligations.borrow().is_empty(),
"region_obligations not empty: {:#?}",
self.region_obligations.borrow());
@ -1187,7 +1222,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
// this infcx was in use. This is totally hokey but
// otherwise we have a hard time separating legit region
// errors from silly ones.
self.report_region_errors(region_map, &errors); // see error_reporting module
self.report_region_errors(region_map, &errors, will_later_be_reported_by_nll);
}
}

View file

@ -124,7 +124,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
rcx.visit_body(body);
rcx.visit_region_obligations(id);
}
rcx.resolve_regions_and_report_errors();
rcx.resolve_regions_and_report_errors_unless_nll();
assert!(self.tables.borrow().free_region_map.is_empty());
self.tables.borrow_mut().free_region_map = rcx.outlives_environment.into_free_region_map();
@ -173,7 +173,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
rcx.visit_fn_body(fn_id, body, self.tcx.hir.span(fn_id));
}
rcx.resolve_regions_and_report_errors();
rcx.resolve_regions_and_report_errors_unless_nll();
// In this mode, we also copy the free-region-map into the
// tables of the enclosing fcx. In the other regionck modes
@ -371,6 +371,12 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
&self.outlives_environment);
}
fn resolve_regions_and_report_errors_unless_nll(&self) {
self.fcx.resolve_regions_and_report_errors_unless_nll(self.subject_def_id,
&self.region_scope_tree,
&self.outlives_environment);
}
fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat) {
debug!("regionck::visit_pat(pat={:?})", pat);
pat.each_binding(|_, id, span, _| {

View file

@ -10,11 +10,15 @@
// Various examples of structs whose fields are not well-formed.
// revisions:lexical nll
#![allow(dead_code)]
#![cfg_attr(nll, feature(nll))]
struct Ref<'a, T> {
field: &'a T
//~^ ERROR the parameter type `T` may not live long enough
//[lexical]~^ ERROR the parameter type `T` may not live long enough
//[nll]~^^ ERROR the parameter type `T` may not live long enough
}
struct RefOk<'a, T:'a> {
@ -23,12 +27,14 @@ struct RefOk<'a, T:'a> {
struct RefIndirect<'a, T> {
field: RefOk<'a, T>
//~^ ERROR the parameter type `T` may not live long enough
//[lexical]~^ ERROR the parameter type `T` may not live long enough
//[nll]~^^ ERROR the parameter type `T` may not live long enough
}
struct DoubleRef<'a, 'b, T> {
field: &'a &'b T
//~^ ERROR reference has a longer lifetime than the data it references
//[lexical]~^ ERROR reference has a longer lifetime than the data it references
//[nll]~^^ ERROR reference has a longer lifetime than the data it references
}
fn main() { }

View file

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags:-Zborrowck=mir -Znll-dump-cause
// compile-flags:-Znll-dump-cause
// Test that a structure which tries to store a pointer to `y` into
// `p` (indirectly) fails to compile.

View file

@ -0,0 +1,41 @@
// Copyright 2016 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that we assume that universal types like `T` outlive the
// function body. Same as ty-param-fn-body, but uses `feature(nll)`,
// which affects error reporting.
#![feature(nll)]
#![allow(warnings)]
#![feature(dyn_trait)]
use std::cell::Cell;
// No errors here, because `'a` is local to the body.
fn region_within_body<T>(t: T) {
let some_int = 22;
let cell = Cell::new(&some_int);
outlives(cell, t)
}
// Error here, because T: 'a is not satisfied.
fn region_static<'a, T>(cell: Cell<&'a usize>, t: T) {
outlives(cell, t)
//~^ ERROR the parameter type `T` may not live long enough
}
fn outlives<'a, T>(x: Cell<&'a usize>, y: T)
where
T: 'a,
{
}
fn main() {}

View file

@ -0,0 +1,10 @@
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/ty-param-fn-body-nll-feature.rs:31:5
|
31 | outlives(cell, t)
| ^^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `T: 'a`...
error: aborting due to previous error