about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-10-27 21:04:59 +0000
committerbors <bors@rust-lang.org>2015-10-27 21:04:59 +0000
commit8a72584f977d2d72f752c2a540e160944159e8db (patch)
tree78a1d3ba818bb07a64cb6d67b19205ce6e0305ed
parenta1e2a5538a33577f5845fc8bf56d06c452513245 (diff)
parentba9c383790c22dba74026340b01f2dda3e78f88c (diff)
downloadrust-8a72584f977d2d72f752c2a540e160944159e8db.tar.gz
rust-8a72584f977d2d72f752c2a540e160944159e8db.zip
Auto merge of #28833 - jryans:borrowck-linear-errors, r=pnkfelix
Change error reporting of conflicting loans to stop earlier after printing
an error for a given borrow, instead of proceeding to error on possibly every
issued loan.  This keeps us down to O(n) errors (for n problem lines), instead
of O(n^2) errors in some cases.

Fixes #27485.
-rw-r--r--src/librustc_borrowck/borrowck/check_loans.rs18
-rw-r--r--src/test/compile-fail/borrowck-mut-borrow-linear-errors.rs28
2 files changed, 38 insertions, 8 deletions
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index 43e9cdd73c4..ff5d364b968 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -363,13 +363,14 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
         let new_loan_indices = self.loans_generated_by(node);
         debug!("new_loan_indices = {:?}", new_loan_indices);
 
-        self.each_issued_loan(node, |issued_loan| {
-            for &new_loan_index in &new_loan_indices {
+        for &new_loan_index in &new_loan_indices {
+            self.each_issued_loan(node, |issued_loan| {
                 let new_loan = &self.all_loans[new_loan_index];
-                self.report_error_if_loans_conflict(issued_loan, new_loan);
-            }
-            true
-        });
+                // Only report an error for the first issued loan that conflicts
+                // to avoid O(n^2) errors.
+                self.report_error_if_loans_conflict(issued_loan, new_loan)
+            });
+        }
 
         for (i, &x) in new_loan_indices.iter().enumerate() {
             let old_loan = &self.all_loans[x];
@@ -382,7 +383,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
 
     pub fn report_error_if_loans_conflict(&self,
                                           old_loan: &Loan<'tcx>,
-                                          new_loan: &Loan<'tcx>) {
+                                          new_loan: &Loan<'tcx>)
+                                          -> bool {
         //! Checks whether `old_loan` and `new_loan` can safely be issued
         //! simultaneously.
 
@@ -397,7 +399,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
         self.report_error_if_loan_conflicts_with_restriction(
             old_loan, new_loan, old_loan, new_loan) &&
         self.report_error_if_loan_conflicts_with_restriction(
-            new_loan, old_loan, old_loan, new_loan);
+            new_loan, old_loan, old_loan, new_loan)
     }
 
     pub fn report_error_if_loan_conflicts_with_restriction(&self,
diff --git a/src/test/compile-fail/borrowck-mut-borrow-linear-errors.rs b/src/test/compile-fail/borrowck-mut-borrow-linear-errors.rs
new file mode 100644
index 00000000000..38e0e27a7b9
--- /dev/null
+++ b/src/test/compile-fail/borrowck-mut-borrow-linear-errors.rs
@@ -0,0 +1,28 @@
+// Copyright 2015 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.
+
+// Test to ensure we only report an error for the first issued loan that
+// conflicts with a new loan, as opposed to every issued loan.  This keeps us
+// down to O(n) errors (for n problem lines), instead of O(n^2) errors.
+
+fn main() {
+    let mut x = 1;
+    let mut addr;
+    loop {
+        match 1 {
+            1 => { addr = &mut x; }
+            //~^ ERROR cannot borrow `x` as mutable more than once at a time
+            2 => { addr = &mut x; }
+            //~^ ERROR cannot borrow `x` as mutable more than once at a time
+            _ => { addr = &mut x; }
+            //~^ ERROR cannot borrow `x` as mutable more than once at a time
+        }
+    }
+}