Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a Share kind #12686

Merged
merged 13 commits into from
Mar 20, 2014
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