From 3be597acf3a0cac1939c4d9f0789510221667c96 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Thu, 16 Nov 2017 02:56:06 -0800 Subject: [PATCH 1/3] Allow assignment to static muts --- src/librustc_mir/borrow_check.rs | 6 ++-- .../borrowck-unsafe-static-mutable-borrows.rs | 31 +++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 src/test/run-pass/borrowck/borrowck-unsafe-static-mutable-borrows.rs diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs index 2a7a62cd64b59..0a7e9d0a82795 100644 --- a/src/librustc_mir/borrow_check.rs +++ b/src/librustc_mir/borrow_check.rs @@ -640,10 +640,12 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> Mutability::Mut => return, } } - Lvalue::Static(_) => { + Lvalue::Static(ref static_) => { // mutation of non-mut static is always illegal, // independent of dataflow. - self.report_assignment_to_static(context, (lvalue, span)); + if !self.tcx.is_static_mut(static_.def_id) { + self.report_assignment_to_static(context, (lvalue, span)); + } return; } } diff --git a/src/test/run-pass/borrowck/borrowck-unsafe-static-mutable-borrows.rs b/src/test/run-pass/borrowck/borrowck-unsafe-static-mutable-borrows.rs new file mode 100644 index 0000000000000..a4dd7b9b125c2 --- /dev/null +++ b/src/test/run-pass/borrowck/borrowck-unsafe-static-mutable-borrows.rs @@ -0,0 +1,31 @@ +// Copyright 2016 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. + +// revisions: ast mir +//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir + +// Test file taken from issue 45129 (https://github.com/rust-lang/rust/issues/45129) + +struct Foo { x: [usize; 2] } + +static mut SFOO: Foo = Foo { x: [23, 32] }; + +impl Foo { + fn x(&mut self) -> &mut usize { &mut self.x[0] } +} + +fn main() { + unsafe { + let sfoo: *mut Foo = &mut SFOO; + let x = (*sfoo).x(); + (*sfoo).x[1] += 1; + *x += 1; + } +} From c9d1db7bc5fe027e60370dae7c0c15671fa2b7ff Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Thu, 16 Nov 2017 15:32:13 -0800 Subject: [PATCH 2/3] Do not registor borrows for unsafe lvalues --- src/librustc_mir/dataflow/impls/borrows.rs | 58 ++++++++++++++++--- .../borrowck/borrowck-describe-lvalue.rs | 34 ----------- 2 files changed, 50 insertions(+), 42 deletions(-) diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 928c07b7fbc05..1e9d916def044 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -10,7 +10,7 @@ use rustc::mir::{self, Location, Mir}; use rustc::mir::visit::Visitor; -use rustc::ty::{Region, TyCtxt}; +use rustc::ty::{self, Region, TyCtxt}; use rustc::ty::RegionKind; use rustc::ty::RegionKind::ReScope; use rustc::util::nodemap::{FxHashMap, FxHashSet}; @@ -71,10 +71,14 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { mir: &'a Mir<'tcx>, nonlexical_regioncx: Option<&'a RegionInferenceContext<'tcx>>) -> Self { - let mut visitor = GatherBorrows { idx_vec: IndexVec::new(), - location_map: FxHashMap(), - region_map: FxHashMap(), - region_span_map: FxHashMap()}; + let mut visitor = GatherBorrows { + tcx, + mir, + idx_vec: IndexVec::new(), + location_map: FxHashMap(), + region_map: FxHashMap(), + region_span_map: FxHashMap() + }; visitor.visit_mir(mir); return Borrows { tcx: tcx, mir: mir, @@ -84,17 +88,22 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { region_span_map: visitor.region_span_map, nonlexical_regioncx }; - struct GatherBorrows<'tcx> { + struct GatherBorrows<'a, 'gcx: 'tcx, 'tcx: 'a> { + tcx: TyCtxt<'a, 'gcx, 'tcx>, + mir: &'a Mir<'tcx>, idx_vec: IndexVec>, location_map: FxHashMap, region_map: FxHashMap, FxHashSet>, region_span_map: FxHashMap, } - impl<'tcx> Visitor<'tcx> for GatherBorrows<'tcx> { + + impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> { fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: mir::Location) { if let mir::Rvalue::Ref(region, kind, ref lvalue) = *rvalue { + if is_unsafe_lvalue(self.tcx, self.mir, lvalue) { return; } + let borrow = BorrowData { location: location, kind: kind, region: region, lvalue: lvalue.clone(), }; @@ -197,7 +206,8 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> { } mir::StatementKind::Assign(_, ref rhs) => { - if let mir::Rvalue::Ref(region, _, _) = *rhs { + if let mir::Rvalue::Ref(region, _, ref lvalue) = *rhs { + if is_unsafe_lvalue(self.tcx, self.mir, lvalue) { return; } let index = self.location_map.get(&location).unwrap_or_else(|| { panic!("could not find BorrowIndex for location {:?}", location); }); @@ -248,3 +258,35 @@ impl<'a, 'gcx, 'tcx> DataflowOperator for Borrows<'a, 'gcx, 'tcx> { false // bottom = no Rvalue::Refs are active by default } } + +fn is_unsafe_lvalue<'a, 'gcx: 'tcx, 'tcx: 'a>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + mir: &'a Mir<'tcx>, + lvalue: &mir::Lvalue<'tcx> +) -> bool { + use self::mir::Lvalue::*; + use self::mir::ProjectionElem; + + match *lvalue { + Local(_) => false, + Static(ref static_) => tcx.is_static_mut(static_.def_id), + Projection(ref proj) => { + match proj.elem { + ProjectionElem::Field(..) | + ProjectionElem::Downcast(..) | + ProjectionElem::Subslice { .. } | + ProjectionElem::ConstantIndex { .. } | + ProjectionElem::Index(_) => { + is_unsafe_lvalue(tcx, mir, &proj.base) + } + ProjectionElem::Deref => { + let ty = proj.base.ty(mir, tcx).to_ty(tcx); + match ty.sty { + ty::TyRawPtr(..) => true, + _ => is_unsafe_lvalue(tcx, mir, &proj.base), + } + } + } + } + } +} diff --git a/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs index 06d61242ec2f8..d1cf08ac75463 100644 --- a/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs +++ b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs @@ -46,12 +46,6 @@ impl Baz { } } -static mut sfoo : Foo = Foo{x: 23 }; -static mut sbar : Bar = Bar(23); -static mut stuple : (i32, i32) = (24, 25); -static mut senum : Baz = Baz::X(26); -static mut sunion : U = U { a: 0 }; - fn main() { // Local and field from struct { @@ -96,34 +90,6 @@ fn main() { //[mir]~^ ERROR cannot use `u.a` because it was mutably borrowed (Ast) //[mir]~| ERROR cannot use `u.a` because it was mutably borrowed (Mir) } - // Static and field from struct - unsafe { - let _x = sfoo.x(); - sfoo.x; //[mir]~ ERROR cannot use `sfoo.x` because it was mutably borrowed (Mir) - } - // Static and field from tuple-struct - unsafe { - let _0 = sbar.x(); - sbar.0; //[mir]~ ERROR cannot use `sbar.0` because it was mutably borrowed (Mir) - } - // Static and field from tuple - unsafe { - let _0 = &mut stuple.0; - stuple.0; //[mir]~ ERROR cannot use `stuple.0` because it was mutably borrowed (Mir) - } - // Static and field from enum - unsafe { - let _e0 = senum.x(); - match senum { - Baz::X(value) => value - //[mir]~^ ERROR cannot use `senum.0` because it was mutably borrowed (Mir) - }; - } - // Static and field from union - unsafe { - let _ra = &mut sunion.a; - sunion.a; //[mir]~ ERROR cannot use `sunion.a` because it was mutably borrowed (Mir) - } // Deref and field from struct { let mut f = Box::new(Foo { x: 22 }); From f8ba371b1ef4337b2181a8f6cc45a66303eb48e3 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Fri, 17 Nov 2017 14:20:28 -0800 Subject: [PATCH 3/3] Add run-pass test for assignment to static mut --- .../borrowck-assignment-to-static-mut.rs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/test/run-pass/borrowck/borrowck-assignment-to-static-mut.rs diff --git a/src/test/run-pass/borrowck/borrowck-assignment-to-static-mut.rs b/src/test/run-pass/borrowck/borrowck-assignment-to-static-mut.rs new file mode 100644 index 0000000000000..b241cb4928915 --- /dev/null +++ b/src/test/run-pass/borrowck/borrowck-assignment-to-static-mut.rs @@ -0,0 +1,23 @@ +// Copyright 2016 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 taken from #45641 (https://github.com/rust-lang/rust/issues/45641) + +// ignore-tidy-linelength +// revisions: ast mir +//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir + +static mut Y: u32 = 0; + +unsafe fn should_ok() { + Y = 1; +} + +fn main() {} \ No newline at end of file