Skip to content

Commit 2821329

Browse files
authored
Rollup merge of rust-lang#60176 - matthewjasper:yield-ref-to-local, r=pnkfelix
Explain error when yielding a reference to a local variable Closes rust-lang#56508
2 parents a9ec99f + d9ea132 commit 2821329

File tree

6 files changed

+107
-26
lines changed

6 files changed

+107
-26
lines changed

src/librustc_mir/borrow_check/error_reporting.rs

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -826,18 +826,21 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
826826

827827
let borrow_span = borrow_spans.var_or_use();
828828
if let BorrowExplanation::MustBeValidFor {
829-
category: ConstraintCategory::Return,
829+
category,
830830
span,
831831
ref opt_place_desc,
832832
from_closure: false,
833833
..
834834
} = explanation {
835-
return self.report_cannot_return_reference_to_local(
835+
if let Some(diag) = self.try_report_cannot_return_reference_to_local(
836836
borrow,
837837
borrow_span,
838838
span,
839+
category,
839840
opt_place_desc.as_ref(),
840-
);
841+
) {
842+
return diag;
843+
}
841844
}
842845

843846
let mut err = self.infcx.tcx.path_does_not_live_long_enough(
@@ -1015,17 +1018,20 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
10151018
);
10161019

10171020
if let BorrowExplanation::MustBeValidFor {
1018-
category: ConstraintCategory::Return,
1021+
category,
10191022
span,
10201023
from_closure: false,
10211024
..
10221025
} = explanation {
1023-
return self.report_cannot_return_reference_to_local(
1026+
if let Some(diag) = self.try_report_cannot_return_reference_to_local(
10241027
borrow,
10251028
proper_span,
10261029
span,
1030+
category,
10271031
None,
1028-
);
1032+
) {
1033+
return diag;
1034+
}
10291035
}
10301036

10311037
let tcx = self.infcx.tcx;
@@ -1064,15 +1070,22 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
10641070
err
10651071
}
10661072

1067-
fn report_cannot_return_reference_to_local(
1073+
fn try_report_cannot_return_reference_to_local(
10681074
&self,
10691075
borrow: &BorrowData<'tcx>,
10701076
borrow_span: Span,
10711077
return_span: Span,
1078+
category: ConstraintCategory,
10721079
opt_place_desc: Option<&String>,
1073-
) -> DiagnosticBuilder<'cx> {
1080+
) -> Option<DiagnosticBuilder<'cx>> {
10741081
let tcx = self.infcx.tcx;
10751082

1083+
let return_kind = match category {
1084+
ConstraintCategory::Return => "return",
1085+
ConstraintCategory::Yield => "yield",
1086+
_ => return None,
1087+
};
1088+
10761089
// FIXME use a better heuristic than Spans
10771090
let reference_desc = if return_span == self.mir.source_info(borrow.reserve_location).span {
10781091
"reference to"
@@ -1110,7 +1123,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
11101123
let local = if let Place::Base(PlaceBase::Local(local)) = *root_place {
11111124
local
11121125
} else {
1113-
bug!("report_cannot_return_reference_to_local: not a local")
1126+
bug!("try_report_cannot_return_reference_to_local: not a local")
11141127
};
11151128
match self.mir.local_kind(local) {
11161129
LocalKind::ReturnPointer | LocalKind::Temp => {
@@ -1131,6 +1144,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
11311144

11321145
let mut err = tcx.cannot_return_reference_to_local(
11331146
return_span,
1147+
return_kind,
11341148
reference_desc,
11351149
&place_desc,
11361150
Origin::Mir,
@@ -1140,7 +1154,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
11401154
err.span_label(borrow_span, note);
11411155
}
11421156

1143-
err
1157+
Some(err)
11441158
}
11451159

11461160
fn report_escaping_closure_capture(

src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,9 +310,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
310310
opt_place_desc,
311311
}
312312
} else {
313+
debug!("explain_why_borrow_contains_point: \
314+
Could not generate a region name");
313315
BorrowExplanation::Unexplained
314316
}
315317
} else {
318+
debug!("explain_why_borrow_contains_point: \
319+
Could not generate an error region vid");
316320
BorrowExplanation::Unexplained
317321
}
318322
}

src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ crate enum RegionNameSource {
3434
MatchedAdtAndSegment(Span),
3535
AnonRegionFromUpvar(Span, String),
3636
AnonRegionFromOutput(Span, String, String),
37+
AnonRegionFromYieldTy(Span, String),
3738
}
3839

3940
impl RegionName {
@@ -48,7 +49,8 @@ impl RegionName {
4849
RegionNameSource::MatchedHirTy(..) |
4950
RegionNameSource::MatchedAdtAndSegment(..) |
5051
RegionNameSource::AnonRegionFromUpvar(..) |
51-
RegionNameSource::AnonRegionFromOutput(..) => false,
52+
RegionNameSource::AnonRegionFromOutput(..) |
53+
RegionNameSource::AnonRegionFromYieldTy(..) => false,
5254
}
5355
}
5456

@@ -105,6 +107,12 @@ impl RegionName {
105107
format!("return type{} is {}", mir_description, type_name),
106108
);
107109
},
110+
RegionNameSource::AnonRegionFromYieldTy(span, type_name) => {
111+
diag.span_label(
112+
*span,
113+
format!("yield type is {}", type_name),
114+
);
115+
}
108116
RegionNameSource::Static => {},
109117
}
110118
}
@@ -170,6 +178,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
170178
self.give_name_if_anonymous_region_appears_in_output(
171179
infcx, mir, mir_def_id, fr, counter,
172180
)
181+
})
182+
.or_else(|| {
183+
self.give_name_if_anonymous_region_appears_in_yield_ty(
184+
infcx, mir, mir_def_id, fr, counter,
185+
)
173186
});
174187

