diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index 8ecac0a60bede..efe9ebff61a42 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -161,29 +161,6 @@ fn gather_loans_in_local(this: &mut GatherLoanCtxt, visit::walk_local(this, local, ()); } -pub fn gather_loans_in_static_initializer(bccx: &mut BorrowckCtxt, expr: &ast::Expr) { - - debug!("gather_loans_in_item(expr={})", expr.repr(bccx.tcx)); - - let mut glcx = GatherLoanCtxt { - bccx: bccx, - id_range: IdRange::max(), - all_loans: Vec::new(), - item_ub: expr.id, - repeating_ids: vec!(expr.id), - move_data: MoveData::new() - }; - - // FIXME #13005 This should also walk the - // expression. - match expr.node { - ast::ExprAddrOf(..) => { - glcx.visit_expr(expr, ()); - } - _ => {} - } -} - fn gather_loans_in_expr(this: &mut GatherLoanCtxt, ex: &ast::Expr) { let bccx = this.bccx; @@ -326,6 +303,58 @@ fn with_assignee_loan_path(bccx: &BorrowckCtxt, expr: &ast::Expr, op: |@LoanPath } } + +/// Implements the A-* rules in doc.rs. +fn check_aliasability(bccx: &BorrowckCtxt, + borrow_span: Span, + loan_cause: LoanCause, + cmt: mc::cmt, + req_kind: ty::BorrowKind) + -> Result<(),()> { + + match (cmt.freely_aliasable(bccx.tcx), req_kind) { + (None, _) => { + /* Uniquely accessible path -- OK for `&` and `&mut` */ + Ok(()) + } + (Some(mc::AliasableStatic(safety)), ty::ImmBorrow) => { + // Borrow of an immutable static item: + match safety { + mc::InteriorUnsafe => { + // If the static item contains an Unsafe, it has interior mutability. + // In such cases, we cannot permit it to be borrowed, because the + // static item resides in immutable memory and mutating it would + // cause segfaults. + bccx.tcx.sess.span_err(borrow_span, + format!("borrow of immutable static items with \ + unsafe interior is not allowed")); + Err(()) + } + mc::InteriorSafe => { + // Immutable static can be borrowed, no problem. + Ok(()) + } + } + } + (Some(mc::AliasableStaticMut(..)), _) => { + // Even touching a static mut is considered unsafe. We assume the + // user knows what they're doing in these cases. + Ok(()) + } + (Some(alias_cause), ty::UniqueImmBorrow) | + (Some(alias_cause), ty::MutBorrow) => { + bccx.report_aliasability_violation( + borrow_span, + BorrowViolation(loan_cause), + alias_cause); + Err(()) + } + (_, _) => { + Ok(()) + } + } +} + impl<'a> GatherLoanCtxt<'a> { pub fn tcx(&self) -> &'a ty::ctxt { self.bccx.tcx } @@ -676,57 +705,6 @@ impl<'a> GatherLoanCtxt<'a> { } } } - - fn check_aliasability(bccx: &BorrowckCtxt, - borrow_span: Span, - loan_cause: LoanCause, - cmt: mc::cmt, - req_kind: ty::BorrowKind) - -> Result<(),()> { - //! Implements the A-* rules in doc.rs. - - match (cmt.freely_aliasable(bccx.tcx), req_kind) { - (None, _) => { - /* Uniquely accessible path -- OK for `&` and `&mut` */ - Ok(()) - } - (Some(mc::AliasableStatic(safety)), ty::ImmBorrow) => { - // Borrow of an immutable static item: - match safety { - mc::InteriorUnsafe => { - // If the static item contains an Unsafe, it has interior mutability. - // In such cases, we cannot permit it to be borrowed, because the - // static item resides in immutable memory and mutating it would - // cause segfaults. - bccx.tcx.sess.span_err(borrow_span, - format!("borrow of immutable static items with \ - unsafe interior is not allowed")); - Err(()) - } - mc::InteriorSafe => { - // Immutable static can be borrowed, no problem. - Ok(()) - } - } - } - (Some(mc::AliasableStaticMut(..)), _) => { - // Even touching a static mut is considered unsafe. We assume the - // user knows what they're doing in these cases. - Ok(()) - } - (Some(alias_cause), ty::UniqueImmBorrow) | - (Some(alias_cause), ty::MutBorrow) => { - bccx.report_aliasability_violation( - borrow_span, - BorrowViolation(loan_cause), - alias_cause); - Err(()) - } - (_, _) => { - Ok(()) - } - } - } } fn restriction_set(&self, req_kind: ty::BorrowKind) -> RestrictionSet { @@ -951,3 +929,44 @@ impl<'a> GatherLoanCtxt<'a> { pat_util::pat_is_binding(self.bccx.tcx.def_map, pat) } } + +/// Context used while gathering loans on static initializers +/// +/// This visitor walks static initializer's expressions and makes +/// sure the loans being taken are sound. +struct StaticInitializerCtxt<'a> { + bccx: &'a BorrowckCtxt<'a>, + id_range: IdRange, + item_ub: ast::NodeId, +} + +impl<'a> visit::Visitor<()> for StaticInitializerCtxt<'a> { + fn visit_expr(&mut self, ex: &Expr, _: ()) { + match ex.node { + ast::ExprAddrOf(mutbl, base) => { + let base_cmt = self.bccx.cat_expr(base); + let borrow_kind = ty::BorrowKind::from_mutbl(mutbl); + // Check that we don't allow borrows of unsafe static items. + if check_aliasability(self.bccx, ex.span, AddrOf, base_cmt, borrow_kind).is_err() { + return; // reported an error, no sense in reporting more. + } + } + _ => {} + } + + visit::walk_expr(self, ex, ()); + } +} + +pub fn gather_loans_in_static_initializer(bccx: &mut BorrowckCtxt, expr: &ast::Expr) { + + debug!("gather_loans_in_static_initializer(expr={})", expr.repr(bccx.tcx)); + + let mut sicx = StaticInitializerCtxt { + bccx: bccx, + id_range: IdRange::max(), + item_ub: expr.id, + }; + + sicx.visit_expr(expr, ()); +} diff --git a/src/test/compile-fail/borrowck-forbid-static-unsafe-interior.rs b/src/test/compile-fail/borrowck-forbid-static-unsafe-interior.rs index c790a040a91a4..9939fc791907d 100644 --- a/src/test/compile-fail/borrowck-forbid-static-unsafe-interior.rs +++ b/src/test/compile-fail/borrowck-forbid-static-unsafe-interior.rs @@ -35,6 +35,13 @@ static STATIC3: MyUnsafe = MyUnsafe{value: STATIC2}; static STATIC4: &'static Unsafe = &'static STATIC2; //~^ ERROR borrow of immutable static items with unsafe interior is not allowed +struct Wrap { + value: T +} + +static UNSAFE: Unsafe = Unsafe{value: 1, marker1: marker::InvariantType}; +static WRAPPED_UNSAFE: Wrap<&'static Unsafe> = Wrap { value: &UNSAFE }; +//~^ ERROR borrow of immutable static items with unsafe interior is not allowed fn main() { let a = &STATIC1;