1
Fork 0

Auto merge of #56460 - davidtwco:issue-55850, r=pnkfelix

Fix ICE with generators and NLL

Fix #55850.

This PR stops an ICE in #55850 by not panicking when a region cannot be named. However, this PR does not (yet) fix the underlying issue that the correct name for the test case provided for the issue (in this instance, `'a`) was not found.

This PR also lays a little bit of groundwork by categorizing yields separately from returns so that region naming can be specialized for this case.

r? @pnkfelix
This commit is contained in:
bors 2018-12-07 17:37:44 +00:00
commit a40fdeddd8
9 changed files with 104 additions and 22 deletions

View file

@ -471,6 +471,7 @@ impl_stable_hash_for!(struct mir::ClosureOutlivesRequirement<'tcx> {
impl_stable_hash_for!(enum mir::ConstraintCategory {
Return,
Yield,
UseAsConst,
UseAsStatic,
TypeAnnotation,

View file

@ -2905,6 +2905,7 @@ pub struct ClosureOutlivesRequirement<'tcx> {
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
pub enum ConstraintCategory {
Return,
Yield,
UseAsConst,
UseAsStatic,
TypeAnnotation,

View file

@ -277,6 +277,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
borrow_region_vid,
region,
);
if let Some(region_name) = region_name {
let opt_place_desc = self.describe_place(&borrow.borrowed_place);
BorrowExplanation::MustBeValidFor {
category,
@ -288,6 +289,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
} else {
BorrowExplanation::Unexplained
}
} else {
BorrowExplanation::Unexplained
}
}
}

View file

@ -38,6 +38,7 @@ impl ConstraintDescription for ConstraintCategory {
match self {
ConstraintCategory::Assignment => "assignment ",
ConstraintCategory::Return => "returning this value ",
ConstraintCategory::Yield => "yielding this value ",
ConstraintCategory::UseAsConst => "using this value as a constant ",
ConstraintCategory::UseAsStatic => "using this value as a static ",
ConstraintCategory::Cast => "cast ",
@ -133,11 +134,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let constraint_sup_scc = self.constraint_sccs.scc(constraint.sup);
match categorized_path[i].0 {
ConstraintCategory::OpaqueType
| ConstraintCategory::Boring
| ConstraintCategory::BoringNoLocation
| ConstraintCategory::Internal => false,
ConstraintCategory::TypeAnnotation | ConstraintCategory::Return => true,
ConstraintCategory::OpaqueType | ConstraintCategory::Boring |
ConstraintCategory::BoringNoLocation | ConstraintCategory::Internal => false,
ConstraintCategory::TypeAnnotation | ConstraintCategory::Return |
ConstraintCategory::Yield => true,
_ => constraint_sup_scc != target_scc,
}
});
@ -376,9 +376,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
diag.span_label(span, message);
match self.give_region_a_name(infcx, mir, mir_def_id, outlived_fr, &mut 1)
.source
{
match self.give_region_a_name(infcx, mir, mir_def_id, outlived_fr, &mut 1).unwrap().source {
RegionNameSource::NamedEarlyBoundRegion(fr_span)
| RegionNameSource::NamedFreeRegion(fr_span)
| RegionNameSource::SynthesizedFreeEnvRegion(fr_span, _)
@ -521,10 +519,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
);
let counter = &mut 1;
let fr_name = self.give_region_a_name(infcx, mir, mir_def_id, fr, counter);
let fr_name = self.give_region_a_name(infcx, mir, mir_def_id, fr, counter).unwrap();
fr_name.highlight_region_name(&mut diag);
let outlived_fr_name =
self.give_region_a_name(infcx, mir, mir_def_id, outlived_fr, counter);
self.give_region_a_name(infcx, mir, mir_def_id, outlived_fr, counter).unwrap();
outlived_fr_name.highlight_region_name(&mut diag);
let mir_def_name = if infcx.tcx.is_closure(mir_def_id) {
@ -661,7 +659,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
infcx: &InferCtxt<'_, '_, 'tcx>,
borrow_region: RegionVid,
outlived_region: RegionVid,
) -> (ConstraintCategory, bool, Span, RegionName) {
) -> (ConstraintCategory, bool, Span, Option<RegionName>) {
let (category, from_closure, span) =
self.best_blame_constraint(mir, borrow_region, |r| r == outlived_region);
let outlived_fr_name =

View file

@ -157,7 +157,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
mir_def_id: DefId,
fr: RegionVid,
counter: &mut usize,
) -> RegionName {
) -> Option<RegionName> {
debug!("give_region_a_name(fr={:?}, counter={})", fr, counter);
assert!(self.universal_regions.is_universal_region(fr));
@ -177,8 +177,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
self.give_name_if_anonymous_region_appears_in_output(
infcx, mir, mir_def_id, fr, counter,
)
})
.unwrap_or_else(|| span_bug!(mir.span, "can't make a name for free region {:?}", fr));
});
debug!("give_region_a_name: gave name {:?}", value);
value

View file

@ -1467,7 +1467,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
value_ty,
ty,
term_location.to_locations(),
ConstraintCategory::Return,
ConstraintCategory::Yield,
) {
span_mirbug!(
self,

View file

@ -0,0 +1,18 @@
error[E0597]: `s` does not live long enough
--> $DIR/issue-55850.rs:38:16
|
LL | yield &s[..] //~ ERROR `s` does not live long enough [E0597]
| ^ borrowed value does not live long enough
LL | })
| - `s` dropped here while still borrowed
error[E0626]: borrow may still be in use when generator yields
--> $DIR/issue-55850.rs:38:16
|
LL | yield &s[..] //~ ERROR `s` does not live long enough [E0597]
| -------^---- possible yield occurs here
error: aborting due to 2 previous errors
Some errors occurred: E0597, E0626.
For more information about an error, try `rustc --explain E0597`.

View file

@ -0,0 +1,44 @@
// 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.
#![allow(unused_mut)]
#![feature(generators, generator_trait)]
use std::ops::Generator;
use std::ops::GeneratorState::Yielded;
pub struct GenIter<G>(G);
impl <G> Iterator for GenIter<G>
where
G: Generator,
{
type Item = G::Yield;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
match self.0.resume() {
Yielded(y) => Some(y),
_ => None
}
}
}
}
fn bug<'a>() -> impl Iterator<Item = &'a str> {
GenIter(move || {
let mut s = String::new();
yield &s[..] //~ ERROR `s` does not live long enough [E0597]
})
}
fn main() {
bug();
}

View file

@ -0,0 +1,17 @@
error[E0597]: `s` does not live long enough
--> $DIR/issue-55850.rs:38:16
|
LL | yield &s[..] //~ ERROR `s` does not live long enough [E0597]
| ^ borrowed value does not live long enough
LL | })
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 35:8...
--> $DIR/issue-55850.rs:35:8
|
LL | fn bug<'a>() -> impl Iterator<Item = &'a str> {
| ^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0597`.