]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #46393 - kennytm:45861-step-2-3-make-tools-job-not-fail-fast, r=alexcri...
authorbors <bors@rust-lang.org>
Sun, 3 Dec 2017 18:01:29 +0000 (18:01 +0000)
committerbors <bors@rust-lang.org>
Sun, 3 Dec 2017 18:01:29 +0000 (18:01 +0000)
[auto-toolstate][2+3/8] Move external tools tests into its own job with --no-fail-fast

This PR performs these  things:

1. The `aux` job now performs "cargotest" and "pretty" tests. The clippy/rustfmt/rls/miri tests are moved into its own job.
2. These tests are run with `--no-fail-fast`, so that we can get the maximum number of failures of all tools from a single CI run.
3. The test results are stored into a JSON file, ready to be uploaded in the future.

This is step 2 and 3/8 of automatic management of broken tools #45861.

41 files changed:
src/librustc/mir/mod.rs
src/librustc_mir/borrow_check.rs
src/librustc_mir/build/expr/into.rs
src/librustc_mir/build/matches/test.rs
src/librustc_mir/build/scope.rs
src/librustc_mir/dataflow/drop_flag_effects.rs
src/librustc_mir/dataflow/impls/borrows.rs
src/librustc_mir/shim.rs
src/librustc_mir/transform/elaborate_drops.rs
src/librustc_mir/transform/mod.rs
src/librustc_mir/transform/no_landing_pads.rs
src/librustc_mir/transform/remove_noop_landing_pads.rs [new file with mode: 0644]
src/librustc_mir/transform/simplify.rs
src/librustc_mir/util/elaborate_drops.rs
src/librustdoc/html/static/main.js
src/test/compile-fail/borrowck/borrowck-local-borrow-with-panic-outlives-fn.rs [new file with mode: 0644]
src/test/mir-opt/basic_assignment.rs
src/test/mir-opt/box_expr.rs
src/test/mir-opt/end_region_4.rs
src/test/mir-opt/end_region_5.rs
src/test/mir-opt/end_region_6.rs
src/test/mir-opt/end_region_7.rs
src/test/mir-opt/end_region_8.rs
src/test/mir-opt/end_region_cyclic.rs
src/test/mir-opt/end_region_destruction_extents_1.rs
src/test/mir-opt/match_false_edges.rs
src/test/mir-opt/nll/liveness-call-subtlety.rs
src/test/mir-opt/nll/liveness-drop-intra-block.rs
src/test/mir-opt/nll/liveness-interblock.rs
src/test/mir-opt/nll/region-liveness-basic.rs
src/test/mir-opt/nll/region-liveness-drop-may-dangle.rs
src/test/mir-opt/nll/region-liveness-drop-no-may-dangle.rs
src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs
src/test/mir-opt/nll/region-subtyping-basic.rs
src/test/mir-opt/packed-struct-drop-aligned.rs
src/test/mir-opt/simplify_if.rs
src/test/mir-opt/validate_2.rs
src/test/mir-opt/validate_4.rs
src/test/run-pass/dynamic-drop.rs
src/test/run-pass/issue-8860.rs
src/test/run-pass/weird-exprs.rs

index 0cbd945095a959fbabd7da8d403ce532f71d7939..cd4ed8081c3bda662c6dd59567ab205e0a820fcf 100644 (file)
@@ -733,6 +733,10 @@ pub fn successors(&self) -> Cow<[BasicBlock]> {
     pub fn successors_mut(&mut self) -> Vec<&mut BasicBlock> {
         self.kind.successors_mut()
     }
+
+    pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> {
+        self.kind.unwind_mut()
+    }
 }
 
 impl<'tcx> TerminatorKind<'tcx> {
@@ -811,6 +815,27 @@ pub fn successors_mut(&mut self) -> Vec<&mut BasicBlock> {
             }
         }
     }
