]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir_build/build/scope.rs
Rollup merge of #71030 - petrochenkov:linkorder2, r=nagisa
[rust.git] / src / librustc_mir_build / build / scope.rs
1 /*!
2 Managing the scope stack. The scopes are tied to lexical scopes, so as
3 we descend the HAIR, we push a scope on the stack, build its
4 contents, and then pop it off. Every scope is named by a
5 `region::Scope`.
6
7 ### SEME Regions
8
9 When pushing a new scope, we record the current point in the graph (a
10 basic block); this marks the entry to the scope. We then generate more
11 stuff in the control-flow graph. Whenever the scope is exited, either
12 via a `break` or `return` or just by fallthrough, that marks an exit
13 from the scope. Each lexical scope thus corresponds to a single-entry,
14 multiple-exit (SEME) region in the control-flow graph.
15
16 For now, we keep a mapping from each `region::Scope` to its
17 corresponding SEME region for later reference (see caveat in next
18 paragraph). This is because region scopes are tied to
19 them. Eventually, when we shift to non-lexical lifetimes, there should
20 be no need to remember this mapping.
21
22 ### Not so SEME Regions
23
24 In the course of building matches, it sometimes happens that certain code
25 (namely guards) gets executed multiple times. This means that the scope lexical
26 scope may in fact correspond to multiple, disjoint SEME regions. So in fact our
27 mapping is from one scope to a vector of SEME regions.
28
29 Also in matches, the scopes assigned to arms are not even SEME regions! Each
30 arm has a single region with one entry for each pattern. We manually
31 manipulate the scheduled drops in this scope to avoid dropping things multiple
32 times, although drop elaboration would clean this up for value drops.
33
34 ### Drops
35
36 The primary purpose for scopes is to insert drops: while building
37 the contents, we also accumulate places that need to be dropped upon
38 exit from each scope. This is done by calling `schedule_drop`. Once a
39 drop is scheduled, whenever we branch out we will insert drops of all
40 those places onto the outgoing edge. Note that we don't know the full
41 set of scheduled drops up front, and so whenever we exit from the
42 scope we only drop the values scheduled thus far. For example, consider
43 the scope S corresponding to this loop:
44
45 ```
46 # let cond = true;
47 loop {
48     let x = ..;
49     if cond { break; }
50     let y = ..;
51 }
52 ```
53
54 When processing the `let x`, we will add one drop to the scope for
55 `x`.  The break will then insert a drop for `x`. When we process `let
56 y`, we will add another drop (in fact, to a subscope, but let's ignore
57 that for now); any later drops would also drop `y`.
58
59 ### Early exit
60
61 There are numerous "normal" ways to early exit a scope: `break`,
62 `continue`, `return` (panics are handled separately). Whenever an
63 early exit occurs, the method `exit_scope` is called. It is given the
64 current point in execution where the early exit occurs, as well as the
65 scope you want to branch to (note that all early exits from to some
66 other enclosing scope). `exit_scope` will record this exit point and
67 also add all drops.
68
69 Panics are handled in a similar fashion, except that a panic always
70 returns out to the `DIVERGE_BLOCK`. To trigger a panic, simply call
71 `panic(p)` with the current point `p`. Or else you can call
72 `diverge_cleanup`, which will produce a block that you can branch to
73 which does the appropriate cleanup and then diverges. `panic(p)`
74 simply calls `diverge_cleanup()` and adds an edge from `p` to the
75 result.
76
77 ### Loop scopes
78
79 In addition to the normal scope stack, we track a loop scope stack
80 that contains only loops. It tracks where a `break` and `continue`
81 should go to.
82
83 */
84
85 use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
86 use crate::hair::{Expr, ExprRef, LintLevel};
87 use rustc_middle::middle::region;
88 use rustc_middle::mir::*;
89 use rustc_data_structures::fx::FxHashMap;
90 use rustc_hir as hir;
91 use rustc_hir::GeneratorKind;
92 use rustc_span::{Span, DUMMY_SP};
93 use std::collections::hash_map::Entry;
94 use std::mem;
95
96 #[derive(Debug)]
97 struct Scope {
98     /// The source scope this scope was created in.
99     source_scope: SourceScope,
100
101     /// the region span of this scope within source code.
102     region_scope: region::Scope,
103
104     /// the span of that region_scope
105     region_scope_span: Span,
106
107     /// set of places to drop when exiting this scope. This starts
108     /// out empty but grows as variables are declared during the
109     /// building process. This is a stack, so we always drop from the
110     /// end of the vector (top of the stack) first.
111     drops: Vec<DropData>,
112
113     moved_locals: Vec<Local>,
114
115     /// The cache for drop chain on “normal” exit into a particular BasicBlock.
116     cached_exits: FxHashMap<(BasicBlock, region::Scope), BasicBlock>,
117
118     /// The cache for drop chain on "generator drop" exit.
119     cached_generator_drop: Option<BasicBlock>,
120
121     /// The cache for drop chain on "unwind" exit.
122     cached_unwind: CachedBlock,
123 }
124
125 #[derive(Debug, Default)]
126 crate struct Scopes<'tcx> {
127     scopes: Vec<Scope>,
128     /// The current set of breakable scopes. See module comment for more details.
129     breakable_scopes: Vec<BreakableScope<'tcx>>,
130 }
131
132 #[derive(Debug)]
133 struct DropData {
134     /// span where drop obligation was incurred (typically where place was declared)
135     span: Span,
136
137     /// local to drop
138     local: Local,
139
140     /// Whether this is a value Drop or a StorageDead.
141     kind: DropKind,
142
143     /// The cached blocks for unwinds.
144     cached_block: CachedBlock,
145 }
146
147 #[derive(Debug, Default, Clone, Copy)]
148 struct CachedBlock {
149     /// The cached block for the cleanups-on-diverge path. This block
150     /// contains code to run the current drop and all the preceding
151     /// drops (i.e., those having lower index in Drop’s Scope drop
152     /// array)
153     unwind: Option<BasicBlock>,
154
155     /// The cached block for unwinds during cleanups-on-generator-drop path
156     ///
157     /// This is split from the standard unwind path here to prevent drop
158     /// elaboration from creating drop flags that would have to be captured
159     /// by the generator. I'm not sure how important this optimization is,
160     /// but it is here.
161     generator_drop: Option<BasicBlock>,
162 }
163
164 #[derive(Debug, PartialEq, Eq)]
165 pub(crate) enum DropKind {
166     Value,
167     Storage,
168 }
169
170 #[derive(Clone, Debug)]
171 struct BreakableScope<'tcx> {
172     /// Region scope of the loop
173     region_scope: region::Scope,
174     /// Where the body of the loop begins. `None` if block
175     continue_block: Option<BasicBlock>,
176     /// Block to branch into when the loop or block terminates (either by being
177     /// `break`-en out from, or by having its condition to become false)
178     break_block: BasicBlock,
179     /// The destination of the loop/block expression itself (i.e., where to put
180     /// the result of a `break` expression)
181     break_destination: Place<'tcx>,
182 }
183
184 /// The target of an expression that breaks out of a scope
185 #[derive(Clone, Copy, Debug)]
186 crate enum BreakableTarget {
187     Continue(region::Scope),
188     Break(region::Scope),
189     Return,
190 }
191
192 impl CachedBlock {
193     fn invalidate(&mut self) {
194         *self = CachedBlock::default();
195     }
196
197     fn get(&self, generator_drop: bool) -> Option<BasicBlock> {
198         if generator_drop { self.generator_drop } else { self.unwind }
199     }
200
201     fn ref_mut(&mut self, generator_drop: bool) -> &mut Option<BasicBlock> {
202         if generator_drop { &mut self.generator_drop } else { &mut self.unwind }
203     }
204 }
205
206 impl Scope {
207     /// Invalidates all the cached blocks in the scope.
208     ///
209     /// Should always be run for all inner scopes when a drop is pushed into some scope enclosing a
210     /// larger extent of code.
211     ///
212     /// `storage_only` controls whether to invalidate only drop paths that run `StorageDead`.
213     /// `this_scope_only` controls whether to invalidate only drop paths that refer to the current
214     /// top-of-scope (as opposed to dependent scopes).
215     fn invalidate_cache(
216         &mut self,
217         storage_only: bool,
218         generator_kind: Option<GeneratorKind>,
219         this_scope_only: bool,
220     ) {
221         // FIXME: maybe do shared caching of `cached_exits` etc. to handle functions
222         // with lots of `try!`?
223
224         // cached exits drop storage and refer to the top-of-scope
225         self.cached_exits.clear();
226
227         // the current generator drop and unwind refer to top-of-scope
228         self.cached_generator_drop = None;
229
230         let ignore_unwinds = storage_only && generator_kind.is_none();
231         if !ignore_unwinds {
232             self.cached_unwind.invalidate();
233         }
234
235         if !ignore_unwinds && !this_scope_only {
236             for drop_data in &mut self.drops {
237                 drop_data.cached_block.invalidate();
238             }
239         }
240     }
241
242     /// Given a span and this scope's source scope, make a SourceInfo.
243     fn source_info(&self, span: Span) -> SourceInfo {
244         SourceInfo { span, scope: self.source_scope }
245     }
246
247     /// Whether there's anything to do for the cleanup path, that is,
248     /// when unwinding through this scope. This includes destructors,
249     /// but not StorageDead statements, which don't get emitted at all
250     /// for unwinding, for several reasons:
251     ///  * clang doesn't emit llvm.lifetime.end for C++ unwinding
252     ///  * LLVM's memory dependency analysis can't handle it atm
253     ///  * polluting the cleanup MIR with StorageDead creates
254     ///    landing pads even though there's no actual destructors
255     ///  * freeing up stack space has no effect during unwinding
256     /// Note that for generators we do emit StorageDeads, for the
257     /// use of optimizations in the MIR generator transform.
258     fn needs_cleanup(&self) -> bool {
259         self.drops.iter().any(|drop| match drop.kind {
260             DropKind::Value => true,
261             DropKind::Storage => false,
262         })
263     }
264 }
265
266 impl<'tcx> Scopes<'tcx> {
267     fn len(&self) -> usize {
268         self.scopes.len()
269     }
270
271     fn push_scope(&mut self, region_scope: (region::Scope, SourceInfo), vis_scope: SourceScope) {
272         debug!("push_scope({:?})", region_scope);
273         self.scopes.push(Scope {
274             source_scope: vis_scope,
275             region_scope: region_scope.0,
276             region_scope_span: region_scope.1.span,
277             drops: vec![],
278             moved_locals: vec![],
279             cached_generator_drop: None,
280             cached_exits: Default::default(),
281             cached_unwind: CachedBlock::default(),
282         });
283     }
284
285     fn pop_scope(
286         &mut self,
287         region_scope: (region::Scope, SourceInfo),
288     ) -> (Scope, Option<BasicBlock>) {
289         let scope = self.scopes.pop().unwrap();
290         assert_eq!(scope.region_scope, region_scope.0);
291         let unwind_to =
292             self.scopes.last().and_then(|next_scope| next_scope.cached_unwind.get(false));
293         (scope, unwind_to)
294     }
295
296     fn may_panic(&self, scope_count: usize) -> bool {
297         let len = self.len();
298         self.scopes[(len - scope_count)..].iter().any(|s| s.needs_cleanup())
299     }
300
301     /// Finds the breakable scope for a given label. This is used for
302     /// resolving `return`, `break` and `continue`.
303     fn find_breakable_scope(
304         &self,
305         span: Span,
306         target: BreakableTarget,
307     ) -> (BasicBlock, region::Scope, Option<Place<'tcx>>) {
308         let get_scope = |scope: region::Scope| {
309             // find the loop-scope by its `region::Scope`.
310             self.breakable_scopes
311                 .iter()
312                 .rfind(|breakable_scope| breakable_scope.region_scope == scope)
313                 .unwrap_or_else(|| span_bug!(span, "no enclosing breakable scope found"))
314         };
315         match target {
316             BreakableTarget::Return => {
317                 let scope = &self.breakable_scopes[0];
318                 if scope.break_destination != Place::return_place() {
319                     span_bug!(span, "`return` in item with no return scope");
320                 }
321                 (scope.break_block, scope.region_scope, Some(scope.break_destination))
322             }
323             BreakableTarget::Break(scope) => {
324                 let scope = get_scope(scope);
325                 (scope.break_block, scope.region_scope, Some(scope.break_destination))
326             }
327             BreakableTarget::Continue(scope) => {
328                 let scope = get_scope(scope);
329                 let continue_block = scope
330                     .continue_block
331                     .unwrap_or_else(|| span_bug!(span, "missing `continue` block"));
332                 (continue_block, scope.region_scope, None)
333             }
334         }
335     }
336
337     fn num_scopes_above(&self, region_scope: region::Scope, span: Span) -> usize {
338         let scope_count = self
339             .scopes
340             .iter()
341             .rev()
342             .position(|scope| scope.region_scope == region_scope)
343             .unwrap_or_else(|| span_bug!(span, "region_scope {:?} does not enclose", region_scope));
344         let len = self.len();
345         assert!(scope_count < len, "should not use `exit_scope` to pop ALL scopes");
346         scope_count
347     }
348
349     fn iter_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut Scope> + '_ {
350         self.scopes.iter_mut().rev()
351     }
352
353     fn top_scopes(&mut self, count: usize) -> impl DoubleEndedIterator<Item = &mut Scope> + '_ {
354         let len = self.len();
355         self.scopes[len - count..].iter_mut()
356     }
357
358     /// Returns the topmost active scope, which is known to be alive until
359     /// the next scope expression.
360     pub(super) fn topmost(&self) -> region::Scope {
361         self.scopes.last().expect("topmost_scope: no scopes present").region_scope
362     }
363
364     fn source_info(&self, index: usize, span: Span) -> SourceInfo {
365         self.scopes[self.len() - index].source_info(span)
366     }
367 }
368
369 impl<'a, 'tcx> Builder<'a, 'tcx> {
370     // Adding and removing scopes
371     // ==========================
372     //  Start a breakable scope, which tracks where `continue`, `break` and
373     //  `return` should branch to.
374     crate fn in_breakable_scope<F, R>(
375         &mut self,
376         loop_block: Option<BasicBlock>,
377         break_block: BasicBlock,
378         break_destination: Place<'tcx>,
379         f: F,
380     ) -> R
381     where
382         F: FnOnce(&mut Builder<'a, 'tcx>) -> R,
383     {
384         let region_scope = self.scopes.topmost();
385         let scope = BreakableScope {
386             region_scope,
387             continue_block: loop_block,
388             break_block,
389             break_destination,
390         };
391         self.scopes.breakable_scopes.push(scope);
392         let res = f(self);
393         let breakable_scope = self.scopes.breakable_scopes.pop().unwrap();
394         assert!(breakable_scope.region_scope == region_scope);
395         res
396     }
397
398     crate fn in_opt_scope<F, R>(
399         &mut self,
400         opt_scope: Option<(region::Scope, SourceInfo)>,
401         f: F,
402     ) -> BlockAnd<R>
403     where
404         F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R>,
405     {
406         debug!("in_opt_scope(opt_scope={:?})", opt_scope);
407         if let Some(region_scope) = opt_scope {
408             self.push_scope(region_scope);
409         }
410         let mut block;
411         let rv = unpack!(block = f(self));
412         if let Some(region_scope) = opt_scope {
413             unpack!(block = self.pop_scope(region_scope, block));
414         }
415         debug!("in_scope: exiting opt_scope={:?} block={:?}", opt_scope, block);
416         block.and(rv)
417     }
418
419     /// Convenience wrapper that pushes a scope and then executes `f`
420     /// to build its contents, popping the scope afterwards.
421     crate fn in_scope<F, R>(
422         &mut self,
423         region_scope: (region::Scope, SourceInfo),
424         lint_level: LintLevel,
425         f: F,
426     ) -> BlockAnd<R>
427     where
428         F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R>,
429     {
430         debug!("in_scope(region_scope={:?})", region_scope);
431         let source_scope = self.source_scope;
432         let tcx = self.hir.tcx();
433         if let LintLevel::Explicit(current_hir_id) = lint_level {
434             // Use `maybe_lint_level_root_bounded` with `root_lint_level` as a bound
435             // to avoid adding Hir dependences on our parents.
436             // We estimate the true lint roots here to avoid creating a lot of source scopes.
437
438             let parent_root = tcx.maybe_lint_level_root_bounded(
439                 self.source_scopes[source_scope].local_data.as_ref().assert_crate_local().lint_root,
440                 self.hir.root_lint_level,
441             );
442             let current_root =
443                 tcx.maybe_lint_level_root_bounded(current_hir_id, self.hir.root_lint_level);
444
445             if parent_root != current_root {
446                 self.source_scope = self.new_source_scope(
447                     region_scope.1.span,
448                     LintLevel::Explicit(current_root),
449                     None,
450                 );
451             }
452         }
453         self.push_scope(region_scope);
454         let mut block;
455         let rv = unpack!(block = f(self));
456         unpack!(block = self.pop_scope(region_scope, block));
457         self.source_scope = source_scope;
458         debug!("in_scope: exiting region_scope={:?} block={:?}", region_scope, block);
459         block.and(rv)
460     }
461
462     /// Push a scope onto the stack. You can then build code in this
463     /// scope and call `pop_scope` afterwards. Note that these two
464     /// calls must be paired; using `in_scope` as a convenience
465     /// wrapper maybe preferable.
466     crate fn push_scope(&mut self, region_scope: (region::Scope, SourceInfo)) {
467         self.scopes.push_scope(region_scope, self.source_scope);
468     }
469
470     /// Pops a scope, which should have region scope `region_scope`,
471     /// adding any drops onto the end of `block` that are needed.
472     /// This must match 1-to-1 with `push_scope`.
473     crate fn pop_scope(
474         &mut self,
475         region_scope: (region::Scope, SourceInfo),
476         mut block: BasicBlock,
477     ) -> BlockAnd<()> {
478         debug!("pop_scope({:?}, {:?})", region_scope, block);
479         // If we are emitting a `drop` statement, we need to have the cached
480         // diverge cleanup pads ready in case that drop panics.
481         if self.scopes.may_panic(1) {
482             self.diverge_cleanup();
483         }
484         let (scope, unwind_to) = self.scopes.pop_scope(region_scope);
485         let unwind_to = unwind_to.unwrap_or_else(|| self.resume_block());
486
487         unpack!(
488             block = build_scope_drops(
489                 &mut self.cfg,
490                 self.generator_kind,
491                 &scope,
492                 block,
493                 unwind_to,
494                 self.arg_count,
495                 false, // not generator
496                 false, // not unwind path
497             )
498         );
499
500         block.unit()
501     }
502
503     crate fn break_scope(
504         &mut self,
505         mut block: BasicBlock,
506         value: Option<ExprRef<'tcx>>,
507         scope: BreakableTarget,
508         source_info: SourceInfo,
509     ) -> BlockAnd<()> {
510         let (mut target_block, region_scope, destination) =
511             self.scopes.find_breakable_scope(source_info.span, scope);
512         if let BreakableTarget::Return = scope {
513             // We call this now, rather than when we start lowering the
514             // function so that the return block doesn't precede the entire
515             // rest of the CFG. Some passes and LLVM prefer blocks to be in
516             // approximately CFG order.
517             target_block = self.return_block();
518         }
519         if let Some(destination) = destination {
520             if let Some(value) = value {
521                 debug!("stmt_expr Break val block_context.push(SubExpr)");
522                 self.block_context.push(BlockFrame::SubExpr);
523                 unpack!(block = self.into(destination, block, value));
524                 self.block_context.pop();
525             } else {
526                 self.cfg.push_assign_unit(block, source_info, destination, self.hir.tcx())
527             }
528         } else {
529             assert!(value.is_none(), "`return` and `break` should have a destination");
530         }
531         self.exit_scope(source_info.span, region_scope, block, target_block);
532         self.cfg.start_new_block().unit()
533     }
534
535     /// Branch out of `block` to `target`, exiting all scopes up to
536     /// and including `region_scope`. This will insert whatever drops are
537     /// needed. See module comment for details.
538     crate fn exit_scope(
539         &mut self,
540         span: Span,
541         region_scope: region::Scope,
542         mut block: BasicBlock,
543         target: BasicBlock,
544     ) {
545         debug!(
546             "exit_scope(region_scope={:?}, block={:?}, target={:?})",
547             region_scope, block, target
548         );
549         let scope_count = self.scopes.num_scopes_above(region_scope, span);
550
551         // If we are emitting a `drop` statement, we need to have the cached
552         // diverge cleanup pads ready in case that drop panics.
553         let may_panic = self.scopes.may_panic(scope_count);
554         if may_panic {
555             self.diverge_cleanup();
556         }
557
558         let mut scopes = self.scopes.top_scopes(scope_count + 1).rev();
559         let mut scope = scopes.next().unwrap();
560         for next_scope in scopes {
561             if scope.drops.is_empty() {
562                 scope = next_scope;
563                 continue;
564             }
565             let source_info = scope.source_info(span);
566             block = match scope.cached_exits.entry((target, region_scope)) {
567                 Entry::Occupied(e) => {
568                     self.cfg.goto(block, source_info, *e.get());
569                     return;
570                 }
571                 Entry::Vacant(v) => {
572                     let b = self.cfg.start_new_block();
573                     self.cfg.goto(block, source_info, b);
574                     v.insert(b);
575                     b
576                 }
577             };
578
579             let unwind_to = next_scope.cached_unwind.get(false).unwrap_or_else(|| {
580                 debug_assert!(!may_panic, "cached block not present?");
581                 START_BLOCK
582             });
583
584             unpack!(
585                 block = build_scope_drops(
586                     &mut self.cfg,
587                     self.generator_kind,
588                     scope,
589                     block,
590                     unwind_to,
591                     self.arg_count,
592                     false, // not generator
593                     false, // not unwind path
594                 )
595             );
596
597             scope = next_scope;
598         }
599
600         self.cfg.goto(block, self.scopes.source_info(scope_count, span), target);
601     }
602
603     /// Creates a path that performs all required cleanup for dropping a generator.
604     ///
605     /// This path terminates in GeneratorDrop. Returns the start of the path.
606     /// None indicates there’s no cleanup to do at this point.
607     crate fn generator_drop_cleanup(&mut self) -> Option<BasicBlock> {
608         // Fill in the cache for unwinds
609         self.diverge_cleanup_gen(true);
610
611         let src_info = self.scopes.source_info(self.scopes.len(), self.fn_span);
612         let resume_block = self.resume_block();
613         let mut scopes = self.scopes.iter_mut().peekable();
614         let mut block = self.cfg.start_new_block();
615         let result = block;
616
617         while let Some(scope) = scopes.next() {
618             block = if let Some(b) = scope.cached_generator_drop {
619                 self.cfg.goto(block, src_info, b);
620                 return Some(result);
621             } else {
622                 let b = self.cfg.start_new_block();
623                 scope.cached_generator_drop = Some(b);
624                 self.cfg.goto(block, src_info, b);
625                 b
626             };
627
628             let unwind_to = scopes
629                 .peek()
630                 .as_ref()
631                 .map(|scope| {
632                     scope
633                         .cached_unwind
634                         .get(true)
635                         .unwrap_or_else(|| span_bug!(src_info.span, "cached block not present?"))
636                 })
637                 .unwrap_or(resume_block);
638
639             unpack!(
640                 block = build_scope_drops(
641                     &mut self.cfg,
642                     self.generator_kind,
643                     scope,
644                     block,
645                     unwind_to,
646                     self.arg_count,
647                     true, // is generator
648                     true, // is cached path
649                 )
650             );
651         }
652
653         self.cfg.terminate(block, src_info, TerminatorKind::GeneratorDrop);
654
655         Some(result)
656     }
657
658     /// Creates a new source scope, nested in the current one.
659     crate fn new_source_scope(
660         &mut self,
661         span: Span,
662         lint_level: LintLevel,
663         safety: Option<Safety>,
664     ) -> SourceScope {
665         let parent = self.source_scope;
666         debug!(
667             "new_source_scope({:?}, {:?}, {:?}) - parent({:?})={:?}",
668             span,
669             lint_level,
670             safety,
671             parent,
672             self.source_scopes.get(parent)
673         );
674         let scope_local_data = SourceScopeLocalData {
675             lint_root: if let LintLevel::Explicit(lint_root) = lint_level {
676                 lint_root
677             } else {
678                 self.source_scopes[parent].local_data.as_ref().assert_crate_local().lint_root
679             },
680             safety: safety.unwrap_or_else(|| {
681                 self.source_scopes[parent].local_data.as_ref().assert_crate_local().safety
682             }),
683         };
684         self.source_scopes.push(SourceScopeData {
685             span,
686             parent_scope: Some(parent),
687             local_data: ClearCrossCrate::Set(scope_local_data),
688         })
689     }
690
691     /// Given a span and the current source scope, make a SourceInfo.
692     crate fn source_info(&self, span: Span) -> SourceInfo {
693         SourceInfo { span, scope: self.source_scope }
694     }
695
696     // Finding scopes
697     // ==============
698     /// Returns the scope that we should use as the lifetime of an
699     /// operand. Basically, an operand must live until it is consumed.
700     /// This is similar to, but not quite the same as, the temporary
701     /// scope (which can be larger or smaller).
702     ///
703     /// Consider:
704     ///
705     ///     let x = foo(bar(X, Y));
706     ///
707     /// We wish to pop the storage for X and Y after `bar()` is
708     /// called, not after the whole `let` is completed.
709     ///
710     /// As another example, if the second argument diverges:
711     ///
712     ///     foo(Box::new(2), panic!())
713     ///
714     /// We would allocate the box but then free it on the unwinding
715     /// path; we would also emit a free on the 'success' path from
716     /// panic, but that will turn out to be removed as dead-code.
717     ///
718     /// When building statics/constants, returns `None` since
719     /// intermediate values do not have to be dropped in that case.
720     crate fn local_scope(&self) -> Option<region::Scope> {
721         match self.hir.body_owner_kind {
722             hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) =>
723             // No need to free storage in this context.
724             {
725                 None
726             }
727             hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => Some(self.scopes.topmost()),
728         }
729     }
730
731     // Schedule an abort block - this is used for some ABIs that cannot unwind
732     crate fn schedule_abort(&mut self) -> BasicBlock {
733         let source_info = self.scopes.source_info(self.scopes.len(), self.fn_span);
734         let abortblk = self.cfg.start_new_cleanup_block();
735         self.cfg.terminate(abortblk, source_info, TerminatorKind::Abort);
736         self.cached_resume_block = Some(abortblk);
737         abortblk
738     }
739
740     // Scheduling drops
741     // ================
742     crate fn schedule_drop_storage_and_value(
743         &mut self,
744         span: Span,
745         region_scope: region::Scope,
746         local: Local,
747     ) {
748         self.schedule_drop(span, region_scope, local, DropKind::Storage);
749         self.schedule_drop(span, region_scope, local, DropKind::Value);
750     }
751
752     /// Indicates that `place` should be dropped on exit from
753     /// `region_scope`.
754     ///
755     /// When called with `DropKind::Storage`, `place` should be a local
756     /// with an index higher than the current `self.arg_count`.
757     crate fn schedule_drop(
758         &mut self,
759         span: Span,
760         region_scope: region::Scope,
761         local: Local,
762         drop_kind: DropKind,
763     ) {
764         let needs_drop = match drop_kind {
765             DropKind::Value => {
766                 if !self.hir.needs_drop(self.local_decls[local].ty) {
767                     return;
768                 }
769                 true
770             }
771             DropKind::Storage => {
772                 if local.index() <= self.arg_count {
773                     span_bug!(
774                         span,
775                         "`schedule_drop` called with local {:?} and arg_count {}",
776                         local,
777                         self.arg_count,
778                     )
779                 }
780                 false
781             }
782         };
783
784         for scope in self.scopes.iter_mut() {
785             let this_scope = scope.region_scope == region_scope;
786             // When building drops, we try to cache chains of drops in such a way so these drops
787             // could be reused by the drops which would branch into the cached (already built)
788             // blocks.  This, however, means that whenever we add a drop into a scope which already
789             // had some blocks built (and thus, cached) for it, we must invalidate all caches which
790             // might branch into the scope which had a drop just added to it. This is necessary,
791             // because otherwise some other code might use the cache to branch into already built
792             // chain of drops, essentially ignoring the newly added drop.
793             //
794             // For example consider there’s two scopes with a drop in each. These are built and
795             // thus the caches are filled:
796             //
797             // +--------------------------------------------------------+
798             // | +---------------------------------+                    |
799             // | | +--------+     +-------------+  |  +---------------+ |
800             // | | | return | <-+ | drop(outer) | <-+ |  drop(middle) | |
801             // | | +--------+     +-------------+  |  +---------------+ |
802             // | +------------|outer_scope cache|--+                    |
803             // +------------------------------|middle_scope cache|------+
804             //
805             // Now, a new, inner-most scope is added along with a new drop into both inner-most and
806             // outer-most scopes:
807             //
808             // +------------------------------------------------------------+
809             // | +----------------------------------+                       |
810             // | | +--------+      +-------------+  |   +---------------+   | +-------------+
811             // | | | return | <+   | drop(new)   | <-+  |  drop(middle) | <--+| drop(inner) |
812             // | | +--------+  |   | drop(outer) |  |   +---------------+   | +-------------+
813             // | |             +-+ +-------------+  |                       |
814             // | +---|invalid outer_scope cache|----+                       |
815             // +----=----------------|invalid middle_scope cache|-----------+
816             //
817             // If, when adding `drop(new)` we do not invalidate the cached blocks for both
818             // outer_scope and middle_scope, then, when building drops for the inner (right-most)
819             // scope, the old, cached blocks, without `drop(new)` will get used, producing the
820             // wrong results.
821             //
822             // The cache and its invalidation for unwind branch is somewhat special. The cache is
823             // per-drop, rather than per scope, which has a several different implications. Adding
824             // a new drop into a scope will not invalidate cached blocks of the prior drops in the
825             // scope. That is true, because none of the already existing drops will have an edge
826             // into a block with the newly added drop.
827             //
828             // Note that this code iterates scopes from the inner-most to the outer-most,
829             // invalidating caches of each scope visited. This way bare minimum of the
830             // caches gets invalidated. i.e., if a new drop is added into the middle scope, the
831             // cache of outer scope stays intact.
832             scope.invalidate_cache(!needs_drop, self.generator_kind, this_scope);
833             if this_scope {
834                 let region_scope_span =
835                     region_scope.span(self.hir.tcx(), &self.hir.region_scope_tree);
836                 // Attribute scope exit drops to scope's closing brace.
837                 let scope_end = self.hir.tcx().sess.source_map().end_point(region_scope_span);
838
839                 scope.drops.push(DropData {
840                     span: scope_end,
841                     local,
842                     kind: drop_kind,
843                     cached_block: CachedBlock::default(),
844                 });
845                 return;
846             }
847         }
848         span_bug!(span, "region scope {:?} not in scope to drop {:?}", region_scope, local);
849     }
850
851     /// Indicates that the "local operand" stored in `local` is
852     /// *moved* at some point during execution (see `local_scope` for
853     /// more information about what a "local operand" is -- in short,
854     /// it's an intermediate operand created as part of preparing some
855     /// MIR instruction). We use this information to suppress
856     /// redundant drops on the non-unwind paths. This results in less
857     /// MIR, but also avoids spurious borrow check errors
858     /// (c.f. #64391).
859     ///
860     /// Example: when compiling the call to `foo` here:
861     ///
862     /// ```rust
863     /// foo(bar(), ...)
864     /// ```
865     ///
866     /// we would evaluate `bar()` to an operand `_X`. We would also
867     /// schedule `_X` to be dropped when the expression scope for
868     /// `foo(bar())` is exited. This is relevant, for example, if the
869     /// later arguments should unwind (it would ensure that `_X` gets
870     /// dropped). However, if no unwind occurs, then `_X` will be
871     /// unconditionally consumed by the `call`:
872     ///
873     /// ```
874     /// bb {
875     ///   ...
876     ///   _R = CALL(foo, _X, ...)
877     /// }
878     /// ```
879     ///
880     /// However, `_X` is still registered to be dropped, and so if we
881     /// do nothing else, we would generate a `DROP(_X)` that occurs
882     /// after the call. This will later be optimized out by the
883     /// drop-elaboation code, but in the meantime it can lead to
884     /// spurious borrow-check errors -- the problem, ironically, is
885     /// not the `DROP(_X)` itself, but the (spurious) unwind pathways
886     /// that it creates. See #64391 for an example.
887     crate fn record_operands_moved(&mut self, operands: &[Operand<'tcx>]) {
888         let scope = match self.local_scope() {
889             None => {
890                 // if there is no local scope, operands won't be dropped anyway
891                 return;
892             }
893
894             Some(local_scope) => self
895                 .scopes
896                 .iter_mut()
897                 .find(|scope| scope.region_scope == local_scope)
898                 .unwrap_or_else(|| bug!("scope {:?} not found in scope list!", local_scope)),
899         };
900
901         // look for moves of a local variable, like `MOVE(_X)`
902         let locals_moved = operands.iter().flat_map(|operand| match operand {
903             Operand::Copy(_) | Operand::Constant(_) => None,
904             Operand::Move(place) => place.as_local(),
905         });
906
907         for local in locals_moved {
908             // check if we have a Drop for this operand and -- if so
909             // -- add it to the list of moved operands. Note that this
910             // local might not have been an operand created for this
911             // call, it could come from other places too.
912             if scope.drops.iter().any(|drop| drop.local == local && drop.kind == DropKind::Value) {
913                 scope.moved_locals.push(local);
914             }
915         }
916     }
917
918     // Other
919     // =====
920     /// Branch based on a boolean condition.
921     ///
922     /// This is a special case because the temporary for the condition needs to
923     /// be dropped on both the true and the false arm.
924     crate fn test_bool(
925         &mut self,
926         mut block: BasicBlock,
927         condition: Expr<'tcx>,
928         source_info: SourceInfo,
929     ) -> (BasicBlock, BasicBlock) {
930         let cond = unpack!(block = self.as_local_operand(block, condition));
931         let true_block = self.cfg.start_new_block();
932         let false_block = self.cfg.start_new_block();
933         let term = TerminatorKind::if_(self.hir.tcx(), cond.clone(), true_block, false_block);
934         self.cfg.terminate(block, source_info, term);
935
936         match cond {
937             // Don't try to drop a constant
938             Operand::Constant(_) => (),
939             // If constants and statics, we don't generate StorageLive for this
940             // temporary, so don't try to generate StorageDead for it either.
941             _ if self.local_scope().is_none() => (),
942             Operand::Copy(place) | Operand::Move(place) => {
943                 if let Some(cond_temp) = place.as_local() {
944                     // Manually drop the condition on both branches.
945                     let top_scope = self.scopes.scopes.last_mut().unwrap();
946                     let top_drop_data = top_scope.drops.pop().unwrap();
947
948                     match top_drop_data.kind {
949                         DropKind::Value { .. } => {
950                             bug!("Drop scheduled on top of condition variable")
951                         }
952                         DropKind::Storage => {
953                             let source_info = top_scope.source_info(top_drop_data.span);
954                             let local = top_drop_data.local;
955                             assert_eq!(local, cond_temp, "Drop scheduled on top of condition");
956                             self.cfg.push(
957                                 true_block,
958                                 Statement { source_info, kind: StatementKind::StorageDead(local) },
959                             );
960                             self.cfg.push(
961                                 false_block,
962                                 Statement { source_info, kind: StatementKind::StorageDead(local) },
963                             );
964                         }
965                     }
966
967                     top_scope.invalidate_cache(true, self.generator_kind, true);
968                 } else {
969                     bug!("Expected as_local_operand to produce a temporary");
970                 }
971             }
972         }
973
974         (true_block, false_block)
975     }
976
977     /// Creates a path that performs all required cleanup for unwinding.
978     ///
979     /// This path terminates in Resume. Returns the start of the path.
980     /// See module comment for more details.
981     crate fn diverge_cleanup(&mut self) -> BasicBlock {
982         self.diverge_cleanup_gen(false)
983     }
984
985     fn resume_block(&mut self) -> BasicBlock {
986         if let Some(target) = self.cached_resume_block {
987             target
988         } else {
989             let resumeblk = self.cfg.start_new_cleanup_block();
990             self.cfg.terminate(
991                 resumeblk,
992                 SourceInfo { scope: OUTERMOST_SOURCE_SCOPE, span: self.fn_span },
993                 TerminatorKind::Resume,
994             );
995             self.cached_resume_block = Some(resumeblk);
996             resumeblk
997         }
998     }
999
1000     fn diverge_cleanup_gen(&mut self, generator_drop: bool) -> BasicBlock {
1001         // Build up the drops in **reverse** order. The end result will
1002         // look like:
1003         //
1004         //    scopes[n] -> scopes[n-1] -> ... -> scopes[0]
1005         //
1006         // However, we build this in **reverse order**. That is, we
1007         // process scopes[0], then scopes[1], etc, pointing each one at
1008         // the result generates from the one before. Along the way, we
1009         // store caches. If everything is cached, we'll just walk right
1010         // to left reading the cached results but never created anything.
1011
1012         // Find the last cached block
1013         debug!("diverge_cleanup_gen(self.scopes = {:?})", self.scopes);
1014         let cached_cleanup = self.scopes.iter_mut().enumerate().find_map(|(idx, ref scope)| {
1015             let cached_block = scope.cached_unwind.get(generator_drop)?;
1016             Some((cached_block, idx))
1017         });
1018         let (mut target, first_uncached) =
1019             cached_cleanup.unwrap_or_else(|| (self.resume_block(), self.scopes.len()));
1020
1021         for scope in self.scopes.top_scopes(first_uncached) {
1022             target = build_diverge_scope(
1023                 &mut self.cfg,
1024                 scope.region_scope_span,
1025                 scope,
1026                 target,
1027                 generator_drop,
1028                 self.generator_kind,
1029             );
1030         }
1031
1032         target
1033     }
1034
1035     /// Utility function for *non*-scope code to build their own drops
1036     crate fn build_drop_and_replace(
1037         &mut self,
1038         block: BasicBlock,
1039         span: Span,
1040         location: Place<'tcx>,
1041         value: Operand<'tcx>,
1042     ) -> BlockAnd<()> {
1043         let source_info = self.source_info(span);
1044         let next_target = self.cfg.start_new_block();
1045         let diverge_target = self.diverge_cleanup();
1046         self.cfg.terminate(
1047             block,
1048             source_info,
1049             TerminatorKind::DropAndReplace {
1050                 location,
1051                 value,
1052                 target: next_target,
1053                 unwind: Some(diverge_target),
1054             },
1055         );
1056         next_target.unit()
1057     }
1058
1059     /// Creates an Assert terminator and return the success block.
1060     /// If the boolean condition operand is not the expected value,
1061     /// a runtime panic will be caused with the given message.
1062     crate fn assert(
1063         &mut self,
1064         block: BasicBlock,
1065         cond: Operand<'tcx>,
1066         expected: bool,
1067         msg: AssertMessage<'tcx>,
1068         span: Span,
1069     ) -> BasicBlock {
1070         let source_info = self.source_info(span);
1071
1072         let success_block = self.cfg.start_new_block();
1073         let cleanup = self.diverge_cleanup();
1074
1075         self.cfg.terminate(
1076             block,
1077             source_info,
1078             TerminatorKind::Assert {
1079                 cond,
1080                 expected,
1081                 msg,
1082                 target: success_block,
1083                 cleanup: Some(cleanup),
1084             },
1085         );
1086
1087         success_block
1088     }
1089
1090     // `match` arm scopes
1091     // ==================
1092     /// Unschedules any drops in the top scope.
1093     ///
1094     /// This is only needed for `match` arm scopes, because they have one
1095     /// entrance per pattern, but only one exit.
1096     pub(crate) fn clear_top_scope(&mut self, region_scope: region::Scope) {
1097         let top_scope = self.scopes.scopes.last_mut().unwrap();
1098
1099         assert_eq!(top_scope.region_scope, region_scope);
1100
1101         top_scope.drops.clear();
1102         top_scope.invalidate_cache(false, self.generator_kind, true);
1103     }
1104 }
1105
1106 /// Builds drops for pop_scope and exit_scope.
1107 fn build_scope_drops<'tcx>(
1108     cfg: &mut CFG<'tcx>,
1109     generator_kind: Option<GeneratorKind>,
1110     scope: &Scope,
1111     mut block: BasicBlock,
1112     last_unwind_to: BasicBlock,
1113     arg_count: usize,
1114     generator_drop: bool,
1115     is_cached_path: bool,
1116 ) -> BlockAnd<()> {
1117     debug!("build_scope_drops({:?} -> {:?})", block, scope);
1118
1119     // Build up the drops in evaluation order. The end result will
1120     // look like:
1121     //
1122     // [SDs, drops[n]] --..> [SDs, drop[1]] -> [SDs, drop[0]] -> [[SDs]]
1123     //               |                    |                 |
1124     //               :                    |                 |
1125     //                                    V                 V
1126     // [drop[n]] -...-> [drop[1]] ------> [drop[0]] ------> [last_unwind_to]
1127     //
1128     // The horizontal arrows represent the execution path when the drops return
1129     // successfully. The downwards arrows represent the execution path when the
1130     // drops panic (panicking while unwinding will abort, so there's no need for
1131     // another set of arrows).
1132     //
1133     // For generators, we unwind from a drop on a local to its StorageDead
1134     // statement. For other functions we don't worry about StorageDead. The
1135     // drops for the unwind path should have already been generated by
1136     // `diverge_cleanup_gen`.
1137
1138     for drop_idx in (0..scope.drops.len()).rev() {
1139         let drop_data = &scope.drops[drop_idx];
1140         let source_info = scope.source_info(drop_data.span);
1141         let local = drop_data.local;
1142
1143         match drop_data.kind {
1144             DropKind::Value => {
1145                 // If the operand has been moved, and we are not on an unwind
1146                 // path, then don't generate the drop. (We only take this into
1147                 // account for non-unwind paths so as not to disturb the
1148                 // caching mechanism.)
1149                 if !is_cached_path && scope.moved_locals.iter().any(|&o| o == local) {
1150                     continue;
1151                 }
1152
1153                 let unwind_to = get_unwind_to(scope, generator_kind, drop_idx, generator_drop)
1154                     .unwrap_or(last_unwind_to);
1155
1156                 let next = cfg.start_new_block();
1157                 cfg.terminate(
1158                     block,
1159                     source_info,
1160                     TerminatorKind::Drop {
1161                         location: local.into(),
1162                         target: next,
1163                         unwind: Some(unwind_to),
1164                     },
1165                 );
1166                 block = next;
1167             }
1168             DropKind::Storage => {
1169                 // Only temps and vars need their storage dead.
1170                 assert!(local.index() > arg_count);
1171                 cfg.push(block, Statement { source_info, kind: StatementKind::StorageDead(local) });
1172             }
1173         }
1174     }
1175     block.unit()
1176 }
1177
1178 fn get_unwind_to(
1179     scope: &Scope,
1180     generator_kind: Option<GeneratorKind>,
1181     unwind_from: usize,
1182     generator_drop: bool,
1183 ) -> Option<BasicBlock> {
1184     for drop_idx in (0..unwind_from).rev() {
1185         let drop_data = &scope.drops[drop_idx];
1186         match (generator_kind, &drop_data.kind) {
1187             (Some(_), DropKind::Storage) => {
1188                 return Some(drop_data.cached_block.get(generator_drop).unwrap_or_else(|| {
1189                     span_bug!(drop_data.span, "cached block not present for {:?}", drop_data)
1190                 }));
1191             }
1192             (None, DropKind::Value) => {
1193                 return Some(drop_data.cached_block.get(generator_drop).unwrap_or_else(|| {
1194                     span_bug!(drop_data.span, "cached block not present for {:?}", drop_data)
1195                 }));
1196             }
1197             _ => (),
1198         }
1199     }
1200     None
1201 }
1202
1203 fn build_diverge_scope<'tcx>(
1204     cfg: &mut CFG<'tcx>,
1205     span: Span,
1206     scope: &mut Scope,
1207     mut target: BasicBlock,
1208     generator_drop: bool,
1209     generator_kind: Option<GeneratorKind>,
1210 ) -> BasicBlock {
1211     // Build up the drops in **reverse** order. The end result will
1212     // look like:
1213     //
1214     //    [drops[n]] -...-> [drops[0]] -> [target]
1215     //
1216     // The code in this function reads from right to left. At each
1217     // point, we check for cached blocks representing the
1218     // remainder. If everything is cached, we'll just walk right to
1219     // left reading the cached results but never create anything.
1220
1221     let source_scope = scope.source_scope;
1222     let source_info = |span| SourceInfo { span, scope: source_scope };
1223
1224     // We keep track of StorageDead statements to prepend to our current block
1225     // and store them here, in reverse order.
1226     let mut storage_deads = vec![];
1227
1228     let mut target_built_by_us = false;
1229
1230     // Build up the drops. Here we iterate the vector in
1231     // *forward* order, so that we generate drops[0] first (right to
1232     // left in diagram above).
1233     debug!("build_diverge_scope({:?})", scope.drops);
1234     for (j, drop_data) in scope.drops.iter_mut().enumerate() {
1235         debug!("build_diverge_scope drop_data[{}]: {:?}", j, drop_data);
1236         // Only full value drops are emitted in the diverging path,
1237         // not StorageDead, except in the case of generators.
1238         //
1239         // Note: This may not actually be what we desire (are we
1240         // "freeing" stack storage as we unwind, or merely observing a
1241         // frozen stack)? In particular, the intent may have been to
1242         // match the behavior of clang, but on inspection eddyb says
1243         // this is not what clang does.
1244         match drop_data.kind {
1245             DropKind::Storage if generator_kind.is_some() => {
1246                 storage_deads.push(Statement {
1247                     source_info: source_info(drop_data.span),
1248                     kind: StatementKind::StorageDead(drop_data.local),
1249                 });
1250                 if !target_built_by_us {
1251                     // We cannot add statements to an existing block, so we create a new
1252                     // block for our StorageDead statements.
1253                     let block = cfg.start_new_cleanup_block();
1254                     let source_info = SourceInfo { span: DUMMY_SP, scope: source_scope };
1255                     cfg.goto(block, source_info, target);
1256                     target = block;
1257                     target_built_by_us = true;
1258                 }
1259                 *drop_data.cached_block.ref_mut(generator_drop) = Some(target);
1260             }
1261             DropKind::Storage => {}
1262             DropKind::Value => {
1263                 let cached_block = drop_data.cached_block.ref_mut(generator_drop);
1264                 target = if let Some(cached_block) = *cached_block {
1265                     storage_deads.clear();
1266                     target_built_by_us = false;
1267                     cached_block
1268                 } else {
1269                     push_storage_deads(cfg, target, &mut storage_deads);
1270                     let block = cfg.start_new_cleanup_block();
1271                     cfg.terminate(
1272                         block,
1273                         source_info(drop_data.span),
1274                         TerminatorKind::Drop {
1275                             location: drop_data.local.into(),
1276                             target,
1277                             unwind: None,
1278                         },
1279                     );
1280                     *cached_block = Some(block);
1281                     target_built_by_us = true;
1282                     block
1283                 };
1284             }
1285         };
1286     }
1287     push_storage_deads(cfg, target, &mut storage_deads);
1288     *scope.cached_unwind.ref_mut(generator_drop) = Some(target);
1289
1290     assert!(storage_deads.is_empty());
1291     debug!("build_diverge_scope({:?}, {:?}) = {:?}", scope, span, target);
1292
1293     target
1294 }
1295
1296 fn push_storage_deads<'tcx>(
1297     cfg: &mut CFG<'tcx>,
1298     target: BasicBlock,
1299     storage_deads: &mut Vec<Statement<'tcx>>,
1300 ) {
1301     if storage_deads.is_empty() {
1302         return;
1303     }
1304     let statements = &mut cfg.block_data_mut(target).statements;
1305     storage_deads.reverse();
1306     debug!(
1307         "push_storage_deads({:?}), storage_deads={:?}, statements={:?}",
1308         target, storage_deads, statements
1309     );
1310     storage_deads.append(statements);
1311     mem::swap(statements, storage_deads);
1312     assert!(storage_deads.is_empty());
1313 }