Skip to content
Merged
4 changes: 2 additions & 2 deletions src/doc/guide-unsafe.md
Original file line number Diff line number Diff line change
Expand Up @@ -595,10 +595,10 @@ Other features provided by lang items include:
- stack unwinding and general failure; the `eh_personality`, `fail_`
and `fail_bounds_checks` lang items.
- the traits in `std::kinds` used to indicate types that satisfy
various kinds; lang items `send`, `freeze` and `pod`.
various kinds; lang items `send`, `share` and `pod`.
- the marker types and variance indicators found in
`std::kinds::markers`; lang items `covariant_type`,
`contravariant_lifetime`, `no_freeze_bound`, etc.
`contravariant_lifetime`, `no_share_bound`, etc.

Lang items are loaded lazily by the compiler; e.g. if one never uses
`~` then there is no need to define functions for `exchange_malloc`
Expand Down
4 changes: 4 additions & 0 deletions src/doc/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -2095,6 +2095,10 @@ and may not be overridden:
Types are sendable
unless they contain managed boxes, managed closures, or references.

* `Share` - Types that are *threadsafe*
These are types that are safe to be used across several threads with access to
a `&T` pointer. `MutexArc` is an example of a *sharable* type with internal mutable data.

* `Freeze` - Constant (immutable) types.
These are types that do not contain anything intrinsically mutable.
Intrinsically mutable values include `Cell` in the standard library.
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/metadata/tydecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,9 @@ fn parse_bounds(st: &mut PState, conv: conv_did) -> ty::ParamBounds {
'P' => {
param_bounds.builtin_bounds.add(ty::BoundPod);
}
'T' => {
param_bounds.builtin_bounds.add(ty::BoundShare);
}
'I' => {
param_bounds.trait_bounds.push(@parse_trait_ref(st, |x,y| conv(x,y)));
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc/metadata/tyencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ fn enc_bounds(w: &mut MemWriter, cx: &ctxt, bs: &ty::ParamBounds) {
ty::BoundStatic => mywrite!(w, "O"),
ty::BoundSized => mywrite!(w, "Z"),
ty::BoundPod => mywrite!(w, "P"),
ty::BoundShare => mywrite!(w, "T"),
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/borrowck/check_loans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -518,11 +518,11 @@ impl<'a> CheckLoanCtxt<'a> {
expr: &ast::Expr,
cmt: mc::cmt)
-> bool {
match cmt.freely_aliasable() {
match cmt.freely_aliasable(this.tcx()) {
None => {
return true;
}
Some(mc::AliasableStaticMut) => {
Some(mc::AliasableStaticMut(..)) => {
return true;
}
Some(cause) => {
Expand Down
118 changes: 71 additions & 47 deletions src/librustc/middle/borrowck/gather_loans/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,12 @@ impl<'a> visit::Visitor<()> for GatherLoanCtxt<'a> {
fn visit_block(&mut self, b: &Block, _: ()) {
gather_loans_in_block(self, b);
}
fn visit_fn(&mut self, fk: &FnKind, fd: &FnDecl, b: &Block,
s: Span, n: NodeId, _: ()) {
gather_loans_in_fn(self, fk, fd, b, s, n);
}

/// Do not visit closures or fn items here, the outer loop in
/// borrowck/mod will visit them for us in turn.
fn visit_fn(&mut self, _: &FnKind, _: &FnDecl, _: &Block,
_: Span, _: NodeId, _: ()) {}

fn visit_stmt(&mut self, s: &Stmt, _: ()) {
visit::walk_stmt(self, s, ());
}
Expand All @@ -99,10 +101,20 @@ impl<'a> visit::Visitor<()> for GatherLoanCtxt<'a> {
// #7740: Do not visit items here, not even fn items nor methods
// of impl items; the outer loop in borrowck/mod will visit them
// for us in turn. Thus override visit_item's walk with a no-op.
fn visit_item(&mut self, _: &ast::Item, _: ()) { }
fn visit_item(&mut self, _: &ast::Item, _: ()) {}
}

fn add_pat_to_id_range(this: &mut GatherLoanCtxt,
p: &ast::Pat) {
// NB: This visitor function just adds the pat ids into the id
// range. We gather loans that occur in patterns using the
// `gather_pat()` method below. Eventually these two should be
// brought together.
this.id_range.add(p.id);
visit::walk_pat(this, p, ());
}

pub fn gather_loans(bccx: &BorrowckCtxt, decl: &ast::FnDecl, body: &ast::Block)
pub fn gather_loans_in_fn(bccx: &BorrowckCtxt, decl: &ast::FnDecl, body: &ast::Block)
-> (IdRange, Vec<Loan>, move_data::MoveData) {
let mut glcx = GatherLoanCtxt {
bccx: bccx,
Expand All @@ -119,27 +131,6 @@ pub fn gather_loans(bccx: &BorrowckCtxt, decl: &ast::FnDecl, body: &ast::Block)
(id_range, all_loans, move_data)
}

fn add_pat_to_id_range(this: &mut GatherLoanCtxt,
p: &ast::Pat) {
// NB: This visitor function just adds the pat ids into the id
// range. We gather loans that occur in patterns using the
// `gather_pat()` method below. Eventually these two should be
// brought together.
this.id_range.add(p.id);
visit::walk_pat(this, p, ());
}

fn gather_loans_in_fn(_v: &mut GatherLoanCtxt,
_fk: &FnKind,
_decl: &ast::FnDecl,
_body: &ast::Block,
_sp: Span,
_id: ast::NodeId) {
// Do not visit closures or fn items here, the outer loop in
// borrowck/mod will visit them for us in turn.
return;
}

fn gather_loans_in_block(this: &mut GatherLoanCtxt,
blk: &ast::Block) {
this.id_range.add(blk.id);
Expand Down Expand Up @@ -171,6 +162,28 @@ 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) {
Expand Down Expand Up @@ -673,34 +686,45 @@ impl<'a> GatherLoanCtxt<'a> {
-> Result<(),()> {
//! Implements the A-* rules in doc.rs.

match req_kind {
ty::ImmBorrow => {
match (cmt.freely_aliasable(bccx.tcx), req_kind) {
(None, _) => {
/* Uniquely accessible path -- OK for `&` and `&mut` */
Ok(())
}

ty::UniqueImmBorrow | ty::MutBorrow => {
// Check for those cases where we cannot control
// the aliasing and make sure that we are not
// being asked to.
match cmt.freely_aliasable() {
None => {
Ok(())
(Some(mc::AliasableStatic(safety)), ty::ImmBorrow) => {
// Borrow of an immutable static item:
match safety {
mc::InteriorUnsafe => {
// If the static item contains an Unsafe<T>, 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(())
}
Some(mc::AliasableStaticMut) => {
// This is nasty, but we ignore the
// aliasing rules if the data is based in
// a `static mut`, since those are always
// unsafe. At your own peril and all that.
mc::InteriorSafe => {
// Immutable static can be borrowed, no problem.
Ok(())
}
Some(alias_cause) => {
bccx.report_aliasability_violation(
}
}
(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(())
}
}
Err(())
}
(_, _) => {
Ok(())
}
}
}
Expand Down
25 changes: 22 additions & 3 deletions src/librustc/middle/borrowck/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ impl<'a> Visitor<()> for BorrowckCtxt<'a> {
b: &Block, s: Span, n: NodeId, _: ()) {
borrowck_fn(self, fk, fd, b, s, n);
}

fn visit_item(&mut self, item: &ast::Item, _: ()) {
borrowck_item(self, item);
}
}

pub fn check_crate(tcx: &ty::ctxt,
Expand Down Expand Up @@ -117,6 +121,21 @@ pub fn check_crate(tcx: &ty::ctxt,
}
}

fn borrowck_item(this: &mut BorrowckCtxt, item: &ast::Item) {
// Gather loans for items. Note that we don't need
// to check loans for single expressions. The check
// loan step is intended for things that have a data
// flow dependent conditions.
match item.node {
ast::ItemStatic(_, _, ex) => {
gather_loans::gather_loans_in_static_initializer(this, ex);
}
_ => {
visit::walk_item(this, item, ());
}
}
}

fn borrowck_fn(this: &mut BorrowckCtxt,
fk: &FnKind,
decl: &ast::FnDecl,
Expand All @@ -127,7 +146,7 @@ fn borrowck_fn(this: &mut BorrowckCtxt,

// Check the body of fn items.
let (id_range, all_loans, move_data) =
gather_loans::gather_loans(this, decl, body);
gather_loans::gather_loans_in_fn(this, decl, body);
let mut loan_dfcx =
DataFlowContext::new(this.tcx,
this.method_map,
Expand Down Expand Up @@ -715,8 +734,8 @@ impl<'a> BorrowckCtxt<'a> {
span,
format!("{} in an aliasable location", prefix));
}
mc::AliasableStatic |
mc::AliasableStaticMut => {
mc::AliasableStatic(..) |
mc::AliasableStaticMut(..) => {
self.tcx.sess.span_err(
span,
format!("{} in a static location", prefix));
Expand Down
25 changes: 4 additions & 21 deletions src/librustc/middle/check_static.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@
// - For each *immutable* static item, it checks that its **value**:
// - doesn't own owned, managed pointers
// - doesn't contain a struct literal or a call to an enum variant / struct constructor where
// - the type of the struct/enum is not freeze
// - the type of the struct/enum has a dtor
//
// Rules Enforced Elsewhere:
// - It's not possible to take the address of a static item with unsafe interior. This is enforced
// by borrowck::gather_loans

use middle::ty;

Expand Down Expand Up @@ -121,21 +124,6 @@ impl<'a> Visitor<bool> for CheckStaticVisitor<'a> {
self.tcx.sess.span_err(e.span,
"static items are not allowed to have owned pointers");
}
ast::ExprProc(..) => {
self.report_error(e.span,
Some(~"immutable static items must be `Freeze`"));
return;
}
ast::ExprAddrOf(mutability, _) => {
match mutability {
ast::MutMutable => {
self.report_error(e.span,
Some(~"immutable static items must be `Freeze`"));
return;
}
_ => {}
}
}
_ => {
let node_ty = ty::node_id_to_type(self.tcx, e.id);

Expand All @@ -147,11 +135,6 @@ impl<'a> Visitor<bool> for CheckStaticVisitor<'a> {
Some(~"static items are not allowed to have destructors"));
return;
}
if Some(did) == self.tcx.lang_items.no_freeze_bound() {
self.report_error(e.span,
Some(~"immutable static items must be `Freeze`"));
return;
}
}
_ => {}
}
Expand Down
18 changes: 12 additions & 6 deletions src/librustc/middle/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

use driver::session::Session;
use metadata::csearch::each_lang_item;
use middle::ty::{BuiltinBound, BoundFreeze, BoundPod, BoundSend, BoundSized};
use middle::ty;
use syntax::ast;
use syntax::ast_util::local_def;
use syntax::attr::AttrMetaMethods;
Expand Down Expand Up @@ -82,15 +82,17 @@ impl LanguageItems {
}
}

pub fn to_builtin_kind(&self, id: ast::DefId) -> Option<BuiltinBound> {
pub fn to_builtin_kind(&self, id: ast::DefId) -> Option<ty::BuiltinBound> {
if Some(id) == self.freeze_trait() {
Some(BoundFreeze)
Some(ty::BoundFreeze)
} else if Some(id) == self.send_trait() {
Some(BoundSend)
Some(ty::BoundSend)
} else if Some(id) == self.sized_trait() {
Some(BoundSized)
Some(ty::BoundSized)
} else if Some(id) == self.pod_trait() {
Some(BoundPod)
Some(ty::BoundPod)
} else if Some(id) == self.share_trait() {
Some(ty::BoundShare)
} else {
None
}
Expand Down Expand Up @@ -213,6 +215,7 @@ lets_do_this! {
SendTraitLangItem, "send", send_trait;
SizedTraitLangItem, "sized", sized_trait;
PodTraitLangItem, "pod", pod_trait;
ShareTraitLangItem, "share", share_trait;

DropTraitLangItem, "drop", drop_trait;

Expand All @@ -230,6 +233,8 @@ lets_do_this! {
ShrTraitLangItem, "shr", shr_trait;
IndexTraitLangItem, "index", index_trait;

UnsafeTypeLangItem, "unsafe", unsafe_type;

DerefTraitLangItem, "deref", deref_trait;
DerefMutTraitLangItem, "deref_mut", deref_mut_trait;

Expand Down Expand Up @@ -274,5 +279,6 @@ lets_do_this! {
NoFreezeItem, "no_freeze_bound", no_freeze_bound;
NoSendItem, "no_send_bound", no_send_bound;
NoPodItem, "no_pod_bound", no_pod_bound;
NoShareItem, "no_share_bound", no_share_bound;
ManagedItem, "managed_bound", managed_bound;
}
Loading