+
+    pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> {
+        match *self {
+            TerminatorKind::Goto { .. } |
+            TerminatorKind::Resume |
+            TerminatorKind::Return |
+            TerminatorKind::Unreachable |
+            TerminatorKind::GeneratorDrop |
+            TerminatorKind::Yield { .. } |
+            TerminatorKind::SwitchInt { .. } |
+            TerminatorKind::FalseEdges { .. } => {
+                None
+            },
+            TerminatorKind::Call { cleanup: ref mut unwind, .. } |
+            TerminatorKind::Assert { cleanup: ref mut unwind, .. } |
+            TerminatorKind::DropAndReplace { ref mut unwind, .. } |
+            TerminatorKind::Drop { ref mut unwind, .. } => {
+                Some(unwind)
+            }
+        }
+    }
 }
 
 impl<'tcx> BasicBlockData<'tcx> {
index 63b4175ce449f8278b1be4849665063e610939d7..ee48d1d369d53e8aba1edec3dcd8f1d16d7d9dbc 100644 (file)
@@ -384,33 +384,23 @@ fn visit_terminator_entry(&mut self,
                 // StorageDead, but we don't always emit those (notably on unwind paths),
                 // so this "extra check" serves as a kind of backup.
                 let domain = flow_state.borrows.base_results.operator();
-                for borrow in domain.borrows() {
-                    let root_place = self.prefixes(
-                        &borrow.place,
-                        PrefixSet::All
-                    ).last().unwrap();
-                    match root_place {
-                        Place::Static(_) => {
-                            self.access_place(
-                                ContextKind::StorageDead.new(loc),
-                                (&root_place, self.mir.source_info(borrow.location).span),
-                                (Deep, Write(WriteKind::StorageDeadOrDrop)),
-                                LocalMutationIsAllowed::Yes,
-                                flow_state
-                            );
-                        }
-                        Place::Local(_) => {
-                            self.access_place(
-                                ContextKind::StorageDead.new(loc),
-                                (&root_place, self.mir.source_info(borrow.location).span),
-                                (Shallow(None), Write(WriteKind::StorageDeadOrDrop)),
-                                LocalMutationIsAllowed::Yes,
-                                flow_state
-                            );
-                        }
-                        Place::Projection(_) => ()
+                let data = domain.borrows();
+                flow_state.borrows.with_elems_outgoing(|borrows| for i in borrows {
+                    let borrow = &data[i];
+
+                    if self.place_is_invalidated_at_exit(&borrow.place) {
+                        debug!("borrow conflicts at exit {:?}", borrow);
+                        let borrow_span = self.mir.source_info(borrow.location).span;
+                        // FIXME: should be talking about the region lifetime instead
+                        // of just a span here.
+                        let end_span = domain.opt_region_end_span(&borrow.region);
+
+                        self.report_borrowed_value_does_not_live_long_enough(
+                            ContextKind::StorageDead.new(loc),
+                            (&borrow.place, borrow_span),
+                            end_span)
                     }
-                }
+                });
             }
             TerminatorKind::Goto { target: _ } |
             TerminatorKind::Unreachable |
@@ -594,7 +584,7 @@ fn access_place(&mut self,
                                     context, common_prefix, place_span, bk,
                                     &borrow, end_issued_loan_span)
                             }
-                             WriteKind::StorageDeadOrDrop => {
+                            WriteKind::StorageDeadOrDrop => {
                                 let end_span =
                                     flow_state.borrows.base_results.operator().opt_region_end_span(
                                         &borrow.region);
@@ -751,6 +741,50 @@ fn consume_operand(&mut self,
             Operand::Constant(_) => {}
         }
     }
+
+    /// Returns whether a borrow of this place is invalidated when the function
+    /// exits
+    fn place_is_invalidated_at_exit(&self, place: &Place<'tcx>) -> bool {
+        debug!("place_is_invalidated_at_exit({:?})", place);
+        let root_place = self.prefixes(place, PrefixSet::All).last().unwrap();
+
+        // FIXME(nll-rfc#40): do more precise destructor tracking here. For now
+        // we just know that all locals are dropped at function exit (otherwise
+        // we'll have a memory leak) and assume that all statics have a destructor.
+        let (might_be_alive, will_be_dropped) = match root_place {
+            Place::Static(statik) => {
+                // Thread-locals might be dropped after the function exits, but
+                // "true" statics will never be.
+                let is_thread_local = self.tcx.get_attrs(statik.def_id).iter().any(|attr| {
+                    attr.check_name("thread_local")
+                });
+
+                (true, is_thread_local)
+            }
+            Place::Local(_) => {
+                // Locals are always dropped at function exit, and if they
+                // have a destructor it would've been called already.
+                (false, true)
+            }
+            Place::Projection(..) => bug!("root of {:?} is a projection ({:?})?",
+                                           place, root_place)
+        };
+
+        if !will_be_dropped {
+            debug!("place_is_invalidated_at_exit({:?}) - won't be dropped", place);
+            return false;
+        }
+
+        // FIXME: replace this with a proper borrow_conflicts_with_place when
+        // that is merged.
+        let prefix_set = if might_be_alive {
+            PrefixSet::Supporting
+        } else {
+            PrefixSet::Shallow
+        };
+
+        self.prefixes(place, prefix_set).any(|prefix| prefix == root_place)
+    }
 }
 
 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
@@ -1667,13 +1701,13 @@ fn report_conflicting_borrow(&mut self,
 
     fn report_borrowed_value_does_not_live_long_enough(&mut self,
                                                        _: Context,
-                                                       (place, span): (&Place, Span),
+                                                       (place, span): (&Place<'tcx>, Span),
                                                        end_span: Option<Span>) {
-        let proper_span = match *place {
+        let root_place = self.prefixes(place, PrefixSet::All).last().unwrap();
+        let proper_span = match *root_place {
             Place::Local(local) => self.mir.local_decls[local].source_info.span,
             _ => span
         };
-
         let mut err = self.tcx.path_does_not_live_long_enough(span, "borrowed value", Origin::Mir);
         err.span_label(proper_span, "temporary value created here");
         err.span_label(span, "temporary value dropped here while still borrowed");
@@ -2162,4 +2196,12 @@ fn elems_incoming(&self) -> indexed_set::Elems<BD::Idx> {
         let univ = self.base_results.sets().bits_per_block();
         self.curr_state.elems(univ)
     }
+
+    fn with_elems_outgoing<F>(&self, f: F) where F: FnOnce(indexed_set::Elems<BD::Idx>) {
+        let mut curr_state = self.curr_state.clone();
+        curr_state.union(&self.stmt_gen);
+        curr_state.subtract(&self.stmt_kill);
+        let univ = self.base_results.sets().bits_per_block();
+        f(curr_state.elems(univ));
+    }
 }
index 0cdac04b810514289841e8973520ae2f47a8a8fc..ed339110537f6a017528c3a5ee83f5654354b678 100644 (file)
@@ -255,7 +255,7 @@ pub fn into_expr(&mut self,
                     this.cfg.terminate(block, source_info, TerminatorKind::Call {
                         func: fun,
                         args,
-                        cleanup,
+                        cleanup: Some(cleanup),
                         destination: if diverges {
                             None
                         } else {
@@ -273,7 +273,9 @@ pub fn into_expr(&mut self,
             ExprKind::Break { .. } |
             ExprKind::InlineAsm { .. } |
             ExprKind::Return {.. } => {
-                this.stmt_expr(block, expr)
+                unpack!(block = this.stmt_expr(block, expr));
+                this.cfg.push_assign_unit(block, source_info, destination);
+                block.unit()
             }
 
             // these are the cases that are more naturally handled by some other mode
index 7c9f190670ba8bcc97445ba8e1ba2fdff54516bc..b2357b771572fa6a1896b97612fa0e8fe0f22d6f 100644 (file)
@@ -315,7 +315,7 @@ pub fn perform_test(&mut self,
                         }),
                         args: vec![val, expect],
                         destination: Some((eq_result.clone(), eq_block)),
-                        cleanup,
+                        cleanup: Some(cleanup),
                     });
 
                     // check the result
index 3814dde17bb679339c44f18970b2a14ead563eaa..630d0bf179294d2e1db7e09e332086cecaf43e58 100644 (file)
@@ -383,7 +383,9 @@ pub fn pop_scope(&mut self,
         assert_eq!(scope.region_scope, region_scope.0);
 
         self.cfg.push_end_region(self.hir.tcx(), block, region_scope.1, scope.region_scope);
+        let resume_block = self.resume_block();
         unpack!(block = build_scope_drops(&mut self.cfg,
+                                          resume_block,
                                           &scope,
                                           &self.scopes,
                                           block,
@@ -422,6 +424,7 @@ pub fn exit_scope(&mut self,
         }
 
         {
+        let resume_block = self.resume_block();
         let mut rest = &mut self.scopes[(len - scope_count)..];
         while let Some((scope, rest_)) = {rest}.split_last_mut() {
             rest = rest_;
@@ -441,6 +444,7 @@ pub fn exit_scope(&mut self,
             self.cfg.push_end_region(self.hir.tcx(), block, region_scope.1, scope.region_scope);
 
             unpack!(block = build_scope_drops(&mut self.cfg,
+                                              resume_block,
                                               scope,
                                               rest,
                                               block,
@@ -468,6 +472,7 @@ pub fn generator_drop_cleanup(&mut self) -> Option<BasicBlock> {
         let src_info = self.scopes[0].source_info(self.fn_span);
         let mut block = self.cfg.start_new_block();
         let result = block;
+        let resume_block = self.resume_block();
         let mut rest = &mut self.scopes[..];
 
         while let Some((scope, rest_)) = {rest}.split_last_mut() {
@@ -491,6 +496,7 @@ pub fn generator_drop_cleanup(&mut self) -> Option<BasicBlock> {
             self.cfg.push_end_region(self.hir.tcx(), block, src_info, scope.region_scope);
 
             unpack!(block = build_scope_drops(&mut self.cfg,
+                                              resume_block,
                                               scope,
                                               rest,
                                               block,
@@ -701,18 +707,31 @@ pub fn schedule_drop(&mut self,
     /// This path terminates in Resume. Returns the start of the path.
     /// See module comment for more details. None indicates there’s no
     /// cleanup to do at this point.
-    pub fn diverge_cleanup(&mut self) -> Option<BasicBlock> {
+    pub fn diverge_cleanup(&mut self) -> BasicBlock {
         self.diverge_cleanup_gen(false)
     }
 
-    fn diverge_cleanup_gen(&mut self, generator_drop: bool) -> Option<BasicBlock> {
-        if !self.scopes.iter().any(|scope| scope.needs_cleanup) {
-            return None;
+    fn resume_block(&mut self) -> BasicBlock {
+        if let Some(target) = self.cached_resume_block {
+            target
+        } else {
+            let resumeblk = self.cfg.start_new_cleanup_block();
+            self.cfg.terminate(resumeblk,
+                               SourceInfo {
+                                   scope: ARGUMENT_VISIBILITY_SCOPE,
+                                   span: self.fn_span
+                               },
+                               TerminatorKind::Resume);
+            self.cached_resume_block = Some(resumeblk);
+            resumeblk
         }
-        assert!(!self.scopes.is_empty()); // or `any` above would be false
+    }
+
+    fn diverge_cleanup_gen(&mut self, generator_drop: bool) -> BasicBlock {
+        // To start, create the resume terminator.
+        let mut target = self.resume_block();
 
-        let Builder { ref mut cfg, ref mut scopes,
-                      ref mut cached_resume_block, .. } = *self;
+        let Builder { ref mut cfg, ref mut scopes, .. } = *self;
 
         // Build up the drops in **reverse** order. The end result will
         // look like:
@@ -725,23 +744,14 @@ fn diverge_cleanup_gen(&mut self, generator_drop: bool) -> Option<BasicBlock> {
         // store caches. If everything is cached, we'll just walk right
         // to left reading the cached results but never created anything.
 
-        // To start, create the resume terminator.
-        let mut target = if let Some(target) = *cached_resume_block {
-            target
-        } else {
-            let resumeblk = cfg.start_new_cleanup_block();
-            cfg.terminate(resumeblk,
-                          scopes[0].source_info(self.fn_span),
-                          TerminatorKind::Resume);
-            *cached_resume_block = Some(resumeblk);
-            resumeblk
-        };
-
-        for scope in scopes.iter_mut() {
-            target = build_diverge_scope(self.hir.tcx(), cfg, scope.region_scope_span,
-                                         scope, target, generator_drop);
+        if scopes.iter().any(|scope| scope.needs_cleanup) {
+            for scope in scopes.iter_mut() {
+                target = build_diverge_scope(self.hir.tcx(), cfg, scope.region_scope_span,
+                                             scope, target, generator_drop);
+            }
         }
-        Some(target)
+
+        target
     }
 
     /// Utility function for *non*-scope code to build their own drops
@@ -760,7 +770,7 @@ pub fn build_drop(&mut self,
                            TerminatorKind::Drop {
                                location,
                                target: next_target,
-                               unwind: diverge_target,
+                               unwind: Some(diverge_target),
                            });
         next_target.unit()
     }
@@ -779,7 +789,7 @@ pub fn build_drop_and_replace(&mut self,
                                location,
                                value,
                                target: next_target,
-                               unwind: diverge_target,
+                               unwind: Some(diverge_target),
                            });
         next_target.unit()
     }
@@ -804,7 +814,7 @@ pub fn assert(&mut self, block: BasicBlock,
                                expected,
                                msg,
                                target: success_block,
-                               cleanup,
+                               cleanup: Some(cleanup),
                            });
 
         success_block
@@ -813,6 +823,7 @@ pub fn assert(&mut self, block: BasicBlock,
 
 /// Builds drops for pop_scope and exit_scope.
 fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
+                           resume_block: BasicBlock,
                            scope: &Scope<'tcx>,
                            earlier_scopes: &[Scope<'tcx>],
                            mut block: BasicBlock,
@@ -868,7 +879,7 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
                 cfg.terminate(block, source_info, TerminatorKind::Drop {
                     location: drop_data.location.clone(),
                     target: next,
-                    unwind: on_diverge
+                    unwind: Some(on_diverge.unwrap_or(resume_block))
                 });
                 block = next;
             }
index f0ecaea15649c71e4eeae8016fe8e522999e5d7d..1cbe0dcc017f9150361c68e56da0c158766f4cf7 100644 (file)
@@ -61,7 +61,12 @@ fn place_contents_drop_state_cannot_differ<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx,
                                                             place: &mir::Place<'tcx>) -> bool {
     let ty = place.ty(mir, tcx).to_ty(tcx);
     match ty.sty {
-        ty::TyArray(..) | ty::TySlice(..) | ty::TyRef(..) | ty::TyRawPtr(..) => {
+        ty::TyArray(..) => {
+            debug!("place_contents_drop_state_cannot_differ place: {:?} ty: {:?} => false",
+                   place, ty);
+            false
+        }
+        ty::TySlice(..) | ty::TyRef(..) | ty::TyRawPtr(..) => {
             debug!("place_contents_drop_state_cannot_differ place: {:?} ty: {:?} refd => true",
                    place, ty);
             true
index 32dcf28cd948376a86de0242cbe1fa139026072e..19ab45dda95453a3000ffde578f369f647a05e77 100644 (file)
@@ -132,6 +132,10 @@ pub fn location(&self, idx: BorrowIndex) -> &Location {
         &self.borrows[idx].location
     }
 
+    pub fn nonlexical_regioncx(&self) -> Option<&'a RegionInferenceContext<'tcx>> {
+        self.nonlexical_regioncx
+    }
+
     /// Returns the span for the "end point" given region. This will
     /// return `None` if NLL is enabled, since that concept has no
     /// meaning there.  Otherwise, return region span if it exists and
@@ -208,6 +212,12 @@ fn statement_effect(&self,
             mir::StatementKind::Assign(_, ref rhs) => {
                 if let mir::Rvalue::Ref(region, _, ref place) = *rhs {
                     if is_unsafe_place(self.tcx, self.mir, place) { return; }
+                    if let RegionKind::ReEmpty = region {
+                        // If the borrowed value is dead, the region for it
+                        // can be empty. Don't track the borrow in that case.
+                        return
+                    }
+
                     let index = self.location_map.get(&location).unwrap_or_else(|| {
                         panic!("could not find BorrowIndex for location {:?}", location);
                     });
index ad228e24e6b13a249c20f5e3980579b4b32a0e0b..9ca044b764806f6a3a2e952e73d13bad28e38798 100644 (file)
@@ -280,6 +280,9 @@ fn deref_subpath(&self, _path: Self::Path) -> Option<Self::Path> {
     fn downcast_subpath(&self, _path: Self::Path, _variant: usize) -> Option<Self::Path> {
         Some(())
     }
+    fn array_subpath(&self, _path: Self::Path, _index: u32, _size: u32) -> Option<Self::Path> {
+        None
+    }
 }
 
 /// Build a `Clone::clone` shim for `self_ty`. Here, `def_id` is `Clone::clone`.
index cb79fc8d7eb27e360337c5b51ba39fa62a92c9ee..b075d2637da9ba53ac1d15a4e1625a90134e46d2 100644 (file)
@@ -257,6 +257,20 @@ fn field_subpath(&self, path: Self::Path, field: Field) -> Option<Self::Path> {
         })
     }
 
+    fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option<Self::Path> {
+        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
+            match p {
+                &Projection {
+                    elem: ProjectionElem::ConstantIndex{offset, min_length: _, from_end: false}, ..
+                } => offset == index,
+                &Projection {
+                    elem: ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true}, ..
+                } => size - offset == index,
+                _ => false
+            }
+        })
+    }
+
     fn deref_subpath(&self, path: Self::Path) -> Option<Self::Path> {
         dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
             match p {
index 418d3d220581e1db447f816c9625d7185bb6352f..830838c60375898d32ee913936a92465c276db74 100644 (file)
@@ -36,6 +36,7 @@
 pub mod add_call_guards;
 pub mod promote_consts;
 pub mod qualify_consts;
+pub mod remove_noop_landing_pads;
 pub mod dump_mir;
 pub mod deaggregator;
 pub mod instcombine;
@@ -226,8 +227,11 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx
 
     let mut mir = tcx.mir_validated(def_id).steal();
     run_passes![tcx, mir, def_id, 2;
+        // Remove all things not needed by analysis
         no_landing_pads::NoLandingPads,
         simplify_branches::SimplifyBranches::new("initial"),
+        remove_noop_landing_pads::RemoveNoopLandingPads,
+        simplify::SimplifyCfg::new("early-opt"),
 
         // These next passes must be executed together
         add_call_guards::CriticalCallEdges,
@@ -255,6 +259,8 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx
         instcombine::InstCombine,
         deaggregator::Deaggregator,
         copy_prop::CopyPropagation,
+        remove_noop_landing_pads::RemoveNoopLandingPads,
+        simplify::SimplifyCfg::new("final"),
         simplify::SimplifyLocals,
 
         generator::StateTransform,
index dd5898cb561b59466613dbfaed23d9762a6bac60..c8f171d4160c61cd20280f7811584d8cd23a7ca0 100644 (file)
@@ -38,23 +38,8 @@ fn visit_terminator(&mut self,
                         bb: BasicBlock,
                         terminator: &mut Terminator<'tcx>,
                         location: Location) {
-        match terminator.kind {
-            TerminatorKind::Goto { .. } |
-            TerminatorKind::Resume |
-            TerminatorKind::Return |
-            TerminatorKind::Unreachable |
-            TerminatorKind::GeneratorDrop |
-            TerminatorKind::Yield { .. } |
-            TerminatorKind::SwitchInt { .. } |
-            TerminatorKind::FalseEdges { .. } => {
-                /* nothing to do */
-            },
-            TerminatorKind::Call { cleanup: ref mut unwind, .. } |
-            TerminatorKind::Assert { cleanup: ref mut unwind, .. } |
-            TerminatorKind::DropAndReplace { ref mut unwind, .. } |
-            TerminatorKind::Drop { ref mut unwind, .. } => {
-                unwind.take();
-            },
+        if let Some(unwind) = terminator.kind.unwind_mut() {
+            unwind.take();
         }
         self.super_terminator(bb, terminator, location);
     }
diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs
new file mode 100644 (file)
index 0000000..d29174d
--- /dev/null
@@ -0,0 +1,137 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::ty::TyCtxt;
+use rustc::mir::*;
+use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::indexed_vec::Idx;
+use transform::{MirPass, MirSource};
+use util::patch::MirPatch;
+
+/// A pass that removes no-op landing pads and replaces jumps to them with
+/// `None`. This is important because otherwise LLVM generates terrible
+/// code for these.
+pub struct RemoveNoopLandingPads;
+
+impl MirPass for RemoveNoopLandingPads {
+    fn run_pass<'a, 'tcx>(&self,
+                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                          _src: MirSource,
+                          mir: &mut Mir<'tcx>) {
+        if tcx.sess.no_landing_pads() {
+            return
+        }
+
+        debug!("remove_noop_landing_pads({:?})", mir);
+        self.remove_nop_landing_pads(mir);
+    }
+}
+
+impl RemoveNoopLandingPads {
+    fn is_nop_landing_pad(&self, bb: BasicBlock, mir: &Mir, nop_landing_pads: &BitVector)
+                          -> bool
+    {
+        for stmt in &mir[bb].statements {
+            match stmt.kind {
+                StatementKind::StorageLive(_) |
+                StatementKind::StorageDead(_) |
+                StatementKind::EndRegion(_) |
+                StatementKind::Nop => {
+                    // These are all nops in a landing pad (there's some
+                    // borrowck interaction between EndRegion and storage
+                    // instructions, but this should all run after borrowck).
+                }
+
+                StatementKind::Assign(Place::Local(_), Rvalue::Use(_)) => {
+                    // Writing to a local (e.g. a drop flag) does not
+                    // turn a landing pad to a non-nop
+                }
+
+                StatementKind::Assign(_, _) |
+                StatementKind::SetDiscriminant { .. } |
+                StatementKind::InlineAsm { .. } |
+                StatementKind::Validate { .. } => {
+                    return false;
+                }
+            }
+        }
+
+        let terminator = mir[bb].terminator();
+        match terminator.kind {
+            TerminatorKind::Goto { .. } |
+            TerminatorKind::Resume |
+            TerminatorKind::SwitchInt { .. } |
+            TerminatorKind::FalseEdges { .. } => {
+                terminator.successors().iter().all(|succ| {
+                    nop_landing_pads.contains(succ.index())
+                })
+            },
+            TerminatorKind::GeneratorDrop |
+            TerminatorKind::Yield { .. } |
+            TerminatorKind::Return |
+            TerminatorKind::Unreachable |
+            TerminatorKind::Call { .. } |
+            TerminatorKind::Assert { .. } |
+            TerminatorKind::DropAndReplace { .. } |
+            TerminatorKind::Drop { .. } => {
+                false
+            }
+        }
+    }
+
+    fn remove_nop_landing_pads(&self, mir: &mut Mir) {
+        // make sure there's a single resume block
+        let resume_block = {
+            let patch = MirPatch::new(mir);
+            let resume_block = patch.resume_block();
+            patch.apply(mir);
+            resume_block
+        };
+        debug!("remove_noop_landing_pads: resume block is {:?}", resume_block);
+
+        let mut jumps_folded = 0;
+        let mut landing_pads_removed = 0;
+        let mut nop_landing_pads = BitVector::new(mir.basic_blocks().len());
+
+        // This is a post-order traversal, so that if A post-dominates B
+        // then A will be visited before B.
+        let postorder: Vec<_> = traversal::postorder(mir).map(|(bb, _)| bb).collect();
+        for bb in postorder {
+            debug!("  processing {:?}", bb);
+            for target in mir[bb].terminator_mut().successors_mut() {
+                if *target != resume_block && nop_landing_pads.contains(target.index()) {
+                    debug!("    folding noop jump to {:?} to resume block", target);
+                    *target = resume_block;
+                    jumps_folded += 1;
+                }
+            }
+
+            match mir[bb].terminator_mut().unwind_mut() {
+                Some(unwind) => {
+                    if *unwind == Some(resume_block) {
+                        debug!("    removing noop landing pad");
+                        jumps_folded -= 1;
+                        landing_pads_removed += 1;
+                        *unwind = None;
+                    }
+                }
+                _ => {}
+            }
+
+            let is_nop_landing_pad = self.is_nop_landing_pad(bb, mir, &nop_landing_pads);
+            if is_nop_landing_pad {
+                nop_landing_pads.insert(bb.index());
+            }
+            debug!("    is_nop_landing_pad({:?}) = {}", bb, is_nop_landing_pad);
+        }
+
+        debug!("removed {:?} jumps and {:?} landing pads", jumps_folded, landing_pads_removed);
+    }
+}
index 2e7c3714ffe12d62ebec06ea93c2d7faf8d9301b..e7675b4ceaf29fea911aeb57fe07de48dc26ae13 100644 (file)
@@ -124,8 +124,6 @@ pub fn simplify(mut self) {
                     self.collapse_goto_chain(successor, &mut changed);
                 }
 
-                changed |= self.simplify_unwind(&mut terminator);
-
                 let mut new_stmts = vec![];
                 let mut inner_changed = true;
                 while inner_changed {
@@ -238,38 +236,6 @@ fn simplify_branch(&mut self, terminator: &mut Terminator<'tcx>) -> bool {
         true
     }
 
-    // turn an unwind branch to a resume block into a None
-    fn simplify_unwind(&mut self, terminator: &mut Terminator<'tcx>) -> bool {
-        let unwind = match terminator.kind {
-            TerminatorKind::Drop { ref mut unwind, .. } |
-            TerminatorKind::DropAndReplace { ref mut unwind, .. } |
-            TerminatorKind::Call { cleanup: ref mut unwind, .. } |
-            TerminatorKind::Assert { cleanup: ref mut unwind, .. } =>
-                unwind,
-            _ => return false
-        };
-
-        if let &mut Some(unwind_block) = unwind {
-            let is_resume_block = match self.basic_blocks[unwind_block] {
-                BasicBlockData {
-                    ref statements,
-                    terminator: Some(Terminator {
-                        kind: TerminatorKind::Resume, ..
-                    }), ..
-                } if statements.is_empty() => true,
-                _ => false
-            };
-            if is_resume_block {
-                debug!("simplifying unwind to {:?} from {:?}",
-                       unwind_block, terminator.source_info);
-                *unwind = None;
-            }
-            return is_resume_block;
-        }
-
-        false
-    }
-
     fn strip_nops(&mut self) {
         for blk in self.basic_blocks.iter_mut() {
             blk.statements.retain(|stmt| if let StatementKind::Nop = stmt.kind {
index e7d1e5a9ccc74c1834e7e8e1352ed231f9a50f07..3331bc9e59e0b44078909998f9a18a2ff5ec8aeb 100644 (file)
@@ -19,7 +19,7 @@
 use rustc_data_structures::indexed_vec::Idx;
 use util::patch::MirPatch;
 
-use std::iter;
+use std::{iter, u32};
 
 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
 pub enum DropFlagState {
@@ -95,6 +95,7 @@ pub trait DropElaborator<'a, 'tcx: 'a> : fmt::Debug {
     fn field_subpath(&self, path: Self::Path, field: Field) -> Option<Self::Path>;
     fn deref_subpath(&self, path: Self::Path) -> Option<Self::Path>;
     fn downcast_subpath(&self, path: Self::Path, variant: usize) -> Option<Self::Path>;
+    fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option<Self::Path>;
 }
 
 #[derive(Debug)]
@@ -632,8 +633,8 @@ fn drop_loop(&mut self,
         loop_block
     }
 
-    fn open_drop_for_array(&mut self, ety: Ty<'tcx>) -> BasicBlock {
-        debug!("open_drop_for_array({:?})", ety);
+    fn open_drop_for_array(&mut self, ety: Ty<'tcx>, opt_size: Option<u64>) -> BasicBlock {
+        debug!("open_drop_for_array({:?}, {:?})", ety, opt_size);
 
         // if size_of::<ety>() == 0 {
         //     index_based_loop
@@ -641,9 +642,27 @@ fn open_drop_for_array(&mut self, ety: Ty<'tcx>) -> BasicBlock {
         //     ptr_based_loop
         // }
 
-        let tcx = self.tcx();
+        if let Some(size) = opt_size {
+            assert!(size <= (u32::MAX as u64),
+                    "move out check doesn't implemented for array bigger then u32");
+            let size = size as u32;
+            let fields: Vec<(Place<'tcx>, Option<D::Path>)> = (0..size).map(|i| {
+                (self.place.clone().elem(ProjectionElem::ConstantIndex{
+                    offset: i,
+                    min_length: size,
+                    from_end: false
+                }),
+                 self.elaborator.array_subpath(self.path, i, size))
+            }).collect();
+
+            if fields.iter().any(|(_,path)| path.is_some()) {
+                let (succ, unwind) = self.drop_ladder_bottom();
+                return self.drop_ladder(fields, succ, unwind).0
+            }
+        }
 
         let move_ = |place: &Place<'tcx>| Operand::Move(place.clone());
+        let tcx = self.tcx();
         let size = &Place::Local(self.new_temp(tcx.types.usize));
         let size_is_zero = &Place::Local(self.new_temp(tcx.types.bool));
         let base_block = BasicBlockData {
@@ -779,9 +798,10 @@ fn open_drop<'a>(&mut self) -> BasicBlock {
                 let succ = self.succ;
                 self.complete_drop(Some(DropFlagMode::Deep), succ, unwind)
             }
-            ty::TyArray(ety, _) | ty::TySlice(ety) => {
-                self.open_drop_for_array(ety)
-            }
+            ty::TyArray(ety, size) => self.open_drop_for_array(
+                ety, size.val.to_const_int().and_then(|v| v.to_u64())),
+            ty::TySlice(ety) => self.open_drop_for_array(ety, None),
+
             _ => bug!("open drop from non-ADT `{:?}`", ty)
         }
     }
index fda6b8359f111ad7c43c6c6e7c833e902474bec6..cea510de692743565b6a83f6f3f336bf97ec3dff 100644 (file)
                 return false;
             }
 
+            function generateId(ty) {
+                if (ty.parent && ty.parent.name) {
+                    return itemTypes[ty.ty] + ty.path + ty.parent.name + ty.name;
+                }
+                return itemTypes[ty.ty] + ty.path + ty.name;
+            }
+
             // quoted values mean literal search
             var nSearchWords = searchWords.length;
             if ((val.charAt(0) === "\"" || val.charAt(0) === "'") &&
                     var in_args = findArg(searchIndex[i], val, true);
                     var returned = checkReturned(searchIndex[i], val, true);
                     var ty = searchIndex[i];
-                    var fullId = itemTypes[ty.ty] + ty.path + ty.name;
+                    var fullId = generateId(ty);
 
                     if (searchWords[i] === val.name) {
                         // filter type: ... queries
                     if (!type) {
                         continue;
                     }
-                    var fullId = itemTypes[ty.ty] + ty.path + ty.name;
+                    var fullId = generateId(ty);
 
                     // allow searching for void (no output) functions as well
                     var typeOutput = type.output ? type.output.name : "";
                     var index = -1;
                     // we want lev results to go lower than others
                     var lev = MAX_LEV_DISTANCE + 1;
-                    var fullId = itemTypes[ty.ty] + ty.path + ty.name;
+                    var fullId = generateId(ty);
 
                     if (searchWords[j].indexOf(split[i]) > -1 ||
                         searchWords[j].indexOf(val) > -1 ||
diff --git a/src/test/compile-fail/borrowck/borrowck-local-borrow-with-panic-outlives-fn.rs b/src/test/compile-fail/borrowck/borrowck-local-borrow-with-panic-outlives-fn.rs
new file mode 100644 (file)
index 0000000..7009c6f
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// revisions: ast mir
+//[mir]compile-flags: -Z borrowck=mir
+
+fn cplusplus_mode_exceptionally_unsafe(x: &mut Option<&'static mut isize>) {
+    let mut z = (0, 0);
+    *x = Some(&mut z.1); //[ast]~ ERROR [E0597]
+                         //[mir]~^ ERROR [E0597]
+    panic!("catch me for a dangling pointer!")
+}
+
+fn main() {
+    cplusplus_mode_exceptionally_unsafe(&mut None);
+}
index a8b87a273bfd5215dcc993b4551494c448302ada..321c05c49035697e1611d9611cba8d3af7ea05b9 100644 (file)
@@ -50,16 +50,16 @@ fn main() {
 //         StorageLive(_5);
 //         StorageLive(_6);
 //         _6 = move _4;
-//         replace(_5 <- move _6) -> [return: bb1, unwind: bb5];
+//         replace(_5 <-move _6) -> [return: bb2, unwind: bb5];
 //     }
 //     bb1: {
-//         drop(_6) -> [return: bb6, unwind: bb4];
+//         resume;
 //     }
 //     bb2: {
-//         resume;
+//         drop(_6) -> [return: bb6, unwind: bb4];
 //     }
 //     bb3: {
-//         drop(_4) -> bb2;
+//         drop(_4) -> bb1;
 //     }
 //     bb4: {
 //         drop(_5) -> bb3;
@@ -74,7 +74,7 @@ fn main() {
 //     }
 //     bb7: {
 //         StorageDead(_5);
-//         drop(_4) -> bb8;
+//         drop(_4) -> [return: bb8, unwind: bb1];
 //     }
 //     bb8: {
 //         StorageDead(_4);
index 74e07d5e864759b4e0dd691a6c3f64fd7fa677a7..ed9c303a16fd4781aa074477d2784e0f830f5082 100644 (file)
@@ -44,20 +44,20 @@ fn drop(&mut self) {
 //         StorageLive(_1);
 //         StorageLive(_2);
 //         _2 = Box(S);
-//         (*_2) = const S::new() -> [return: bb1, unwind: bb3];
+//         (*_2) = const S::new() -> [return: bb2, unwind: bb3];
 //     }
 //
 //     bb1: {
-//         _1 = move _2;
-//         drop(_2) -> bb4;
+//         resume;
 //     }
 //
 //     bb2: {
-//         resume;
+//         _1 = move _2;
+//         drop(_2) -> bb4;
 //     }
 //
 //     bb3: {
-//         drop(_2) -> bb2;
+//         drop(_2) -> bb1;
 //     }
 //
 //     bb4: {
@@ -72,7 +72,7 @@ fn drop(&mut self) {
 //     }
 //
 //     bb6: {
-//         drop(_1) -> bb2;
+//         drop(_1) -> bb1;
 //     }
 //
 //     bb7: {
index d9456ef1563d328970eb3c16dffad09d9d66ee59..ded818688d72f0aded96c3c38813d15496c0989e 100644 (file)
@@ -51,9 +51,12 @@ fn foo(i: i32) {
 //         _3 = &'26_2rs _2;
 //         StorageLive(_5);
 //         _5 = (*_3);
-//         _4 = const foo(move _5) -> [return: bb1, unwind: bb3];
+//         _4 = const foo(move _5) -> [return: bb2, unwind: bb3];
 //     }
 //     bb1: {
+//         resume;
+//     }
+//     bb2: {
 //         StorageDead(_5);
 //         StorageLive(_6);
 //         _6 = &'26_4rs _2;
@@ -63,14 +66,11 @@ fn foo(i: i32) {
 //         EndRegion('26_2rs);
 //         StorageDead(_3);
 //         StorageDead(_2);
-//         drop(_1) -> bb4;
-//     }
-//     bb2: {
-//         resume;
+//         drop(_1) -> [return: bb4, unwind: bb1];
 //     }
 //     bb3: {
 //         EndRegion('26_2rs);
-//         drop(_1) -> bb2;
+//         drop(_1) -> bb1;
 //     }
 //     bb4: {
 //         StorageDead(_1);
index c2ee2d62b98e80a4aec597af1e21d0e7cc6dc571..1da97a997a19c38034e25c2068a9e3be66623bf1 100644 (file)
@@ -43,20 +43,20 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //         _4 = &'14s _1;
 //         _3 = [closure@NodeId(18)] { d: move _4 };
 //         StorageDead(_4);
-//         _2 = const foo(move _3) -> [return: bb1, unwind: bb3];
+//         _2 = const foo(move _3) -> [return: bb2, unwind: bb3];
 //     }
 //     bb1: {
+//         resume;
+//     }
+//     bb2: {
 //         EndRegion('14s);
 //         StorageDead(_3);
 //         _0 = ();
-//         drop(_1) -> bb4;
-//     }
-//     bb2: {
-//         resume;
+//         drop(_1) -> [return: bb4, unwind: bb1];
 //     }
 //     bb3: {
 //         EndRegion('14s);
-//         drop(_1) -> bb2;
+//         drop(_1) -> bb1;
 //     }
 //     bb4: {
 //         StorageDead(_1);
index 34675e8842f4c2641a4e4a5d6587087f4c0c4813..dadc755eb8c579a571932815bdeb1511e0d60246 100644 (file)
@@ -43,20 +43,20 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //         _4 = &'19s _1;
 //         _3 = [closure@NodeId(22)] { d: move _4 };
 //         StorageDead(_4);
-//         _2 = const foo(move _3) -> [return: bb1, unwind: bb3];
+//         _2 = const foo(move _3) -> [return: bb2, unwind: bb3];
 //     }
 //     bb1: {
+//         resume;
+//     }
+//     bb2: {
 //         EndRegion('19s);
 //         StorageDead(_3);
 //         _0 = ();
-//         drop(_1) -> bb4;
-//     }
-//     bb2: {
-//         resume;
+//         drop(_1) -> [return: bb4, unwind: bb1];
 //     }
 //     bb3: {
 //         EndRegion('19s);
-//         drop(_1) -> bb2;
+//         drop(_1) -> bb1;
 //     }
 //     bb4: {
 //         StorageDead(_1);
index a9b6d2196fc7eaab4d989f00c07be289d9dfa0f7..1426174b482b64af54495f376ab182502ea48096 100644 (file)
@@ -63,7 +63,7 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //     bb6: {
 //         StorageDead(_3);
 //         _0 = ();
-//         drop(_1) -> bb7;
+//         drop(_1) -> [return: bb7, unwind: bb1];
 //     }
 //     bb7: {
 //         StorageDead(_1);
@@ -88,9 +88,12 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //         StorageDead(_3);
 //         EndRegion('15_0rs);
 //         StorageDead(_2);
-//         drop(_1) -> bb1;
+//         drop(_1) -> [return: bb2, unwind: bb1];
 //     }
 //     bb1: {
+//         resume;
+//     }
+//     bb2: {
 //         return;
 //     }
 // }
index 4c1ec4b10262916a3301910ab16979e11f696290..405864aba94365fb85c895a2665553d58978c092 100644 (file)
@@ -48,21 +48,21 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //        _5 = _2;
 //        _4 = [closure@NodeId(22)] { r: move _5 };
 //        StorageDead(_5);
-//        _3 = const foo(move _4) -> [return: bb1, unwind: bb3];
+//        _3 = const foo(move _4) -> [return: bb2, unwind: bb3];
 //    }
 //    bb1: {
+//        resume;
+//    }
+//    bb2: {
 //        StorageDead(_4);
 //        _0 = ();
 //        EndRegion('21_1rs);
 //        StorageDead(_2);
-//        drop(_1) -> bb4;
-//    }
-//    bb2: {
-//        resume;
+//        drop(_1) -> [return: bb4, unwind: bb1];
 //    }
 //    bb3: {
 //        EndRegion('21_1rs);
-//        drop(_1) -> bb2;
+//        drop(_1) -> bb1;
 //    }
 //    bb4: {
 //        StorageDead(_1);
index b8dabada18eabfafaf973a2e31520e0824e56599..37a6229febabb33820d83af7ad6781cf647b3fb1 100644 (file)
@@ -62,6 +62,7 @@ fn query() -> bool { true }
 //     let mut _15: std::option::Option<&'35_0rs S<'35_0rs>>;
 //     let mut _16: &'35_0rs S<'35_0rs>;
 //     let mut _17: &'35_0rs S<'35_0rs>;
+//
 //     bb0: {
 //         goto -> bb1;
 //     }
@@ -70,9 +71,12 @@ fn query() -> bool { true }
 //         StorageLive(_3);
 //         StorageLive(_4);
 //         _4 = std::option::Option<&'35_0rs S<'35_0rs>>::None;
-//         _3 = const <std::cell::Cell<T>>::new(move _4) -> bb2;
+//         _3 = const <std::cell::Cell<T>>::new(move _4) -> [return: bb3, unwind: bb2];
 //     }
 //     bb2: {
+//         resume;
+//     }
+//     bb3: {
 //         StorageDead(_4);
 //         _2 = S<'35_0rs> { r: move _3 };
 //         StorageDead(_3);
@@ -85,27 +89,27 @@ fn query() -> bool { true }
 //         _8 = &'35_0rs (*_9);
 //         _7 = std::option::Option<&'35_0rs S<'35_0rs>>::Some(move _8,);
 //         StorageDead(_8);
-//         _5 = const <std::cell::Cell<T>>::set(move _6, move _7) -> bb3;
+//         _5 = const <std::cell::Cell<T>>::set(move _6, move _7) -> [return: bb4, unwind: bb2];
 //     }
-//     bb3: {
+//     bb4: {
 //         EndRegion('16s);
 //         StorageDead(_7);
 //         StorageDead(_6);
 //         StorageDead(_9);
 //         StorageLive(_11);
-//         _11 = const query() -> bb4;
-//     }
-//     bb4: {
-//         switchInt(move _11) -> [0u8: bb6, otherwise: bb5];
+//         _11 = const query() -> [return: bb5, unwind: bb2];
 //     }
 //     bb5: {
+//         switchInt(move _11) -> [0u8: bb7, otherwise: bb6];
+//     }
+//     bb6: {
 //         _0 = ();
 //         StorageDead(_11);
 //         EndRegion('35_0rs);
 //         StorageDead(_2);
 //         return;
 //     }
-//     bb6: {
+//     bb7: {
 //         _10 = ();
 //         StorageDead(_11);
 //         StorageLive(_14);
@@ -117,9 +121,9 @@ fn query() -> bool { true }
 //         _16 = &'35_0rs (*_17);
 //         _15 = std::option::Option<&'35_0rs S<'35_0rs>>::Some(move _16,);
 //         StorageDead(_16);
-//         _13 = const <std::cell::Cell<T>>::set(move _14, move_15) -> bb7;
+//         _13 = const <std::cell::Cell<T>>::set(move _14, move _15) -> [return: bb8, unwind: bb2];
 //     }
-//     bb7: {
+//     bb8: {
 //         EndRegion('33s);
 //         StorageDead(_15);
 //         StorageDead(_14);
index aebe0a1ff6a91b7a527b94b3a9c5d0b58e33513a..69c5cdccf49d7627e122d846f6195771b70fcf7f 100644 (file)
@@ -99,10 +99,14 @@ fn drop(&mut self) {
 //         _2 = (_3.0: &'12ds S1);
 //         _1 = move _2;
 //         StorageDead(_2);
-//         drop(_3) -> bb1;
+//         drop(_3) -> [return: bb2, unwind: bb1];
 //     }
 //
 //     bb1: {
+//         resume;
+//     }
+//
+//     bb2: {
 //         StorageDead(_3);
 //         StorageDead(_8);
 //         StorageDead(_9);
@@ -146,10 +150,14 @@ fn drop(&mut self) {
 //         _2 = (_3.0: &'12ds S1);
 //         _1 = move _2;
 //         StorageDead(_2);
-//         drop(_3) -> bb1;
+//         drop(_3) -> [return: bb2, unwind: bb1];
 //     }
 //
 //     bb1: {
+//         resume;
+//     }
+//
+//     bb2: {
 //         StorageDead(_3);
 //         StorageDead(_8);
 //         StorageDead(_5);
index b0adbd6ba89e68b903dc069d30aea1673f8d52fd..1f892b0f9587aeade918d94b9657e49fd7da6f7b 100644 (file)
@@ -49,198 +49,207 @@ fn main() {
 
 // END RUST SOURCE
 //
-// START rustc.full_tested_match.SimplifyBranches-initial.before.mir
+// START rustc.full_tested_match.QualifyAndPromoteConstants.after.mir
 //  bb0: {
 //      ...
 //      _2 = std::option::Option<i32>::Some(const 42i32,);
 //      _5 = discriminant(_2);
-//      switchInt(move _5) -> [0isize: bb5, 1isize: bb3, otherwise: bb7];
+//      switchInt(move _5) -> [0isize: bb6, 1isize: bb4, otherwise: bb8];
 //  }
-//  bb1: { // arm1
+//  bb1: {
+//      resume;
+//  }
+//  bb2: {  // arm1
 //      StorageLive(_7);
 //      _7 = _3;
 //      _1 = (const 1i32, move _7);
 //      StorageDead(_7);
-//      goto -> bb12;
+//      goto -> bb13;
 //  }
-//  bb2: { // binding3(empty) and arm3
+//  bb3: { // binding3(empty) and arm3
 //      _1 = (const 3i32, const 3i32);
-//      goto -> bb12;
-//  }
-//  bb3: {
-//      falseEdges -> [real: bb8, imaginary: bb4]; //pre_binding1
+//      goto -> bb13;
 //  }
 //  bb4: {
-//      falseEdges -> [real: bb11, imaginary: bb5]; //pre_binding2
+//      falseEdges -> [real: bb9, imaginary: bb5]; //pre_binding1
 //  }
 //  bb5: {
-//      falseEdges -> [real: bb2, imaginary: bb6]; //pre_binding3
+//      falseEdges -> [real: bb12, imaginary: bb6]; //pre_binding2
 //  }
 //  bb6: {
-//      unreachable;
+//      falseEdges -> [real: bb3, imaginary: bb7]; //pre_binding3
 //  }
 //  bb7: {
 //      unreachable;
 //  }
-//  bb8: { // binding1 and guard
+//  bb8: {
+//      unreachable;
+//  }
+//  bb9: { // binding1 and guard
 //      StorageLive(_3);
 //      _3 = ((_2 as Some).0: i32);
 //      StorageLive(_6);
-//      _6 = const guard() -> bb9;
+//      _6 = const guard() -> [return: bb10, unwind: bb1];
 //  }
-//  bb9: { // end of guard
-//      switchInt(move _6) -> [0u8: bb10, otherwise: bb1];
+//  bb10: { // end of guard
+//      switchInt(move _6) -> [0u8: bb11, otherwise: bb2];
 //  }
-//  bb10: { // to pre_binding2
-//      falseEdges -> [real: bb4, imaginary: bb4];
+//  bb11: { // to pre_binding2
+//      falseEdges -> [real: bb5, imaginary: bb5];
 //  }
-//  bb11: { // bindingNoLandingPads.before.mir2 and arm2
+//  bb12: { // bindingNoLandingPads.before.mir2 and arm2
 //      StorageLive(_4);
 //      _4 = ((_2 as Some).0: i32);
 //      StorageLive(_8);
 //      _8 = _4;
 //      _1 = (const 2i32, move _8);
 //      StorageDead(_8);
-//      goto -> bb12;
+//      goto -> bb13;
 //  }
-//  bb12: {
+//  bb13: {
 //      ...
 //      return;
 //  }
-// END rustc.full_tested_match.SimplifyBranches-initial.before.mir
+// END rustc.full_tested_match.QualifyAndPromoteConstants.after.mir
 //
-// START rustc.full_tested_match2.SimplifyBranches-initial.before.mir
+// START rustc.full_tested_match2.QualifyAndPromoteConstants.before.mir
 //  bb0: {
 //      ...
 //      _2 = std::option::Option<i32>::Some(const 42i32,);
 //      _5 = discriminant(_2);
-//      switchInt(move _5) -> [0isize: bb4, 1isize: bb3, otherwise: bb7];
+//      switchInt(move _5) -> [0isize: bb5, 1isize: bb4, otherwise: bb8];
+//  }
+//  bb1: {
+//      resume;
 //  }
-//  bb1: { // arm1
+//  bb2: { // arm1
 //      StorageLive(_7);
 //      _7 = _3;
 //      _1 = (const 1i32, move _7);
 //      StorageDead(_7);
-//      goto -> bb12;
+//      goto -> bb13;
 //  }
-//  bb2: { // binding3(empty) and arm3
+//  bb3: { // binding3(empty) and arm3
 //      _1 = (const 3i32, const 3i32);
-//      goto -> bb12;
-//  }
-//  bb3: {
-//      falseEdges -> [real: bb8, imaginary: bb4]; //pre_binding1
+//      goto -> bb13;
 //  }
 //  bb4: {
-//      falseEdges -> [real: bb2, imaginary: bb5]; //pre_binding2
+//      falseEdges -> [real: bb9, imaginary: bb5]; //pre_binding1
 //  }
 //  bb5: {
-//      falseEdges -> [real: bb11, imaginary: bb6]; //pre_binding3
+//      falseEdges -> [real: bb3, imaginary: bb6]; //pre_binding2
 //  }
 //  bb6: {
-//      unreachable;
+//      falseEdges -> [real: bb12, imaginary: bb7]; //pre_binding3
 //  }
 //  bb7: {
 //      unreachable;
 //  }
-//  bb8: { // binding1 and guard
+//  bb8: {
+//      unreachable;
+//  }
+//  bb9: { // binding1 and guard
 //      StorageLive(_3);
 //      _3 = ((_2 as Some).0: i32);
 //      StorageLive(_6);
-//      _6 = const guard() -> bb9;
+//      _6 = const guard() -> [return: bb10, unwind: bb1];
 //  }
-//  bb9: { // end of guard
-//      switchInt(move _6) -> [0u8: bb10, otherwise: bb1];
+//  bb10: { // end of guard
+//      switchInt(move _6) -> [0u8: bb11, otherwise: bb2];
 //  }
-//  bb10: { // to pre_binding2
-//      falseEdges -> [real: bb5, imaginary: bb4];
+//  bb11: { // to pre_binding2
+//      falseEdges -> [real: bb6, imaginary: bb5];
 //  }
-//  bb11: { // binding2 and arm2
+//  bb12: { // binding2 and arm2
 //      StorageLive(_4);
 //      _4 = ((_2 as Some).0: i32);
 //      StorageLive(_8);
 //      _8 = _4;
 //      _1 = (const 2i32, move _8);
 //      StorageDead(_8);
-//      goto -> bb12;
+//      goto -> bb13;
 //  }
-//  bb12: {
+//  bb13: {
 //      ...
 //      return;
 //  }
-// END rustc.full_tested_match2.SimplifyBranches-initial.before.mir
+// END rustc.full_tested_match2.QualifyAndPromoteConstants.before.mir
 //
-// START rustc.main.SimplifyBranches-initial.before.mir
+// START rustc.main.QualifyAndPromoteConstants.before.mir
 // bb0: {
 //     ...
 //     _2 = std::option::Option<i32>::Some(const 1i32,);
 //     _7 = discriminant(_2);
-//     switchInt(move _7) -> [1isize: bb3, otherwise: bb4];
+//     switchInt(move _7) -> [1isize: bb4, otherwise: bb5];
+// }
+// bb1: {
+//     resume;
 // }
-// bb1: { // arm1
-//      _1 = const 1i32;
-//      goto -> bb16;
+// bb2: { // arm1
+//     _1 = const 1i32;
+//     goto -> bb17;
 // }
-// bb2: { // arm3
+// bb3: { // arm3
 //     _1 = const 3i32;
-//      goto -> bb16;
+//     goto -> bb17;
 // }
 //
-//  bb3: {
-//      falseEdges -> [real: bb8, imaginary: bb4]; //pre_binding1
-//  }
-//  bb4: {
-//      falseEdges -> [real: bb11, imaginary: bb5]; //pre_binding2
-//  }
-//  bb5: {
-//      falseEdges -> [real: bb12, imaginary: bb6]; //pre_binding3
-//  }
-//  bb6: {
-//      falseEdges -> [real: bb15, imaginary: bb7]; //pre_binding4
-//  }
-//  bb7: {
-//      unreachable;
-//  }
-//  bb8: { // binding1: Some(w) if guard()
-//      StorageLive(_3);
-//      _3 = ((_2 as Some).0: i32);
-//      StorageLive(_8);
-//      _8 = const guard() -> bb9;
-//  }
-//  bb9: { //end of guard
-//      switchInt(move _8) -> [0u8: bb10, otherwise: bb1];
-//  }
-//  bb10: { // to pre_binding2
-//      falseEdges -> [real: bb4, imaginary: bb4];
-//  }
-//  bb11: { // binding2 & arm2
-//      StorageLive(_4);
-//      _4 = _2;
-//      _1 = const 2i32;
-//      goto -> bb16;
-//  }
-//  bb12: { // binding3: Some(y) if guard2(y)
-//      StorageLive(_5);
-//      _5 = ((_2 as Some).0: i32);
-//      StorageLive(_10);
-//      StorageLive(_11);
-//      _11 = _5;
-//      _10 = const guard2(move _11) -> bb13;
-//  }
-//  bb13: { // end of guard2
-//      StorageDead(_11);
-//      switchInt(move _10) -> [0u8: bb14, otherwise: bb2];
-//  }
-//  bb14: { // to pre_binding4
-//      falseEdges -> [real: bb6, imaginary: bb6];
-//  }
-//  bb15: { // binding4 & arm4
-//      StorageLive(_6);
-//      _6 = _2;
-//      _1 = const 4i32;
-//      goto -> bb16;
-//  }
-// bb16: {
+// bb4: {
+//     falseEdges -> [real: bb9, imaginary: bb5]; //pre_binding1
+// }
+// bb5: {
+//     falseEdges -> [real: bb12, imaginary: bb6]; //pre_binding2
+// }
+// bb6: {
+//     falseEdges -> [real: bb13, imaginary: bb7]; //pre_binding3
+// }
+// bb7: {
+//     falseEdges -> [real: bb16, imaginary: bb8]; //pre_binding4
+// }
+// bb8: {
+//     unreachable;
+// }
+// bb9: { // binding1: Some(w) if guard()
+//     StorageLive(_3);
+//     _3 = ((_2 as Some).0: i32);
+//     StorageLive(_8);
+//     _8 = const guard() -> [return: bb10, unwind: bb1];
+// }
+// bb10: { //end of guard
+//    switchInt(move _8) -> [0u8: bb11, otherwise: bb2];
+// }
+// bb11: { // to pre_binding2
+//     falseEdges -> [real: bb5, imaginary: bb5];
+// }
+// bb12: { // binding2 & arm2
+//     StorageLive(_4);
+//     _4 = _2;
+//     _1 = const 2i32;
+//     goto -> bb17;
+// }
+// bb13: { // binding3: Some(y) if guard2(y)
+//     StorageLive(_5);
+//     _5 = ((_2 as Some).0: i32);
+//     StorageLive(_10);
+//     StorageLive(_11);
+//     _11 = _5;
+//     _10 = const guard2(move _11) -> [return: bb14, unwind: bb1];
+// }
+// bb14: { // end of guard2
+//     StorageDead(_11);
+//     switchInt(move _10) -> [0u8: bb15, otherwise: bb3];
+// }
+// bb15: { // to pre_binding4
+//     falseEdges -> [real: bb7, imaginary: bb7];
+// }
+// bb16: { // binding4 & arm4
+//     StorageLive(_6);
+//     _6 = _2;
+//     _1 = const 4i32;
+//     goto -> bb17;
+// }
+// bb17: {
 //     ...
 //     return;
 // }
-// END rustc.main.SimplifyBranches-initial.before.mir
+// END rustc.main.QualifyAndPromoteConstants.before.mir
index 59a1d4891f66fab5c2ab36ea02d590d975b90cd6..e4dd99f5a1e75e8874e39f9fc064ac68ae1f30be 100644 (file)
@@ -31,15 +31,15 @@ fn main() {
 //            | Live variables at bb0[0]: []
 //        StorageLive(_1);
 //            | Live variables at bb0[1]: []
-//        _1 = const <std::boxed::Box<T>>::new(const 22usize) -> bb1;
+//        _1 = const <std::boxed::Box<T>>::new(const 22usize) -> [return: bb2, unwind: bb1];
 //    }
 // END rustc.main.nll.0.mir
 // START rustc.main.nll.0.mir
-//    | Live variables on entry to bb1: [_1 (drop)]
-//    bb1: {
-//            | Live variables at bb1[0]: [_1 (drop)]
+//    | Live variables on entry to bb2: [_1 (drop)]
+//    bb2: {
+//            | Live variables at bb2[0]: [_1 (drop)]
 //        StorageLive(_2);
-//            | Live variables at bb1[1]: [_1 (drop)]
-//        _2 = const can_panic() -> [return: bb2, unwind: bb4];
+//            | Live variables at bb2[1]: [_1 (drop)]
+//        _2 = const can_panic() -> [return: bb3, unwind: bb4];
 //    }
 // END rustc.main.nll.0.mir
index 3e86677956f0bea0689065e7c5f36446eae7b4f6..8dae773806718094a85ac1e378c72fd8af1ed210 100644 (file)
@@ -25,17 +25,17 @@ fn main() {
 
 // END RUST SOURCE
 // START rustc.main.nll.0.mir
-//    | Live variables on entry to bb1: []
-//    bb1: {
-//            | Live variables at bb1[0]: []
+//    | Live variables on entry to bb2: []
+//    bb2: {
+//            | Live variables at bb2[0]: []
 //        _1 = const 55usize;
-//            | Live variables at bb1[1]: [_1]
+//            | Live variables at bb2[1]: [_1]
 //        StorageLive(_3);
-//            | Live variables at bb1[2]: [_1]
+//            | Live variables at bb2[2]: [_1]
 //        StorageLive(_4);
-//            | Live variables at bb1[3]: [_1]
+//            | Live variables at bb2[3]: [_1]
 //        _4 = _1;
-//            | Live variables at bb1[4]: [_4]
-//        _3 = const use_x(move _4) -> bb2;
+//            | Live variables at bb2[4]: [_4]
+//        _3 = const use_x(move _4) -> [return: bb3, unwind: bb1];
 //    }
 // END rustc.main.nll.0.mir
index 32a38a5cd5e359b5283560a65a0bb73eea50b127..5d799d3d90b414c87c6aea71393b9eeb96b7be6f 100644 (file)
@@ -29,22 +29,20 @@ fn main() {
 
 // END RUST SOURCE
 // START rustc.main.nll.0.mir
-//     | Live variables on entry to bb2: [_1]
-//     bb2: {
-//             | Live variables at bb2[0]: [_1]
+//     | Live variables on entry to bb3: [_1]
+//     bb3: {
+//             | Live variables at bb3[0]: [_1]
 //         StorageLive(_4);
-//             | Live variables at bb2[1]: [_1]
+//             | Live variables at bb3[1]: [_1]
 //         _4 = _1;
-//             | Live variables at bb2[2]: [_4]
-//         _3 = const make_live(move _4) -> bb4;
+//             | Live variables at bb3[2]: [_4]
+//         _3 = const make_live(move _4) -> [return: bb5, unwind: bb1];
 //     }
 // END rustc.main.nll.0.mir
 // START rustc.main.nll.0.mir
-//     | Live variables on entry to bb3: []
-//     bb3: {
-//             | Live variables at bb3[0]: []
-//         _5 = const make_dead() -> bb5;
+//     | Live variables on entry to bb4: []
+//     bb4: {
+//             | Live variables at bb4[0]: []
+//         _5 = const make_dead() -> [return: bb6, unwind: bb1];
 //     }
 // END rustc.main.nll.0.mir
-
-
index 3aba3ac86aea4efb25b36bceb7fed8909fef8cfc..36dedeebd538a92c73df3af01e46784d2ff96612 100644 (file)
@@ -31,26 +31,26 @@ fn main() {
 
 // END RUST SOURCE
 // START rustc.main.nll.0.mir
-// | '_#1r: {bb1[1], bb2[0], bb2[1]}
-// | '_#2r: {bb1[1], bb2[0], bb2[1]}
+// | '_#1r: {bb2[1], bb3[0], bb3[1]}
+// | '_#2r: {bb2[1], bb3[0], bb3[1]}
 // ...
 //             let _2: &'_#2r usize;
 // END rustc.main.nll.0.mir
 // START rustc.main.nll.0.mir
-//    bb1: {
-//            | Live variables at bb1[0]: [_1, _3]
+//    bb2: {
+//            | Live variables at bb2[0]: [_1, _3]
 //        _2 = &'_#1r _1[_3];
-//            | Live variables at bb1[1]: [_2]
-//        switchInt(const true) -> [0u8: bb3, otherwise: bb2];
+//            | Live variables at bb2[1]: [_2]
+//        switchInt(const true) -> [0u8: bb4, otherwise: bb3];
 //    }
 // END rustc.main.nll.0.mir
 // START rustc.main.nll.0.mir
-//    bb2: {
-//            | Live variables at bb2[0]: [_2]
+//    bb3: {
+//            | Live variables at bb3[0]: [_2]
 //        StorageLive(_7);
-//            | Live variables at bb2[1]: [_2]
+//            | Live variables at bb3[1]: [_2]
 //        _7 = (*_2);
-//            | Live variables at bb2[2]: [_7]
-//        _6 = const use_x(move _7) -> bb4;
+//            | Live variables at bb3[2]: [_7]
+//        _6 = const use_x(move _7) -> [return: bb5, unwind: bb1];
 //    }
 // END rustc.main.nll.0.mir
index 6d7aa0a26c8a8d129ee95fad87650238d61d7f3b..04a30dc284d7727f997970d6019fa4b691d394e0 100644 (file)
@@ -44,5 +44,5 @@ fn drop(&mut self) { }
 
 // END RUST SOURCE
 // START rustc.main.nll.0.mir
-// | '_#5r: {bb1[3], bb1[4], bb1[5], bb2[0], bb2[1]}
+// | '_#5r: {bb2[3], bb2[4], bb2[5], bb3[0], bb3[1]}
 // END rustc.main.nll.0.mir
index 3d92054b0b2bf32694f2cd5b5a5a0e4478929145..5569fe7f5748c44b7b6ef4b6bf3439421f5dbc49 100644 (file)
@@ -13,7 +13,6 @@
 // including) the call to `use_x`. The `else` branch is not included.
 
 // ignore-tidy-linelength
-// ignore-test #46267
 // compile-flags:-Znll -Zverbose
 //                     ^^^^^^^^^ force compiler to dump more region information
 
@@ -47,5 +46,5 @@ fn drop(&mut self) { }
 
 // END RUST SOURCE
 // START rustc.main.nll.0.mir
-// | '_#5r: {bb1[3], bb1[4], bb1[5], bb2[0], bb2[1], bb2[2], bb3[0], bb4[0], bb4[1], bb4[2], bb6[0], bb7[0], bb7[1], bb8[0]}
+// | '_#5r: {bb2[3], bb2[4], bb2[5], bb3[0], bb3[1], bb3[2], bb4[0], bb5[0], bb5[1], bb5[2], bb6[0], bb7[0], bb7[1], bb8[0]}
 // END rustc.main.nll.0.mir
index 5c28746126a643c92e84123e7d43db0f4b961cdc..de2b18fe4afa3596b351049aae48ca6cb8c37eb3 100644 (file)
@@ -36,10 +36,10 @@ fn main() {
 
 // END RUST SOURCE
 // START rustc.main.nll.0.mir
-// | '_#1r: {bb1[1], bb2[0], bb2[1]}
+// | '_#1r: {bb2[1], bb3[0], bb3[1]}
 // ...
-// | '_#3r: {bb7[2], bb7[3], bb7[4]}
-// | '_#4r: {bb1[1], bb2[0], bb2[1], bb7[2], bb7[3], bb7[4]}
+// | '_#3r: {bb8[2], bb8[3], bb8[4]}
+// | '_#4r: {bb2[1], bb3[0], bb3[1], bb8[2], bb8[3], bb8[4]}
 // ...
 // let mut _2: &'_#4r usize;
 // ...
index 3570107673052d134fcb73a05fa82555837ec537..6a2a7cc7149974b00a303b8c83323eda46c1f151 100644 (file)
@@ -32,9 +32,9 @@ fn main() {
 
 // END RUST SOURCE
 // START rustc.main.nll.0.mir
-// | '_#1r: {bb1[1], bb1[2], bb1[3], bb1[4], bb1[5], bb1[6], bb2[0], bb2[1]}
-// | '_#2r: {bb1[1], bb1[2], bb1[3], bb1[4], bb1[5], bb1[6], bb2[0], bb2[1]}
-// | '_#3r: {bb1[5], bb1[6], bb2[0], bb2[1]}
+// | '_#1r: {bb2[1], bb2[2], bb2[3], bb2[4], bb2[5], bb2[6], bb3[0], bb3[1]}
+// | '_#2r: {bb2[1], bb2[2], bb2[3], bb2[4], bb2[5], bb2[6], bb3[0], bb3[1]}
+// | '_#3r: {bb2[5], bb2[6], bb3[0], bb3[1]}
 // END rustc.main.nll.0.mir
 // START rustc.main.nll.0.mir
 // let _2: &'_#2r usize;
index 0706f185d3163da489b90651170bd545ec3d023a..1b114419448f11b54cbb48d4b69ac09128c4d5c1 100644 (file)
@@ -64,7 +64,7 @@ fn drop(&mut self) {}
 //         (_1.0: Aligned) = move _4;
 //         StorageDead(_4);
 //         _0 = ();
-//         drop(_1) -> bb2;
+//         drop(_1) -> [return: bb2, unwind: bb1];
 //     }
 // }
 // END rustc.main.EraseRegions.before.mir
index ad3bbba8d08df2a82230854e4eb47f5d6e5106ab..35786643648eb12d48d8367491ccb35d2adc3ef0 100644 (file)
@@ -17,11 +17,11 @@ fn main() {
 // END RUST SOURCE
 // START rustc.main.SimplifyBranches-initial.before.mir
 // bb0: {
-//     switchInt(const false) -> [0u8: bb2, otherwise: bb1];
+//     switchInt(const false) -> [0u8: bb3, otherwise: bb2];
 // }
 // END rustc.main.SimplifyBranches-initial.before.mir
 // START rustc.main.SimplifyBranches-initial.after.mir
 // bb0: {
-//     goto -> bb2;
+//     goto -> bb3;
 // }
 // END rustc.main.SimplifyBranches-initial.after.mir
index 5b8ba4d8d06321a36606f24a3832eee41377faac..3776a11b3ab825ceb53ad5241d1bfdd3be2b83f0 100644 (file)
@@ -9,6 +9,8 @@
 // except according to those terms.
 
 // ignore-tidy-linelength
+// ignore-wasm32-bare unwinding being disabled causes differences in output
+// ignore-wasm64-bare unwinding being disabled causes differences in output
 // compile-flags: -Z verbose -Z mir-emit-validate=1
 
 fn main() {
@@ -28,7 +30,7 @@ fn main() {
 //         StorageDead(_3);
 //         _0 = ();
 //         Validate(Release, [_1: std::boxed::Box<[i32]>]);
-//         drop(_1) -> bb2;
+//         drop(_1) -> [return: bb2, unwind: bb3];
 //     }
 //     ...
 // }
index fb0c8871d8384936af2723a0a6f28f74c9c99bcf..24a4ebd8429dfb559d887d928c824be17f46699b 100644 (file)
@@ -54,6 +54,7 @@ fn main() {
 //         Validate(Acquire, [_1: &ReFree(DefId(0/1:9 ~ validate_4[317d]::write_42[0]::{{closure}}[0]), BrEnv) [closure@NodeId(22)], _2: *mut i32]);
 //         Validate(Release, [_1: &ReFree(DefId(0/1:9 ~ validate_4[317d]::write_42[0]::{{closure}}[0]), BrEnv) [closure@NodeId(22)], _2: *mut i32]);
 //         (*_2) = const 23i32;
+//         _0 = ();
 //         return;
 //     }
 // }
index 3310d3a89b92b76dab4f60e22cd9cd54a1f74d41..09318e7256fd7c5277641de20bd3eec7dca35d6d 100644 (file)
@@ -10,7 +10,7 @@
 
 // ignore-wasm32-bare compiled with panic=abort by default
 
-#![feature(generators, generator_trait, untagged_unions)]
+#![feature(generators, generator_trait, untagged_unions, slice_patterns, advanced_slice_patterns)]
 
 use std::cell::{Cell, RefCell};
 use std::ops::Generator;
@@ -195,6 +195,33 @@ fn vec_unreachable(a: &Allocator) {
     let _x = vec![a.alloc(), a.alloc(), a.alloc(), return];
 }
 
+fn slice_pattern_first(a: &Allocator) {
+    let[_x, ..] = [a.alloc(), a.alloc(), a.alloc()];
+}
+
+fn slice_pattern_middle(a: &Allocator) {
+    let[_, _x, _] = [a.alloc(), a.alloc(), a.alloc()];
+}
+
+fn slice_pattern_two(a: &Allocator) {
+    let[_x, _, _y, _] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
+}
+
+fn slice_pattern_last(a: &Allocator) {
+    let[.., _y] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
+}
+
+fn slice_pattern_one_of(a: &Allocator, i: usize) {
+    let array = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
+    let _x = match i {
+        0 => { let [a, ..] = array; a }
+        1 => { let [_, a, ..] = array; a }
+        2 => { let [_, _, a, _] = array; a }
+        3 => { let [_, _, _, a] = array; a }
+        _ => panic!("unmatched"),
+    };
+}
+
 fn run_test<F>(mut f: F)
     where F: FnMut(&Allocator)
 {
@@ -264,5 +291,14 @@ fn main() {
 
     run_test(|a| mixed_drop_and_nondrop(a));
 
+    run_test(|a| slice_pattern_first(a));
+    run_test(|a| slice_pattern_middle(a));
+    run_test(|a| slice_pattern_two(a));
+    run_test(|a| slice_pattern_last(a));
+    run_test(|a| slice_pattern_one_of(a, 0));
+    run_test(|a| slice_pattern_one_of(a, 1));
+    run_test(|a| slice_pattern_one_of(a, 2));
+    run_test(|a| slice_pattern_one_of(a, 3));
+
     run_test_nopanic(|a| union1(a));
 }
index ff562aac1614bd34c9d19047ee936275b67c3287..127f9e355c7a27532db03065bbd229c7f391de48 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// compile-flags: -Z borrowck=compare
 
 static mut DROP: isize = 0;
 static mut DROP_S: isize = 0;
index 64fd9e0a7721b833de1877fd4abb12964d6b01f2..ecb62b1888dd20de8383479a15cd8329bcf397e1 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// compile-flags: -Z borrowck=compare
 
 use std::cell::Cell;
 use std::mem::swap;