From 58365e2921206a9e3b98ac1df5161a62d5eddcdb Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 6 Jan 2017 21:04:49 -0500 Subject: [PATCH] check that the path from which we borrow is readable The old code incorrectly assumed that the borrow would always generate a loan. In that case, we will check if that loan conflicts with other loans and hence get an error if the path we borrowed is mutably borrowed. But this is not true if we are borrowing the referent of an `&T` reference. Fixes #38899. --- src/libgetopts/lib.rs | 9 ++++--- src/librustc_borrowck/borrowck/check_loans.rs | 1 + ...ck-reborrow-shared-referent-issue-38899.rs | 27 +++++++++++++++++++ 3 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 src/test/compile-fail/borrowck/borrowck-reborrow-shared-referent-issue-38899.rs diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs index 4d2f1b999a2ae..4d0ab34bc4a90 100644 --- a/src/libgetopts/lib.rs +++ b/src/libgetopts/lib.rs @@ -101,6 +101,7 @@ use self::SplitWithinState::*; use self::Whitespace::*; use self::LengthLimit::*; +use std::cell::Cell; use std::fmt; use std::iter::repeat; use std::result; @@ -858,7 +859,7 @@ fn each_split_within(ss: &str, lim: usize, mut it: F) -> bool let mut slice_start = 0; let mut last_start = 0; let mut last_end = 0; - let mut state = A; + let state = Cell::new(A); let mut fake_i = ss.len(); let mut lim = lim; @@ -881,7 +882,7 @@ fn each_split_within(ss: &str, lim: usize, mut it: F) -> bool OverLim }; - state = match (state, whitespace, limit) { + state.set(match (state.get(), whitespace, limit) { (A, Ws, _) => A, (A, Cr, _) => { slice_start = i; @@ -925,7 +926,7 @@ fn each_split_within(ss: &str, lim: usize, mut it: F) -> bool A } (C, Ws, UnderLim) => C, - }; + }); *cont }; @@ -934,7 +935,7 @@ fn each_split_within(ss: &str, lim: usize, mut it: F) -> bool // Let the automaton 'run out' by supplying trailing whitespace while cont && - match state { + match state.get() { B | C => true, A => false, } { diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index dc2214dd34e72..1a539ef2afd15 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -141,6 +141,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> { _ => MovedInUse, }; self.check_if_path_is_moved(borrow_id, borrow_span, moved_value_use_kind, &lp); + self.check_for_copy_of_frozen_path(borrow_id, borrow_span, &lp); } self.check_for_conflicting_loans(borrow_id); diff --git a/src/test/compile-fail/borrowck/borrowck-reborrow-shared-referent-issue-38899.rs b/src/test/compile-fail/borrowck/borrowck-reborrow-shared-referent-issue-38899.rs new file mode 100644 index 0000000000000..b821f40970769 --- /dev/null +++ b/src/test/compile-fail/borrowck/borrowck-reborrow-shared-referent-issue-38899.rs @@ -0,0 +1,27 @@ +// Copyright 2012 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that reborrowing the referent of an `&T` reference is not +// possible if the path we use to reach that reference is itself +// borrowed. Regression test for #38899. + +#![allow(dead_code)] + +pub struct Block<'a> { + current: &'a u8, + unrelated: &'a u8, +} + +fn bump<'a>(mut block: &mut Block<'a>) { + let x = &mut block; + let p: &'a u8 = &*block.current; //~ ERROR E0503 +} + +fn main() {}