diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 1bfc5805bc8..16ecfce49d0 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -112,19 +112,28 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) { // is not yet stolen. tcx.mir_validated(owner_def_id).borrow(); - let cfg = cfg::CFG::new(bccx.tcx, &body); - let AnalysisData { all_loans, - loans: loan_dfcx, - move_data: flowed_moves } = - build_borrowck_dataflow_data(bccx, &cfg, body_id); - - check_loans::check_loans(bccx, &loan_dfcx, &flowed_moves, &all_loans, body); + // option dance because you can't capture an uninitialized variable + // by mut-ref. + let mut cfg = None; + if let Some(AnalysisData { all_loans, + loans: loan_dfcx, + move_data: flowed_moves }) = + build_borrowck_dataflow_data(bccx, false, body_id, + |bccx| { + cfg = Some(cfg::CFG::new(bccx.tcx, &body)); + cfg.as_mut().unwrap() + }) + { + check_loans::check_loans(bccx, &loan_dfcx, &flowed_moves, &all_loans, body); + } } -fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, - cfg: &cfg::CFG, - body_id: hir::BodyId) - -> AnalysisData<'a, 'tcx> +fn build_borrowck_dataflow_data<'a, 'c, 'tcx, F>(this: &mut BorrowckCtxt<'a, 'tcx>, + force_analysis: bool, + body_id: hir::BodyId, + get_cfg: F) + -> Option> + where F: FnOnce(&mut BorrowckCtxt<'a, 'tcx>) -> &'c cfg::CFG { // Check the body of fn items. let tcx = this.tcx; @@ -137,6 +146,18 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, let (all_loans, move_data) = gather_loans::gather_loans_in_fn(this, body_id); + if !force_analysis && move_data.is_empty() && all_loans.is_empty() { + // large arrays of data inserted as constants can take a lot of + // time and memory to borrow-check - see issue #36799. However, + // they don't have lvalues, so no borrow-check is actually needed. + // Recognize that case and skip borrow-checking. + debug!("skipping loan propagation for {:?} because of no loans", body_id); + return None; + } else { + debug!("propagating loans in {:?}", body_id); + } + + let cfg = get_cfg(this); let mut loan_dfcx = DataFlowContext::new(this.tcx, "borrowck", @@ -159,9 +180,9 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, id_range, body); - AnalysisData { all_loans: all_loans, - loans: loan_dfcx, - move_data:flowed_moves } + Some(AnalysisData { all_loans: all_loans, + loans: loan_dfcx, + move_data:flowed_moves }) } /// Accessor for introspective clients inspecting `AnalysisData` and @@ -178,8 +199,8 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>( let region_maps = tcx.region_maps(owner_def_id); let mut bccx = BorrowckCtxt { tcx, tables, region_maps, owner_def_id }; - let dataflow_data = build_borrowck_dataflow_data(&mut bccx, cfg, body_id); - (bccx, dataflow_data) + let dataflow_data = build_borrowck_dataflow_data(&mut bccx, true, body_id, |_| cfg); + (bccx, dataflow_data.unwrap()) } // ---------------------------------------------------------------------- diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index 0a31905c792..fd80e8320d6 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -220,6 +220,15 @@ impl<'a, 'tcx> MoveData<'tcx> { } } + /// return true if there are no trackable assignments or moves + /// in this move data - that means that there is nothing that + /// could cause a borrow error. + pub fn is_empty(&self) -> bool { + self.moves.borrow().is_empty() && + self.path_assignments.borrow().is_empty() && + self.var_assignments.borrow().is_empty() + } + pub fn path_loan_path(&self, index: MovePathIndex) -> Rc> { (*self.paths.borrow())[index.get()].loan_path.clone() }