Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 8 pull requests #73299

Closed
wants to merge 27 commits into from
Closed
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
9cee22c
Display information about captured variable in `FnMut` error
Aaron1011 May 24, 2020
4548eb8
Clarify the behaviour of Pattern when used with methods like str::con…
poliorcetics Jun 2, 2020
e9b67d2
Fix link error with #[thread_local] introduced by #71192
Amanieu Jun 6, 2020
6f6620b
Rename "cyclone" to "apple-a7" per changes in upstream LLVM
trevyn Jun 7, 2020
687767a
Suggest substituting `'static` lifetime in impl/dyn `Trait + 'static`…
estebank May 29, 2020
c91320f
When `'static` is explicit, suggest constraining argument with it
estebank May 30, 2020
abf74b9
Reduce verbosity of suggestion message and mention lifetime in label
estebank May 30, 2020
50c422e
Move overlapping span to a note
estebank May 30, 2020
17951e2
Tweak output for overlapping required/captured spans
estebank May 30, 2020
19bb589
Tweak wording and add error code
estebank May 30, 2020
3cfecde
review comments: wording
estebank Jun 1, 2020
bdfb9b1
Use note for requirement source span
estebank Jun 2, 2020
215de3b
Register new eror code
estebank Jun 2, 2020
187e105
small tweaks
estebank Jun 2, 2020
6145918
Change E0758 to E0759 to avoid conflict with #72912
estebank Jun 3, 2020
2af53e9
Add -O compile flag to test
Amanieu Jun 10, 2020
975f7df
compiletest: Add directives to detect sanitizer support
tmiasko Jun 5, 2020
57b54c4
Use the built cargo for cargotest.
ehuss Jun 12, 2020
b126f32
Fix links when pinging notification groups
LeSeulArtichaut Jun 12, 2020
b6e45f0
Rollup merge of #72598 - Aaron1011:feature/fnmut-capture-span, r=niko…
Dylan-DPC Jun 13, 2020
7cec851
Rollup merge of #72804 - estebank:opaque-missing-lts-in-fn-2, r=nikom…
Dylan-DPC Jun 13, 2020
22c222f
Rollup merge of #72932 - poliorcetics:pattern-contains-behaviour, r=h…
Dylan-DPC Jun 13, 2020
9163d1b
Rollup merge of #73044 - tmiasko:compiletest-san, r=nikomatsakis
Dylan-DPC Jun 13, 2020
c69bfd0
Rollup merge of #73065 - Amanieu:tls-fix, r=oli-obk
Dylan-DPC Jun 13, 2020
58b2584
Rollup merge of #73086 - trevyn:apple-a7, r=nikic
Dylan-DPC Jun 13, 2020
23e7524
Rollup merge of #73267 - ehuss:cargotest-this-cargo, r=Mark-Simulacrum
Dylan-DPC Jun 13, 2020
bba35b1
Rollup merge of #73290 - LeSeulArtichaut:patch-1, r=Dylan-DPC
Dylan-DPC Jun 13, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Display information about captured variable in FnMut error
Fixes #69446

When we encounter a region error involving an `FnMut` closure, we
display a specialized error message. However, we currently do not
tell the user which upvar was captured. This makes it difficult to
determine the cause of the error, especially when the closure is large.

This commit records marks constraints involving closure upvars
with `ConstraintCategory::ClosureUpvar`. When we decide to 'blame'
a `ConstraintCategory::Return`, we additionall store
the captured upvar if we found a `ConstraintCategory::ClosureUpvar` in
the path.

When generating an error message, we point to relevant spans if we have
closure upvar information available. We further customize the message if
an `async` closure is being returned, to make it clear that the captured
variable is being returned indirectly.
Aaron1011 committed May 26, 2020

Verified

