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 { impl_stable_hash_for!(enum mir::ConstraintCategory {
Return, Return,
Yield,
UseAsConst, UseAsConst,
UseAsStatic, UseAsStatic,
TypeAnnotation, TypeAnnotation,

View file

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

View file

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

View file

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

View file

@ -157,7 +157,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
mir_def_id: DefId, mir_def_id: DefId,
fr: RegionVid, fr: RegionVid,
counter: &mut usize, counter: &mut usize,
) -> RegionName { ) -> Option<RegionName> {
debug!("give_region_a_name(fr={:?}, counter={})", fr, counter); debug!("give_region_a_name(fr={:?}, counter={})", fr, counter);
assert!(self.universal_regions.is_universal_region(fr)); 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( self.give_name_if_anonymous_region_appears_in_output(
infcx, mir, mir_def_id, fr, counter, 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); debug!("give_region_a_name: gave name {:?}", value);
value value

View file

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