1 //! See docs in build/expr/mod.rs
3 use crate::build
::expr
::category
::Category
;
4 use crate::build
::ForGuard
::{OutsideGuard, RefWithinGuard}
;
5 use crate::build
::{BlockAnd, BlockAndExtension, Builder}
;
6 use rustc_hir
::def_id
::DefId
;
8 use rustc_middle
::hir
::place
::ProjectionKind
as HirProjectionKind
;
9 use rustc_middle
::middle
::region
;
10 use rustc_middle
::mir
::AssertKind
::BoundsCheck
;
11 use rustc_middle
::mir
::*;
12 use rustc_middle
::thir
::*;
13 use rustc_middle
::ty
::AdtDef
;
14 use rustc_middle
::ty
::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, Variance}
;
16 use rustc_target
::abi
::VariantIdx
;
18 use rustc_index
::vec
::Idx
;
22 /// The "outermost" place that holds this value.
23 #[derive(Copy, Clone, Debug, PartialEq)]
24 crate enum PlaceBase
{
25 /// Denotes the start of a `Place`.
28 /// When building place for an expression within a closure, the place might start off a
29 /// captured path. When `capture_disjoint_fields` is enabled, we might not know the capture
30 /// index (within the desugared closure) of the captured path until most of the projections
31 /// are applied. We use `PlaceBase::Upvar` to keep track of the root variable off of which the
32 /// captured path starts, the closure the capture belongs to and the trait the closure
35 /// Once we have figured out the capture index, we can convert the place builder to start from
36 /// `PlaceBase::Local`.
38 /// Consider the following example
40 /// let t = (10, (10, (10, 10)));
43 /// println!("{}", t.0.0.0);
46 /// Here the THIR expression for `t.0.0.0` will be something like
55 /// When `capture_disjoint_fields` is enabled, `t.0.0.0` is captured and we won't be able to
56 /// figure out that it is captured until all the `Field` projections are applied.
58 /// HirId of the upvar
60 /// DefId of the closure
61 closure_def_id
: DefId
,
62 /// The trait closure implements, `Fn`, `FnMut`, `FnOnce`
63 closure_kind
: ty
::ClosureKind
,
67 /// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a
68 /// place by pushing more and more projections onto the end, and then convert the final set into a
69 /// place using the `into_place` method.
71 /// This is used internally when building a place for an expression like `a.b.c`. The fields `b`
72 /// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
73 #[derive(Clone, Debug, PartialEq)]
74 crate struct PlaceBuilder
<'tcx
> {
76 projection
: Vec
<PlaceElem
<'tcx
>>,
79 /// Given a list of MIR projections, convert them to list of HIR ProjectionKind.
80 /// The projections are truncated to represent a path that might be captured by a
81 /// closure/generator. This implies the vector returned from this function doesn't contain
82 /// ProjectionElems `Downcast`, `ConstantIndex`, `Index`, or `Subslice` because those will never be
83 /// part of a path that is captured by a closure. We stop applying projections once we see the first
84 /// projection that isn't captured by a closure.
85 fn convert_to_hir_projections_and_truncate_for_capture
<'tcx
>(
86 mir_projections
: &[PlaceElem
<'tcx
>],
87 ) -> Vec
<HirProjectionKind
> {
88 let mut hir_projections
= Vec
::new();
89 let mut variant
= None
;
91 for mir_projection
in mir_projections
{
92 let hir_projection
= match mir_projection
{
93 ProjectionElem
::Deref
=> HirProjectionKind
::Deref
,
94 ProjectionElem
::Field(field
, _
) => {
95 let variant
= variant
.unwrap_or(VariantIdx
::new(0));
96 HirProjectionKind
::Field(field
.index() as u32, variant
)
98 ProjectionElem
::Downcast(.., idx
) => {
99 // We don't expect to see multi-variant enums here, as earlier
100 // phases will have truncated them already. However, there can
101 // still be downcasts, thanks to single-variant enums.
102 // We keep track of VariantIdx so we can use this information
103 // if the next ProjectionElem is a Field.
104 variant
= Some(*idx
);
107 ProjectionElem
::Index(..)
108 | ProjectionElem
::ConstantIndex { .. }
109 | ProjectionElem
::Subslice { .. }
=> {
110 // We don't capture array-access projections.
111 // We can stop here as arrays are captured completely.
116 hir_projections
.push(hir_projection
);
122 /// Return true if the `proj_possible_ancestor` represents an ancestor path
123 /// to `proj_capture` or `proj_possible_ancestor` is same as `proj_capture`,
124 /// assuming they both start off of the same root variable.
126 /// **Note:** It's the caller's responsibility to ensure that both lists of projections
127 /// start off of the same root variable.
129 /// Eg: 1. `foo.x` which is represented using `projections=[Field(x)]` is an ancestor of
130 /// `foo.x.y` which is represented using `projections=[Field(x), Field(y)]`.
131 /// Note both `foo.x` and `foo.x.y` start off of the same root variable `foo`.
132 /// 2. Since we only look at the projections here function will return `bar.x` as an a valid
133 /// ancestor of `foo.x.y`. It's the caller's responsibility to ensure that both projections
134 /// list are being applied to the same root variable.
135 fn is_ancestor_or_same_capture(
136 proj_possible_ancestor
: &Vec
<HirProjectionKind
>,
137 proj_capture
: &[HirProjectionKind
],
139 // We want to make sure `is_ancestor_or_same_capture("x.0.0", "x.0")` to return false.
140 // Therefore we can't just check if all projections are same in the zipped iterator below.
141 if proj_possible_ancestor
.len() > proj_capture
.len() {
145 iter
::zip(proj_possible_ancestor
, proj_capture
).all(|(a
, b
)| a
== b
)
148 /// Computes the index of a capture within the desugared closure provided the closure's
149 /// `closure_min_captures` and the capture's index of the capture in the
150 /// `ty::MinCaptureList` of the root variable `var_hir_id`.
151 fn compute_capture_idx
<'tcx
>(
152 closure_min_captures
: &ty
::RootVariableMinCaptureList
<'tcx
>,
157 for (var_id
, capture_list
) in closure_min_captures
{
158 if *var_id
== var_hir_id
{
162 res
+= capture_list
.len();
169 /// Given a closure, returns the index of a capture within the desugared closure struct and the
170 /// `ty::CapturedPlace` which is the ancestor of the Place represented using the `var_hir_id`
171 /// and `projection`.
173 /// Note there will be at most one ancestor for any given Place.
175 /// Returns None, when the ancestor is not found.
176 fn find_capture_matching_projections
<'a
, 'tcx
>(
177 typeck_results
: &'a ty
::TypeckResults
<'tcx
>,
179 closure_def_id
: DefId
,
180 projections
: &[PlaceElem
<'tcx
>],
181 ) -> Option
<(usize, &'a ty
::CapturedPlace
<'tcx
>)> {
182 let closure_min_captures
= typeck_results
.closure_min_captures
.get(&closure_def_id
)?
;
183 let root_variable_min_captures
= closure_min_captures
.get(&var_hir_id
)?
;
185 let hir_projections
= convert_to_hir_projections_and_truncate_for_capture(projections
);
187 // If an ancestor is found, `idx` is the index within the list of captured places
188 // for root variable `var_hir_id` and `capture` is the `ty::CapturedPlace` itself.
189 let (idx
, capture
) = root_variable_min_captures
.iter().enumerate().find(|(_
, capture
)| {
190 let possible_ancestor_proj_kinds
=
191 capture
.place
.projections
.iter().map(|proj
| proj
.kind
).collect();
192 is_ancestor_or_same_capture(&possible_ancestor_proj_kinds
, &hir_projections
)
195 // Convert index to be from the perspective of the entire closure_min_captures map
196 // instead of just the root variable capture list
197 Some((compute_capture_idx(closure_min_captures
, var_hir_id
, idx
), capture
))
200 /// Takes a PlaceBuilder and resolves the upvar (if any) within it, so that the
201 /// `PlaceBuilder` now starts from `PlaceBase::Local`.
203 /// Returns a Result with the error being the PlaceBuilder (`from_builder`) that was not found.
204 fn to_upvars_resolved_place_builder
<'a
, 'tcx
>(
205 from_builder
: PlaceBuilder
<'tcx
>,
207 typeck_results
: &'a ty
::TypeckResults
<'tcx
>,
208 ) -> Result
<PlaceBuilder
<'tcx
>, PlaceBuilder
<'tcx
>> {
209 match from_builder
.base
{
210 PlaceBase
::Local(_
) => Ok(from_builder
),
211 PlaceBase
::Upvar { var_hir_id, closure_def_id, closure_kind }
=> {
212 let mut upvar_resolved_place_builder
= PlaceBuilder
::from(ty
::CAPTURE_STRUCT_LOCAL
);
214 ty
::ClosureKind
::Fn
| ty
::ClosureKind
::FnMut
=> {
215 upvar_resolved_place_builder
= upvar_resolved_place_builder
.deref();
217 ty
::ClosureKind
::FnOnce
=> {}
220 let Some((capture_index
, capture
)) =
221 find_capture_matching_projections(
225 &from_builder
.projection
,
227 let closure_span
= tcx
.def_span(closure_def_id
);
228 if !enable_precise_capture(tcx
, closure_span
) {
230 "No associated capture found for {:?}[{:#?}] even though \
231 capture_disjoint_fields isn't enabled",
233 from_builder
.projection
237 "No associated capture found for {:?}[{:#?}]",
238 var_hir_id
, from_builder
.projection
,
241 return Err(from_builder
);
244 // We won't be building MIR if the closure wasn't local
245 let closure_hir_id
= tcx
.hir().local_def_id_to_hir_id(closure_def_id
.expect_local());
246 let closure_ty
= typeck_results
.node_type(closure_hir_id
);
248 let substs
= match closure_ty
.kind() {
249 ty
::Closure(_
, substs
) => ty
::UpvarSubsts
::Closure(substs
),
250 ty
::Generator(_
, substs
, _
) => ty
::UpvarSubsts
::Generator(substs
),
251 _
=> bug
!("Lowering capture for non-closure type {:?}", closure_ty
),
254 // Access the capture by accessing the field within the Closure struct.
256 // We must have inferred the capture types since we are building MIR, therefore
257 // it's safe to call `tuple_element_ty` and we can unwrap here because
258 // we know that the capture exists and is the `capture_index`-th capture.
259 let var_ty
= substs
.tupled_upvars_ty().tuple_fields()[capture_index
];
261 upvar_resolved_place_builder
=
262 upvar_resolved_place_builder
.field(Field
::new(capture_index
), var_ty
);
264 // If the variable is captured via ByRef(Immutable/Mutable) Borrow,
265 // we need to deref it
266 upvar_resolved_place_builder
= match capture
.info
.capture_kind
{
267 ty
::UpvarCapture
::ByRef(_
) => upvar_resolved_place_builder
.deref(),
268 ty
::UpvarCapture
::ByValue
=> upvar_resolved_place_builder
,
271 let next_projection
= capture
.place
.projections
.len();
272 let mut curr_projections
= from_builder
.projection
;
274 // We used some of the projections to build the capture itself,
275 // now we apply the remaining to the upvar resolved place.
276 upvar_resolved_place_builder
278 .extend(curr_projections
.drain(next_projection
..));
280 Ok(upvar_resolved_place_builder
)
285 impl<'tcx
> PlaceBuilder
<'tcx
> {
286 crate fn into_place
<'a
>(
289 typeck_results
: &'a ty
::TypeckResults
<'tcx
>,
291 if let PlaceBase
::Local(local
) = self.base
{
292 Place { local, projection: tcx.intern_place_elems(&self.projection) }
294 self.expect_upvars_resolved(tcx
, typeck_results
).into_place(tcx
, typeck_results
)
298 fn expect_upvars_resolved
<'a
>(
301 typeck_results
: &'a ty
::TypeckResults
<'tcx
>,
302 ) -> PlaceBuilder
<'tcx
> {
303 to_upvars_resolved_place_builder(self, tcx
, typeck_results
).unwrap()
306 /// Attempts to resolve the `PlaceBuilder`.
307 /// On success, it will return the resolved `PlaceBuilder`.
308 /// On failure, it will return itself.
310 /// Upvars resolve may fail for a `PlaceBuilder` when attempting to
311 /// resolve a disjoint field whose root variable is not captured
312 /// (destructured assignments) or when attempting to resolve a root
313 /// variable (discriminant matching with only wildcard arm) that is
314 /// not captured. This can happen because the final mir that will be
315 /// generated doesn't require a read for this place. Failures will only
316 /// happen inside closures.
317 crate fn try_upvars_resolved
<'a
>(
320 typeck_results
: &'a ty
::TypeckResults
<'tcx
>,
321 ) -> Result
<PlaceBuilder
<'tcx
>, PlaceBuilder
<'tcx
>> {
322 to_upvars_resolved_place_builder(self, tcx
, typeck_results
)
325 crate fn base(&self) -> PlaceBase
{
329 crate fn field(self, f
: Field
, ty
: Ty
<'tcx
>) -> Self {
330 self.project(PlaceElem
::Field(f
, ty
))
333 crate fn deref(self) -> Self {
334 self.project(PlaceElem
::Deref
)
337 crate fn downcast(self, adt_def
: AdtDef
<'tcx
>, variant_index
: VariantIdx
) -> Self {
338 self.project(PlaceElem
::Downcast(Some(adt_def
.variant(variant_index
).name
), variant_index
))
341 fn index(self, index
: Local
) -> Self {
342 self.project(PlaceElem
::Index(index
))
345 crate fn project(mut self, elem
: PlaceElem
<'tcx
>) -> Self {
346 self.projection
.push(elem
);
351 impl<'tcx
> From
<Local
> for PlaceBuilder
<'tcx
> {
352 fn from(local
: Local
) -> Self {
353 Self { base: PlaceBase::Local(local), projection: Vec::new() }
357 impl<'tcx
> From
<PlaceBase
> for PlaceBuilder
<'tcx
> {
358 fn from(base
: PlaceBase
) -> Self {
359 Self { base, projection: Vec::new() }
363 impl<'a
, 'tcx
> Builder
<'a
, 'tcx
> {
364 /// Compile `expr`, yielding a place that we can move from etc.
366 /// WARNING: Any user code might:
367 /// * Invalidate any slice bounds checks performed.
368 /// * Change the address that this `Place` refers to.
369 /// * Modify the memory that this place refers to.
370 /// * Invalidate the memory that this place refers to, this will be caught
371 /// by borrow checking.
373 /// Extra care is needed if any user code is allowed to run between calling
374 /// this method and using it, as is the case for `match` and index
378 mut block
: BasicBlock
,
380 ) -> BlockAnd
<Place
<'tcx
>> {
381 let place_builder
= unpack
!(block
= self.as_place_builder(block
, expr
));
382 block
.and(place_builder
.into_place(self.tcx
, self.typeck_results
))
385 /// This is used when constructing a compound `Place`, so that we can avoid creating
386 /// intermediate `Place` values until we know the full set of projections.
387 crate fn as_place_builder(
391 ) -> BlockAnd
<PlaceBuilder
<'tcx
>> {
392 self.expr_as_place(block
, expr
, Mutability
::Mut
, None
)
395 /// Compile `expr`, yielding a place that we can move from etc.
396 /// Mutability note: The caller of this method promises only to read from the resulting
397 /// place. The place itself may or may not be mutable:
398 /// * If this expr is a place expr like a.b, then we will return that place.
399 /// * Otherwise, a temporary is created: in that event, it will be an immutable temporary.
400 crate fn as_read_only_place(
402 mut block
: BasicBlock
,
404 ) -> BlockAnd
<Place
<'tcx
>> {
405 let place_builder
= unpack
!(block
= self.as_read_only_place_builder(block
, expr
));
406 block
.and(place_builder
.into_place(self.tcx
, self.typeck_results
))
409 /// This is used when constructing a compound `Place`, so that we can avoid creating
410 /// intermediate `Place` values until we know the full set of projections.
411 /// Mutability note: The caller of this method promises only to read from the resulting
412 /// place. The place itself may or may not be mutable:
413 /// * If this expr is a place expr like a.b, then we will return that place.
414 /// * Otherwise, a temporary is created: in that event, it will be an immutable temporary.
415 fn as_read_only_place_builder(
419 ) -> BlockAnd
<PlaceBuilder
<'tcx
>> {
420 self.expr_as_place(block
, expr
, Mutability
::Not
, None
)
425 mut block
: BasicBlock
,
427 mutability
: Mutability
,
428 fake_borrow_temps
: Option
<&mut Vec
<Local
>>,
429 ) -> BlockAnd
<PlaceBuilder
<'tcx
>> {
430 debug
!("expr_as_place(block={:?}, expr={:?}, mutability={:?})", block
, expr
, mutability
);
433 let expr_span
= expr
.span
;
434 let source_info
= this
.source_info(expr_span
);
436 ExprKind
::Scope { region_scope, lint_level, value }
=> {
437 this
.in_scope((region_scope
, source_info
), lint_level
, |this
| {
438 this
.expr_as_place(block
, &this
.thir
[value
], mutability
, fake_borrow_temps
)
441 ExprKind
::Field { lhs, name }
=> {
442 let place_builder
= unpack
!(
444 this
.expr_as_place(block
, &this
.thir
[lhs
], mutability
, fake_borrow_temps
,)
446 block
.and(place_builder
.field(name
, expr
.ty
))
448 ExprKind
::Deref { arg }
=> {
449 let place_builder
= unpack
!(
451 this
.expr_as_place(block
, &this
.thir
[arg
], mutability
, fake_borrow_temps
,)
453 block
.and(place_builder
.deref())
455 ExprKind
::Index { lhs, index }
=> this
.lower_index_expression(
465 ExprKind
::UpvarRef { closure_def_id, var_hir_id }
=> {
466 let upvar_id
= ty
::UpvarId
::new(var_hir_id
, closure_def_id
.expect_local());
467 this
.lower_captured_upvar(block
, upvar_id
)
470 ExprKind
::VarRef { id }
=> {
471 let place_builder
= if this
.is_bound_var_in_guard(id
) {
472 let index
= this
.var_local_id(id
, RefWithinGuard
);
473 PlaceBuilder
::from(index
).deref()
475 let index
= this
.var_local_id(id
, OutsideGuard
);
476 PlaceBuilder
::from(index
)
478 block
.and(place_builder
)
481 ExprKind
::PlaceTypeAscription { source, user_ty }
=> {
482 let place_builder
= unpack
!(
483 block
= this
.expr_as_place(
490 if let Some(user_ty
) = user_ty
{
491 let annotation_index
=
492 this
.canonical_user_type_annotations
.push(CanonicalUserTypeAnnotation
{
493 span
: source_info
.span
,
495 inferred_ty
: expr
.ty
,
498 let place
= place_builder
.clone().into_place(this
.tcx
, this
.typeck_results
);
503 kind
: StatementKind
::AscribeUserType(
506 UserTypeProjection { base: annotation_index, projs: vec![] }
,
513 block
.and(place_builder
)
515 ExprKind
::ValueTypeAscription { source, user_ty }
=> {
516 let source
= &this
.thir
[source
];
518 unpack
!(block
= this
.as_temp(block
, source
.temp_lifetime
, source
, mutability
));
519 if let Some(user_ty
) = user_ty
{
520 let annotation_index
=
521 this
.canonical_user_type_annotations
.push(CanonicalUserTypeAnnotation
{
522 span
: source_info
.span
,
524 inferred_ty
: expr
.ty
,
530 kind
: StatementKind
::AscribeUserType(
533 UserTypeProjection { base: annotation_index, projs: vec![] }
,
540 block
.and(PlaceBuilder
::from(temp
))
543 ExprKind
::Array { .. }
544 | ExprKind
::Tuple { .. }
545 | ExprKind
::Adt { .. }
546 | ExprKind
::Closure { .. }
547 | ExprKind
::Unary { .. }
548 | ExprKind
::Binary { .. }
549 | ExprKind
::LogicalOp { .. }
550 | ExprKind
::Box { .. }
551 | ExprKind
::Cast { .. }
552 | ExprKind
::Use { .. }
553 | ExprKind
::NeverToAny { .. }
554 | ExprKind
::Pointer { .. }
555 | ExprKind
::Repeat { .. }
556 | ExprKind
::Borrow { .. }
557 | ExprKind
::AddressOf { .. }
558 | ExprKind
::Match { .. }
559 | ExprKind
::If { .. }
560 | ExprKind
::Loop { .. }
561 | ExprKind
::Block { .. }
562 | ExprKind
::Let { .. }
563 | ExprKind
::Assign { .. }
564 | ExprKind
::AssignOp { .. }
565 | ExprKind
::Break { .. }
566 | ExprKind
::Continue { .. }
567 | ExprKind
::Return { .. }
568 | ExprKind
::Literal { .. }
569 | ExprKind
::NamedConst { .. }
570 | ExprKind
::NonHirLiteral { .. }
571 | ExprKind
::ConstParam { .. }
572 | ExprKind
::ConstBlock { .. }
573 | ExprKind
::StaticRef { .. }
574 | ExprKind
::InlineAsm { .. }
575 | ExprKind
::Yield { .. }
576 | ExprKind
::ThreadLocalRef(_
)
577 | ExprKind
::Call { .. }
=> {
578 // these are not places, so we need to make a temporary.
579 debug_assert
!(!matches
!(Category
::of(&expr
.kind
), Some(Category
::Place
)));
581 unpack
!(block
= this
.as_temp(block
, expr
.temp_lifetime
, expr
, mutability
));
582 block
.and(PlaceBuilder
::from(temp
))
587 /// Lower a captured upvar. Note we might not know the actual capture index,
588 /// so we create a place starting from `PlaceBase::Upvar`, which will be resolved
589 /// once all projections that allow us to identify a capture have been applied.
590 fn lower_captured_upvar(
593 upvar_id
: ty
::UpvarId
,
594 ) -> BlockAnd
<PlaceBuilder
<'tcx
>> {
595 let closure_ty
= self
597 .node_type(self.tcx
.hir().local_def_id_to_hir_id(upvar_id
.closure_expr_id
));
599 let closure_kind
= if let ty
::Closure(_
, closure_substs
) = closure_ty
.kind() {
600 self.infcx
.closure_kind(closure_substs
).unwrap()
602 // Generators are considered FnOnce.
603 ty
::ClosureKind
::FnOnce
606 block
.and(PlaceBuilder
::from(PlaceBase
::Upvar
{
607 var_hir_id
: upvar_id
.var_path
.hir_id
,
608 closure_def_id
: upvar_id
.closure_expr_id
.to_def_id(),
613 /// Lower an index expression
615 /// This has two complications;
617 /// * We need to do a bounds check.
618 /// * We need to ensure that the bounds check can't be invalidated using an
619 /// expression like `x[1][{x = y; 2}]`. We use fake borrows here to ensure
620 /// that this is the case.
621 fn lower_index_expression(
623 mut block
: BasicBlock
,
626 mutability
: Mutability
,
627 fake_borrow_temps
: Option
<&mut Vec
<Local
>>,
628 temp_lifetime
: Option
<region
::Scope
>,
630 source_info
: SourceInfo
,
631 ) -> BlockAnd
<PlaceBuilder
<'tcx
>> {
632 let base_fake_borrow_temps
= &mut Vec
::new();
633 let is_outermost_index
= fake_borrow_temps
.is_none();
634 let fake_borrow_temps
= fake_borrow_temps
.unwrap_or(base_fake_borrow_temps
);
637 unpack
!(block
= self.expr_as_place(block
, base
, mutability
, Some(fake_borrow_temps
),));
639 // Making this a *fresh* temporary means we do not have to worry about
640 // the index changing later: Nothing will ever change this temporary.
641 // The "retagging" transformation (for Stacked Borrows) relies on this.
642 let idx
= unpack
!(block
= self.as_temp(block
, temp_lifetime
, index
, Mutability
::Not
,));
644 block
= self.bounds_check(block
, base_place
.clone(), idx
, expr_span
, source_info
);
646 if is_outermost_index
{
647 self.read_fake_borrows(block
, fake_borrow_temps
, source_info
)
649 base_place
= base_place
.expect_upvars_resolved(self.tcx
, self.typeck_results
);
650 self.add_fake_borrows_of_base(
659 block
.and(base_place
.index(idx
))
665 slice
: PlaceBuilder
<'tcx
>,
668 source_info
: SourceInfo
,
670 let usize_ty
= self.tcx
.types
.usize;
671 let bool_ty
= self.tcx
.types
.bool
;
673 let len
= self.temp(usize_ty
, expr_span
);
674 let lt
= self.temp(bool_ty
, expr_span
);
677 self.cfg
.push_assign(
681 Rvalue
::Len(slice
.into_place(self.tcx
, self.typeck_results
)),
684 self.cfg
.push_assign(
690 Box
::new((Operand
::Copy(Place
::from(index
)), Operand
::Copy(len
))),
693 let msg
= BoundsCheck { len: Operand::Move(len), index: Operand::Copy(Place::from(index)) }
;
694 // assert!(lt, "...")
695 self.assert(block
, Operand
::Move(lt
), true, msg
, expr_span
)
698 fn add_fake_borrows_of_base(
700 base_place
: &PlaceBuilder
<'tcx
>,
702 fake_borrow_temps
: &mut Vec
<Local
>,
704 source_info
: SourceInfo
,
707 let local
= match base_place
.base
{
708 PlaceBase
::Local(local
) => local
,
709 PlaceBase
::Upvar { .. }
=> bug
!("Expected PlacseBase::Local found Upvar"),
712 let place_ty
= Place
::ty_from(local
, &base_place
.projection
, &self.local_decls
, tcx
);
713 if let ty
::Slice(_
) = place_ty
.ty
.kind() {
714 // We need to create fake borrows to ensure that the bounds
715 // check that we just did stays valid. Since we can't assign to
716 // unsized values, we only need to ensure that none of the
717 // pointers in the base place are modified.
718 for (idx
, elem
) in base_place
.projection
.iter().enumerate().rev() {
720 ProjectionElem
::Deref
=> {
721 let fake_borrow_deref_ty
= Place
::ty_from(
723 &base_place
.projection
[..idx
],
729 tcx
.mk_imm_ref(tcx
.lifetimes
.re_erased
, fake_borrow_deref_ty
);
730 let fake_borrow_temp
=
731 self.local_decls
.push(LocalDecl
::new(fake_borrow_ty
, expr_span
));
732 let projection
= tcx
.intern_place_elems(&base_place
.projection
[..idx
]);
733 self.cfg
.push_assign(
736 fake_borrow_temp
.into(),
738 tcx
.lifetimes
.re_erased
,
740 Place { local, projection }
,
743 fake_borrow_temps
.push(fake_borrow_temp
);
745 ProjectionElem
::Index(_
) => {
746 let index_ty
= Place
::ty_from(
748 &base_place
.projection
[..idx
],
752 match index_ty
.ty
.kind() {
753 // The previous index expression has already
754 // done any index expressions needed here.
755 ty
::Slice(_
) => break,
757 _
=> bug
!("unexpected index base"),
760 ProjectionElem
::Field(..)
761 | ProjectionElem
::Downcast(..)
762 | ProjectionElem
::ConstantIndex { .. }
763 | ProjectionElem
::Subslice { .. }
=> (),
769 fn read_fake_borrows(
772 fake_borrow_temps
: &mut Vec
<Local
>,
773 source_info
: SourceInfo
,
775 // All indexes have been evaluated now, read all of the
776 // fake borrows so that they are live across those index
778 for temp
in fake_borrow_temps
{
779 self.cfg
.push_fake_read(bb
, source_info
, FakeReadCause
::ForIndex
, Place
::from(*temp
));
784 /// Precise capture is enabled if the feature gate `capture_disjoint_fields` is enabled or if
785 /// user is using Rust Edition 2021 or higher.
786 fn enable_precise_capture(tcx
: TyCtxt
<'_
>, closure_span
: Span
) -> bool
{
787 tcx
.features().capture_disjoint_fields
|| closure_span
.rust_2021()