This commit was signed with the committer’s verified signature.
Aaron1011 Aaron Hill
commit 9cee22c1a401ace6dd8633335b131c47a37d7bac
1 change: 1 addition & 0 deletions src/libcore/future/mod.rs
Original file line number Diff line number Diff line change
@@ -56,6 +56,7 @@ pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
where
T: Generator<ResumeTy, Yield = ()>,
{
#[rustc_diagnostic_item = "gen_future"]
struct GenFuture<T: Generator<ResumeTy, Yield = ()>>(T);

// We rely on the fact that async/await futures are immovable in order to create
10 changes: 9 additions & 1 deletion src/librustc_middle/mir/query.rs
Original file line number Diff line number Diff line change
@@ -171,7 +171,7 @@ pub struct ClosureOutlivesRequirement<'tcx> {
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
#[derive(RustcEncodable, RustcDecodable, HashStable)]
pub enum ConstraintCategory {
Return,
Return(ReturnConstraint),
Yield,
UseAsConst,
UseAsStatic,
@@ -187,6 +187,7 @@ pub enum ConstraintCategory {
SizedBound,
Assignment,
OpaqueType,
ClosureUpvar(hir::HirId),

/// A "boring" constraint (caused by the given location) is one that
/// the user probably doesn't want to see described in diagnostics,
@@ -204,6 +205,13 @@ pub enum ConstraintCategory {
Internal,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
#[derive(RustcEncodable, RustcDecodable, HashStable)]
pub enum ReturnConstraint {
Normal,
ClosureUpvar(hir::HirId),
}

/// The subject of a `ClosureOutlivesRequirement` -- that is, the thing
/// that must outlive some region.
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
6 changes: 3 additions & 3 deletions src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
@@ -766,7 +766,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
category:
category
@
(ConstraintCategory::Return
(ConstraintCategory::Return(_)
| ConstraintCategory::CallArgument
| ConstraintCategory::OpaqueType),
from_closure: false,
@@ -1096,7 +1096,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
opt_place_desc: Option<&String>,
) -> Option<DiagnosticBuilder<'cx>> {
let return_kind = match category {
ConstraintCategory::Return => "return",
ConstraintCategory::Return(_) => "return",
ConstraintCategory::Yield => "yield",
_ => return None,
};
@@ -1210,7 +1210,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);

let msg = match category {
ConstraintCategory::Return | ConstraintCategory::OpaqueType => {
ConstraintCategory::Return(_) | ConstraintCategory::OpaqueType => {
format!("{} is returned here", kind)
}
ConstraintCategory::CallArgument => {
57 changes: 41 additions & 16 deletions src/librustc_mir/borrow_check/diagnostics/region_errors.rs
Original file line number Diff line number Diff line change
@@ -5,9 +5,9 @@ use rustc_infer::infer::{
error_reporting::nice_region_error::NiceRegionError,
error_reporting::unexpected_hidden_region_diagnostic, NLLRegionVariableOrigin,
};
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
use rustc_middle::ty::{self, RegionVid, Ty};
use rustc_span::symbol::kw;
use rustc_span::symbol::{kw, sym};
use rustc_span::Span;

use crate::util::borrowck_errors;
@@ -26,7 +26,7 @@ impl ConstraintDescription for ConstraintCategory {
// Must end with a space. Allows for empty names to be provided.
match self {
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::UseAsStatic => "using this value as a static ",
@@ -37,6 +37,7 @@ impl ConstraintDescription for ConstraintCategory {
ConstraintCategory::SizedBound => "proving this value is `Sized` ",
ConstraintCategory::CopyBound => "copying this value ",
ConstraintCategory::OpaqueType => "opaque type ",
ConstraintCategory::ClosureUpvar(_) => "closure capture ",
ConstraintCategory::Boring
| ConstraintCategory::BoringNoLocation
| ConstraintCategory::Internal => "",
@@ -306,8 +307,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
};

let diag = match (category, fr_is_local, outlived_fr_is_local) {
(ConstraintCategory::Return, true, false) if self.is_closure_fn_mut(fr) => {
self.report_fnmut_error(&errci)
(ConstraintCategory::Return(kind), true, false) if self.is_closure_fn_mut(fr) => {
self.report_fnmut_error(&errci, kind)
}
(ConstraintCategory::Assignment, true, false)
| (ConstraintCategory::CallArgument, true, false) => {
@@ -347,7 +348,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
/// executing...
/// = note: ...therefore, returned references to captured variables will escape the closure
/// ```
fn report_fnmut_error(&self, errci: &ErrorConstraintInfo) -> DiagnosticBuilder<'tcx> {
fn report_fnmut_error(
&self,
errci: &ErrorConstraintInfo,
kind: ReturnConstraint,
) -> DiagnosticBuilder<'tcx> {
let ErrorConstraintInfo { outlived_fr, span, .. } = errci;

let mut diag = self
@@ -356,19 +361,39 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
.sess
.struct_span_err(*span, "captured variable cannot escape `FnMut` closure body");

// We should check if the return type of this closure is in fact a closure - in that
// case, we can special case the error further.
let return_type_is_closure =
self.regioncx.universal_regions().unnormalized_output_ty.is_closure();
let message = if return_type_is_closure {
"returns a closure that contains a reference to a captured variable, which then \
escapes the closure body"
} else {
"returns a reference to a captured variable which escapes the closure body"
let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty;
if let ty::Opaque(def_id, _) = output_ty.kind {
output_ty = self.infcx.tcx.type_of(def_id)
};

debug!("report_fnmut_error: output_ty={:?}", output_ty);

let message = match output_ty.kind {
ty::Closure(_, _) => {
"returns a closure that contains a reference to a captured variable, which then \
escapes the closure body"
}
ty::Adt(def, _) if self.infcx.tcx.is_diagnostic_item(sym::gen_future, def.did) => {
"returns an `async` block that contains a reference to a captured variable, which then \
escapes the closure body"
}
_ => "returns a reference to a captured variable which escapes the closure body",
};

diag.span_label(*span, message);

if let ReturnConstraint::ClosureUpvar(upvar) = kind {
let def_id = match self.regioncx.universal_regions().defining_ty {
DefiningTy::Closure(def_id, _) => def_id,
ty @ _ => bug!("unexpected DefiningTy {:?}", ty),
};

let upvar_def_span = self.infcx.tcx.hir().span(upvar);
let upvar_span = self.infcx.tcx.upvars_mentioned(def_id).unwrap()[&upvar].span;
diag.span_label(upvar_def_span, "variable defined here");
diag.span_label(upvar_span, "variable captured here");
}

match self.give_region_a_name(*outlived_fr).unwrap().source {
RegionNameSource::NamedEarlyBoundRegion(fr_span)
| RegionNameSource::NamedFreeRegion(fr_span)
@@ -506,7 +531,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
outlived_fr_name.highlight_region_name(&mut diag);

match (category, outlived_fr_is_local, fr_is_local) {
(ConstraintCategory::Return, true, _) => {
(ConstraintCategory::Return(_), true, _) => {
diag.span_label(
*span,
format!(
26 changes: 2 additions & 24 deletions src/librustc_mir/borrow_check/mod.rs
Original file line number Diff line number Diff line change
@@ -218,6 +218,7 @@ fn do_mir_borrowck<'a, 'tcx>(
&mut flow_inits,
&mdpe.move_data,
&borrow_set,
&upvars,
);

// Dump MIR results into a file, if that is enabled. This let us
@@ -2301,30 +2302,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// be `self` in the current MIR, because that is the only time we directly access the fields
/// of a closure type.
pub fn is_upvar_field_projection(&self, place_ref: PlaceRef<'tcx>) -> Option<Field> {
let mut place_projection = place_ref.projection;
let mut by_ref = false;

if let [proj_base @ .., ProjectionElem::Deref] = place_projection {
place_projection = proj_base;
by_ref = true;
}

match place_projection {
[base @ .., ProjectionElem::Field(field, _ty)] => {
let tcx = self.infcx.tcx;
let base_ty = Place::ty_from(place_ref.local, base, self.body(), tcx).ty;

if (base_ty.is_closure() || base_ty.is_generator())
&& (!by_ref || self.upvars[field.index()].by_ref)
{
Some(*field)
} else {
None
}
}

_ => None,
}
path_utils::is_upvar_field_projection(self.infcx.tcx, &self.upvars, place_ref, self.body())
}
}

3 changes: 3 additions & 0 deletions src/librustc_mir/borrow_check/nll.rs
Original file line number Diff line number Diff line change
@@ -39,6 +39,7 @@ use crate::borrow_check::{
renumber,
type_check::{self, MirTypeckRegionConstraints, MirTypeckResults},
universal_regions::UniversalRegions,
Upvar,
};

crate type PoloniusOutput = Output<RustcFacts>;
@@ -166,6 +167,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
flow_inits: &mut ResultsCursor<'cx, 'tcx, MaybeInitializedPlaces<'cx, 'tcx>>,
move_data: &MoveData<'tcx>,
borrow_set: &BorrowSet<'tcx>,
upvars: &[Upvar],
) -> NllOutput<'tcx> {
let mut all_facts = AllFacts::enabled(infcx.tcx).then_some(AllFacts::default());

@@ -188,6 +190,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
flow_inits,
move_data,
elements,
upvars,
);

if let Some(all_facts) = &mut all_facts {
38 changes: 37 additions & 1 deletion src/librustc_mir/borrow_check/path_utils.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use crate::borrow_check::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation};
use crate::borrow_check::places_conflict;
use crate::borrow_check::AccessDepth;
use crate::borrow_check::Upvar;
use crate::dataflow::indexes::BorrowIndex;
use rustc_data_structures::graph::dominators::Dominators;
use rustc_middle::mir::BorrowKind;
use rustc_middle::mir::{BasicBlock, Body, Location, Place};
use rustc_middle::mir::{BasicBlock, Body, Field, Location, Place, PlaceRef, ProjectionElem};
use rustc_middle::ty::TyCtxt;

/// Returns `true` if the borrow represented by `kind` is
@@ -135,3 +136,38 @@ pub(super) fn borrow_of_local_data(place: Place<'_>) -> bool {
// Any errors will be caught on the initial borrow
!place.is_indirect()
}

/// If `place` is a field projection, and the field is being projected from a closure type,
/// then returns the index of the field being projected. Note that this closure will always
/// be `self` in the current MIR, because that is the only time we directly access the fields
/// of a closure type.
pub(crate) fn is_upvar_field_projection(
tcx: TyCtxt<'tcx>,
upvars: &[Upvar],
place_ref: PlaceRef<'tcx>,
body: &Body<'tcx>,
) -> Option<Field> {
let mut place_projection = place_ref.projection;
let mut by_ref = false;

if let [proj_base @ .., ProjectionElem::Deref] = place_projection {
place_projection = proj_base;
by_ref = true;
}

match place_projection {
[base @ .., ProjectionElem::Field(field, _ty)] => {
let base_ty = Place::ty_from(place_ref.local, base, body, tcx).ty;

if (base_ty.is_closure() || base_ty.is_generator())
&& (!by_ref || upvars[field.index()].by_ref)
{
Some(*field)
} else {
None
}
}

_ => None,
}
}
18 changes: 15 additions & 3 deletions src/librustc_mir/borrow_check/region_infer/mod.rs
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound}
use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin, RegionVariableOrigin};
use rustc_middle::mir::{
Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
ConstraintCategory, Local, Location,
ConstraintCategory, Local, Location, ReturnConstraint,
};
use rustc_middle::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable};
use rustc_span::Span;
@@ -2017,7 +2017,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
| ConstraintCategory::BoringNoLocation
| ConstraintCategory::Internal => false,
ConstraintCategory::TypeAnnotation
| ConstraintCategory::Return
| ConstraintCategory::Return(_)
| ConstraintCategory::Yield => true,
_ => constraint_sup_scc != target_scc,
}
@@ -2042,14 +2042,26 @@ impl<'tcx> RegionInferenceContext<'tcx> {

if let Some(i) = best_choice {
if let Some(next) = categorized_path.get(i + 1) {
if categorized_path[i].0 == ConstraintCategory::Return
if matches!(categorized_path[i].0, ConstraintCategory::Return(_))
&& next.0 == ConstraintCategory::OpaqueType
{
// The return expression is being influenced by the return type being
// impl Trait, point at the return type and not the return expr.
return *next;
}
}

if categorized_path[i].0 == ConstraintCategory::Return(ReturnConstraint::Normal) {
let field = categorized_path.iter().find_map(|p| {
if let ConstraintCategory::ClosureUpvar(f) = p.0 { Some(f) } else { None }
});

if let Some(field) = field {
categorized_path[i].0 =
ConstraintCategory::Return(ReturnConstraint::ClosureUpvar(field));
}
}

return categorized_path[i];
}

27 changes: 22 additions & 5 deletions src/librustc_mir/borrow_check/type_check/mod.rs
Original file line number Diff line number Diff line change
@@ -55,13 +55,15 @@ use crate::borrow_check::{
location::LocationTable,
member_constraints::MemberConstraintSet,
nll::ToRegionVid,
path_utils,
region_infer::values::{
LivenessValues, PlaceholderIndex, PlaceholderIndices, RegionValueElements,
},
region_infer::{ClosureRegionRequirementsExt, TypeTest},
renumber,
type_check::free_region_relations::{CreateResult, UniversalRegionRelations},
universal_regions::{DefiningTy, UniversalRegions},
Upvar,
};

macro_rules! span_mirbug {
@@ -132,6 +134,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
move_data: &MoveData<'tcx>,
elements: &Rc<RegionValueElements>,
upvars: &[Upvar],
) -> MirTypeckResults<'tcx> {
let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
let mut constraints = MirTypeckRegionConstraints {
@@ -162,6 +165,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
borrow_set,
all_facts,
constraints: &mut constraints,
upvars,
};

let opaque_type_values = type_check_internal(
@@ -577,7 +581,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
for constraint in constraints.outlives().iter() {
let mut constraint = *constraint;
constraint.locations = locations;
if let ConstraintCategory::Return
if let ConstraintCategory::Return(_)
| ConstraintCategory::UseAsConst
| ConstraintCategory::UseAsStatic = constraint.category
{
@@ -827,6 +831,7 @@ struct BorrowCheckContext<'a, 'tcx> {
all_facts: &'a mut Option<AllFacts>,
borrow_set: &'a BorrowSet<'tcx>,
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
upvars: &'a [Upvar],
}

crate struct MirTypeckResults<'tcx> {
@@ -1420,7 +1425,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ConstraintCategory::UseAsConst
}
} else {
ConstraintCategory::Return
ConstraintCategory::Return(ReturnConstraint::Normal)
}
}
Some(l) if !body.local_decls[l].is_user_variable() => {
@@ -1703,7 +1708,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ConstraintCategory::UseAsConst
}
} else {
ConstraintCategory::Return
ConstraintCategory::Return(ReturnConstraint::Normal)
}
}
Some(l) if !body.local_decls[l].is_user_variable() => {
@@ -2487,14 +2492,26 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
);

let mut cursor = borrowed_place.projection.as_ref();
let tcx = self.infcx.tcx;
let field = path_utils::is_upvar_field_projection(
tcx,
&self.borrowck_context.upvars,
borrowed_place.as_ref(),
body,
);
let category = if let Some(field) = field {
ConstraintCategory::ClosureUpvar(self.borrowck_context.upvars[field.index()].var_hir_id)
} else {
ConstraintCategory::Boring
};

while let [proj_base @ .., elem] = cursor {
cursor = proj_base;

debug!("add_reborrow_constraint - iteration {:?}", elem);

match elem {
ProjectionElem::Deref => {
let tcx = self.infcx.tcx;
let base_ty = Place::ty_from(borrowed_place.local, proj_base, body, tcx).ty;

debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
@@ -2504,7 +2521,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
sup: ref_region.to_region_vid(),
sub: borrow_region.to_region_vid(),
locations: location.to_locations(),
category: ConstraintCategory::Boring,
category,
});

match mutbl {
22 changes: 22 additions & 0 deletions src/test/ui/async-await/issue-69446-fnmut-capture.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Regression test for issue #69446 - we should display
// which variable is captured
// edition:2018

use core::future::Future;

struct Foo;
impl Foo {
fn foo(&mut self) {}
}

async fn bar<T>(_: impl FnMut() -> T)
where
T: Future<Output = ()>,
{}

fn main() {
let mut x = Foo;
bar(move || async { //~ ERROR captured
x.foo();
});
}
19 changes: 19 additions & 0 deletions src/test/ui/async-await/issue-69446-fnmut-capture.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
error: captured variable cannot escape `FnMut` closure body
--> $DIR/issue-69446-fnmut-capture.rs:19:17
|
LL | let mut x = Foo;
| ----- variable defined here
LL | bar(move || async {
| _______________-_^
| | |
| | inferred to be a `FnMut` closure
LL | | x.foo();
| | - variable captured here
LL | | });
| |_____^ returns an `async` block that contains a reference to a captured variable, which then escapes the closure body
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
= note: ...therefore, they cannot allow references to captured variables to escape

error: aborting due to previous error

3 changes: 3 additions & 0 deletions src/test/ui/borrowck/borrowck-describe-lvalue.stderr
Original file line number Diff line number Diff line change
@@ -21,10 +21,13 @@ LL | *y = 1;
error: captured variable cannot escape `FnMut` closure body
--> $DIR/borrowck-describe-lvalue.rs:264:16
|
LL | let mut x = 0;
| ----- variable defined here
LL | || {
| - inferred to be a `FnMut` closure
LL | / || {
LL | | let y = &mut x;
| | - variable captured here
LL | | &mut x;
LL | | *y = 1;
LL | | drop(y);
8 changes: 7 additions & 1 deletion src/test/ui/issues/issue-40510-1.stderr
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
error: captured variable cannot escape `FnMut` closure body
--> $DIR/issue-40510-1.rs:7:9
|
LL | let mut x: Box<()> = Box::new(());
| ----- variable defined here
LL |
LL | || {
| - inferred to be a `FnMut` closure
LL | &mut x
| ^^^^^^ returns a reference to a captured variable which escapes the closure body
| ^^^^^-
| | |
| | variable captured here
| returns a reference to a captured variable which escapes the closure body
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
= note: ...therefore, they cannot allow references to captured variables to escape
4 changes: 4 additions & 0 deletions src/test/ui/issues/issue-40510-3.stderr
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
error: captured variable cannot escape `FnMut` closure body
--> $DIR/issue-40510-3.rs:7:9
|
LL | let mut x: Vec<()> = Vec::new();
| ----- variable defined here
LL |
LL | || {
| - inferred to be a `FnMut` closure
LL | / || {
LL | | x.push(())
| | - variable captured here
LL | | }
| |_________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body
|
3 changes: 3 additions & 0 deletions src/test/ui/issues/issue-49824.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
error: captured variable cannot escape `FnMut` closure body
--> $DIR/issue-49824.rs:4:9
|
LL | let mut x = 0;
| ----- variable defined here
LL | || {
| - inferred to be a `FnMut` closure
LL | / || {
LL | |
LL | | let _y = &mut x;
| | - variable captured here
LL | | }
| |_________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body
|
8 changes: 6 additions & 2 deletions src/test/ui/nll/issue-53040.stderr
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
error: captured variable cannot escape `FnMut` closure body
--> $DIR/issue-53040.rs:3:8
|
LL | let mut v: Vec<()> = Vec::new();
| ----- variable defined here
LL | || &mut v;
| - ^^^^^^ returns a reference to a captured variable which escapes the closure body
| |
| - ^^^^^-
| | | |
| | | variable captured here
| | returns a reference to a captured variable which escapes the closure body
| inferred to be a `FnMut` closure
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
error: captured variable cannot escape `FnMut` closure body
--> $DIR/regions-return-ref-to-upvar-issue-17403.rs:7:24
|
LL | let mut x = 0;
| ----- variable defined here
LL | let mut f = || &mut x;
| - ^^^^^^ returns a reference to a captured variable which escapes the closure body
| |
| - ^^^^^-
| | | |
| | | variable captured here
| | returns a reference to a captured variable which escapes the closure body
| inferred to be a `FnMut` closure
|
= note: `FnMut` closures only have access to their captured variables while they are executing...