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:
commit
a40fdeddd8
9 changed files with 104 additions and 22 deletions
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 =
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
18
src/test/ui/nll/issue-55850.nll.stderr
Normal file
18
src/test/ui/nll/issue-55850.nll.stderr
Normal 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`.
|
44
src/test/ui/nll/issue-55850.rs
Normal file
44
src/test/ui/nll/issue-55850.rs
Normal 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();
|
||||||
|
}
|
17
src/test/ui/nll/issue-55850.stderr
Normal file
17
src/test/ui/nll/issue-55850.stderr
Normal 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`.
|
Loading…
Add table
Add a link
Reference in a new issue