175188
debug!("give_region_a_name: gave name {:?}", value);
@@ -676,10 +689,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
676689
"give_name_if_anonymous_region_appears_in_output: return_ty = {:?}",
677690
return_ty
678691
);
679-
if !infcx
680-
.tcx
681-
.any_free_region_meets(&return_ty, |r| r.to_region_vid() == fr)
682-
{
692+
if !tcx.any_free_region_meets(&return_ty, |r| r.to_region_vid() == fr) {
683693
return None;
684694
}
685695

@@ -724,6 +734,57 @@ impl<'tcx> RegionInferenceContext<'tcx> {
724734
})
725735
}
726736

737+
fn give_name_if_anonymous_region_appears_in_yield_ty(
738+
&self,
739+
infcx: &InferCtxt<'_, '_, 'tcx>,
740+
mir: &Mir<'tcx>,
741+
mir_def_id: DefId,
742+
fr: RegionVid,
743+
counter: &mut usize,
744+
) -> Option<RegionName> {
745+
// Note: generators from `async fn` yield `()`, so we don't have to
746+
// worry about them here.
747+
let yield_ty = self.universal_regions.yield_ty?;
748+
debug!(
749+
"give_name_if_anonymous_region_appears_in_yield_ty: yield_ty = {:?}",
750+
yield_ty,
751+
);
752+
753+
let tcx = infcx.tcx;
754+
755+
if !tcx.any_free_region_meets(&yield_ty, |r| r.to_region_vid() == fr) {
756+
return None;
757+
}
758+
759+
let mut highlight = RegionHighlightMode::default();
760+
highlight.highlighting_region_vid(fr, *counter);
761+
let type_name = infcx.extract_type_name(&yield_ty, Some(highlight));
762+
763+
let mir_node_id = tcx.hir().as_local_node_id(mir_def_id).expect("non-local mir");
764+
765+
let yield_span = match tcx.hir().get(mir_node_id) {
766+
hir::Node::Expr(hir::Expr {
767+
node: hir::ExprKind::Closure(_, _, _, span, _),
768+
..
769+
}) => (
770+
tcx.sess.source_map().end_point(*span)
771+
),
772+
_ => mir.span,
773+
};
774+
775+
debug!(
776+
"give_name_if_anonymous_region_appears_in_yield_ty: \
777+
type_name = {:?}, yield_span = {:?}",
778+
yield_span,
779+
type_name,
780+
);
781+
782+
Some(RegionName {
783+
name: self.synthesize_region_name(counter),
784+
source: RegionNameSource::AnonRegionFromYieldTy(yield_span, type_name),
785+
})
786+
}
787+
727788
/// Creates a synthetic region named `'1`, incrementing the
728789
/// counter.
729790
fn synthesize_region_name(&self, counter: &mut usize) -> InternedString {

src/librustc_mir/util/borrowck_errors.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
634634
fn cannot_return_reference_to_local(
635635
self,
636636
span: Span,
637+
return_kind: &str,
637638
reference_desc: &str,
638639
path_desc: &str,
639640
o: Origin,
@@ -642,15 +643,16 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
642643
self,
643644
span,
644645
E0515,
645-
"cannot return {REFERENCE} {LOCAL}{OGN}",
646+
"cannot {RETURN} {REFERENCE} {LOCAL}{OGN}",
647+
RETURN=return_kind,
646648
REFERENCE=reference_desc,
647649
LOCAL=path_desc,
648650
OGN = o
649651
);
650652

651653
err.span_label(
652654
span,
653-
format!("returns a {} data owned by the current function", reference_desc),
655+
format!("{}s a {} data owned by the current function", return_kind, reference_desc),
654656
);
655657

656658
self.cancel_if_wrong_origin(err, o)

src/test/ui/nll/issue-55850.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ where
2525
fn bug<'a>() -> impl Iterator<Item = &'a str> {
2626
GenIter(move || {
2727
let mut s = String::new();
28-
yield &s[..] //~ ERROR `s` does not live long enough [E0597]
28+
yield &s[..] //~ ERROR cannot yield value referencing local variable `s` [E0515]
2929
//~| ERROR borrow may still be in use when generator yields
3030
})
3131
}

src/test/ui/nll/issue-55850.stderr

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
error[E0597]: `s` does not live long enough
2-
--> $DIR/issue-55850.rs:28:16
1+
error[E0515]: cannot yield value referencing local variable `s`
2+
--> $DIR/issue-55850.rs:28:9
33
|
44
LL | yield &s[..]
5-
| ^ borrowed value does not live long enough
6-
LL |
7-
LL | })
8-
| - `s` dropped here while still borrowed
5+
| ^^^^^^^-^^^^
6+
| | |
7+
| | `s` is borrowed here
8+
| yields a value referencing data owned by the current function
99

1010
error[E0626]: borrow may still be in use when generator yields
1111
--> $DIR/issue-55850.rs:28:16
@@ -15,5 +15,5 @@ LL | yield &s[..]
1515

1616
error: aborting due to 2 previous errors
1717

18-
Some errors have detailed explanations: E0597, E0626.
19-
For more information about an error, try `rustc --explain E0597`.
18+
Some errors have detailed explanations: E0515, E0626.
19+
For more information about an error, try `rustc --explain E0515`.

0 commit comments

Comments
 (0)