auto merge of #12686 : FlaPer87/rust/shared, r=nikomatsakis

`Share` implies that all *reachable* content is *threadsafe*.

Threadsafe is defined as "exposing no operation that permits a data race if multiple threads have access to a &T pointer simultaneously". (NB: the type system should guarantee that if you have access to memory via a &T pointer, the only other way to gain access to that memory is through another &T pointer)...

Fixes #11781
cc #12577 

What this PR will do
================

- [x] Add Share kind and
- [x]  Replace usages of Freeze with Share in bounds.
- [x] Add Unsafe<T> #12577
- [x] Forbid taking the address of a immutable static item with `Unsafe<T>` interior

What's left to do in a separate PR (after the snapshot)?
===========================================

- Remove `Freeze` completely
This commit is contained in:
bors 2014-03-20 05:51:48 -07:00
commit 8e285208d5
40 changed files with 502 additions and 269 deletions

View File

@ -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`

View File

@ -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.

View File

@ -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)));
}

View File

@ -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"),
}
}

View File

@ -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) => {

View File

@ -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, ());
}
@ -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, _: ()) {}
}
pub fn gather_loans(bccx: &BorrowckCtxt, decl: &ast::FnDecl, body: &ast::Block)
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_in_fn(bccx: &BorrowckCtxt, decl: &ast::FnDecl, body: &ast::Block)
-> (IdRange, Vec<Loan>, move_data::MoveData) {
let mut glcx = GatherLoanCtxt {
bccx: bccx,
@ -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);
@ -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) {
@ -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 => {
(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(())
}
mc::InteriorSafe => {
// Immutable static can be borrowed, no problem.
Ok(())
}
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.
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(())
}
}
}

View File

@ -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,
@ -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,
@ -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,
@ -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));

View File

@ -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;
@ -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);
@ -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;
}
}
_ => {}
}

View File

@ -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;
@ -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
}
@ -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;
@ -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;
@ -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;
}

View File

@ -1222,12 +1222,17 @@ pub fn field_mutbl(tcx: &ty::ctxt,
return None;
}
pub enum InteriorSafety {
InteriorUnsafe,
InteriorSafe
}
pub enum AliasableReason {
AliasableManaged,
AliasableBorrowed,
AliasableOther,
AliasableStatic,
AliasableStaticMut,
AliasableStatic(InteriorSafety),
AliasableStaticMut(InteriorSafety),
}
impl cmt_ {
@ -1257,7 +1262,7 @@ impl cmt_ {
}
}
pub fn freely_aliasable(&self) -> Option<AliasableReason> {
pub fn freely_aliasable(&self, ctxt: &ty::ctxt) -> Option<AliasableReason> {
/*!
* Returns `Some(_)` if this lvalue represents a freely aliasable
* pointer type.
@ -1275,7 +1280,7 @@ impl cmt_ {
cat_interior(b, _) |
cat_discr(b, _) => {
// Aliasability depends on base cmt
b.freely_aliasable()
b.freely_aliasable(ctxt)
}
cat_copied_upvar(CopiedUpvar {onceness: ast::Once, ..}) |
@ -1292,10 +1297,16 @@ impl cmt_ {
}
cat_static_item(..) => {
if self.mutbl.is_mutable() {
Some(AliasableStaticMut)
let int_safe = if ty::type_interior_is_unsafe(ctxt, self.ty) {
InteriorUnsafe
} else {
Some(AliasableStatic)
InteriorSafe
};
if self.mutbl.is_mutable() {
Some(AliasableStaticMut(int_safe))
} else {
Some(AliasableStatic(int_safe))
}
}

View File

@ -850,6 +850,7 @@ pub enum BuiltinBound {
BoundFreeze,
BoundSized,
BoundPod,
BoundShare,
}
pub fn EmptyBuiltinBounds() -> BuiltinBounds {
@ -862,6 +863,7 @@ pub fn AllBuiltinBounds() -> BuiltinBounds {
set.add(BoundSend);
set.add(BoundFreeze);
set.add(BoundSized);
set.add(BoundShare);
set
}
@ -1872,31 +1874,33 @@ macro_rules! def_type_content_sets(
def_type_content_sets!(
mod TC {
None = 0b0000__00000000__0000,
None = 0b0000_0000__0000_0000__0000,
// Things that are interior to the value (first nibble):
InteriorUnsized = 0b0000__00000000__0001,
// InteriorAll = 0b0000__00000000__1111,
InteriorUnsized = 0b0000_0000__0000_0000__0001,
InteriorUnsafe = 0b0000_0000__0000_0000__0010,
// InteriorAll = 0b00000000__00000000__1111,
// Things that are owned by the value (second and third nibbles):
OwnsOwned = 0b0000__00000001__0000,
OwnsDtor = 0b0000__00000010__0000,
OwnsManaged /* see [1] below */ = 0b0000__00000100__0000,
OwnsAffine = 0b0000__00001000__0000,
OwnsAll = 0b0000__11111111__0000,
OwnsOwned = 0b0000_0000__0000_0001__0000,
OwnsDtor = 0b0000_0000__0000_0010__0000,
OwnsManaged /* see [1] below */ = 0b0000_0000__0000_0100__0000,
OwnsAffine = 0b0000_0000__0000_1000__0000,
OwnsAll = 0b0000_0000__1111_1111__0000,
// Things that are reachable by the value in any way (fourth nibble):
ReachesNonsendAnnot = 0b0001__00000000__0000,
ReachesBorrowed = 0b0010__00000000__0000,
// ReachesManaged /* see [1] below */ = 0b0100__00000000__0000,
ReachesMutable = 0b1000__00000000__0000,
ReachesAll = 0b1111__00000000__0000,
ReachesNonsendAnnot = 0b0000_0001__0000_0000__0000,
ReachesBorrowed = 0b0000_0010__0000_0000__0000,
// ReachesManaged /* see [1] below */ = 0b0000_0100__0000_0000__0000,
ReachesMutable = 0b0000_1000__0000_0000__0000,
ReachesNoShare = 0b0001_0000__0000_0000__0000,
ReachesAll = 0b0001_1111__0000_0000__0000,
// Things that cause values to *move* rather than *copy*
Moves = 0b0000__00001011__0000,
Moves = 0b0000_0000__0000_1011__0000,
// Things that mean drop glue is necessary
NeedsDrop = 0b0000__00000111__0000,
NeedsDrop = 0b0000_0000__0000_0111__0000,
// Things that prevent values from being sent
//
@ -1905,31 +1909,34 @@ def_type_content_sets!(
// both ReachesManaged and OwnsManaged so that when
// a parameter has a bound T:Send, we are able to deduce
// that it neither reaches nor owns a managed pointer.
Nonsendable = 0b0111__00000100__0000,
Nonsendable = 0b0000_0111__0000_0100__0000,
// Things that prevent values from being considered freezable
Nonfreezable = 0b1000__00000000__0000,
Nonfreezable = 0b0000_1000__0000_0000__0000,
// Things that prevent values from being considered 'static
Nonstatic = 0b0010__00000000__0000,
Nonstatic = 0b0000_0010__0000_0000__0000,
// Things that prevent values from being considered sized
Nonsized = 0b0000__00000000__0001,
Nonsized = 0b0000_0000__0000_0000__0001,
// Things that prevent values from being shared
Nonsharable = 0b0001_0000__0000_0000__0000,
// Things that make values considered not POD (would be same
// as `Moves`, but for the fact that managed data `@` is
// not considered POD)
Nonpod = 0b0000__00001111__0000,
Nonpod = 0b0000_0000__0000_1111__0000,
// Bits to set when a managed value is encountered
//
// [1] Do not set the bits TC::OwnsManaged or
// TC::ReachesManaged directly, instead reference
// TC::Managed to set them both at once.
Managed = 0b0100__00000100__0000,
Managed = 0b0000_0100__0000_0100__0000,
// All bits
All = 0b1111__11111111__1111
All = 0b1111_1111__1111_1111__1111
}
)
@ -1945,6 +1952,7 @@ impl TypeContents {
BoundSend => self.is_sendable(cx),
BoundSized => self.is_sized(cx),
BoundPod => self.is_pod(cx),
BoundShare => self.is_sharable(cx),
}
}
@ -1964,6 +1972,10 @@ impl TypeContents {
!self.intersects(TC::Nonsendable)
}
pub fn is_sharable(&self, _: &ctxt) -> bool {
!self.intersects(TC::Nonsharable)
}
pub fn owns_managed(&self) -> bool {
self.intersects(TC::OwnsManaged)
}
@ -1984,6 +1996,10 @@ impl TypeContents {
!self.intersects(TC::Nonpod)
}
pub fn interior_unsafe(&self) -> bool {
self.intersects(TC::InteriorUnsafe)
}
pub fn moves_by_default(&self, _: &ctxt) -> bool {
self.intersects(TC::Moves)
}
@ -2080,6 +2096,10 @@ pub fn type_is_freezable(cx: &ctxt, t: ty::t) -> bool {
type_contents(cx, t).is_freezable(cx)
}
pub fn type_interior_is_unsafe(cx: &ctxt, t: ty::t) -> bool {
type_contents(cx, t).interior_unsafe()
}
pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
let ty_id = type_id(ty);
@ -2284,6 +2304,10 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
tc | TC::Managed
} else if Some(did) == cx.lang_items.no_pod_bound() {
tc | TC::OwnsAffine
} else if Some(did) == cx.lang_items.no_share_bound() {
tc | TC::ReachesNoShare
} else if Some(did) == cx.lang_items.unsafe_type() {
tc | TC::InteriorUnsafe
} else {
tc
}
@ -2362,6 +2386,7 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
BoundFreeze => TC::Nonfreezable,
BoundSized => TC::Nonsized,
BoundPod => TC::Nonpod,
BoundShare => TC::Nonsharable,
};
});
return tc;

View File

@ -674,6 +674,7 @@ impl Repr for ty::ParamBounds {
ty::BoundFreeze => ~"Freeze",
ty::BoundSized => ~"Sized",
ty::BoundPod => ~"Pod",
ty::BoundShare => ~"Share",
});
}
for t in self.trait_bounds.iter() {
@ -961,6 +962,7 @@ impl UserString for ty::BuiltinBound {
ty::BoundFreeze => ~"Freeze",
ty::BoundSized => ~"Sized",
ty::BoundPod => ~"Pod",
ty::BoundShare => ~"Share",
}
}
}

View File

@ -17,35 +17,38 @@ use fmt;
use kinds::{marker, Pod};
use ops::{Deref, DerefMut, Drop};
use option::{None, Option, Some};
use ty::Unsafe;
/// A mutable memory location that admits only `Pod` data.
pub struct Cell<T> {
priv value: T,
priv value: Unsafe<T>,
priv marker1: marker::InvariantType<T>,
priv marker2: marker::NoFreeze,
priv marker3: marker::NoShare,
}
impl<T:Pod> Cell<T> {
/// Creates a new `Cell` containing the given value.
pub fn new(value: T) -> Cell<T> {
Cell {
value: value,
value: Unsafe{value: value, marker1: marker::InvariantType::<T>},
marker1: marker::InvariantType::<T>,
marker2: marker::NoFreeze,
marker3: marker::NoShare,
}
}
/// Returns a copy of the contained value.
#[inline]
pub fn get(&self) -> T {
self.value
unsafe{ *self.value.get() }
}
/// Sets the contained value.
#[inline]
pub fn set(&self, value: T) {
unsafe {
*cast::transmute_mut(&self.value) = value
*self.value.get() = value;
}
}
}
@ -64,17 +67,18 @@ impl<T:Eq + Pod> Eq for Cell<T> {
impl<T: fmt::Show> fmt::Show for Cell<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f.buf, r"Cell \{ value: {} \}", self.value)
write!(f.buf, r"Cell \{ value: {} \}", unsafe{*&self.value.get()})
}
}
/// A mutable memory location with dynamically checked borrow rules
pub struct RefCell<T> {
priv value: T,
priv value: Unsafe<T>,
priv borrow: BorrowFlag,
priv marker1: marker::InvariantType<T>,
priv marker2: marker::NoFreeze,
priv marker3: marker::NoPod,
priv marker4: marker::NoShare,
}
// Values [1, MAX-1] represent the number of `Ref` active
@ -90,7 +94,8 @@ impl<T> RefCell<T> {
marker1: marker::InvariantType::<T>,
marker2: marker::NoFreeze,
marker3: marker::NoPod,
value: value,
marker4: marker::NoShare,
value: Unsafe{value: value, marker1: marker::InvariantType::<T>},
borrow: UNUSED,
}
}
@ -98,7 +103,7 @@ impl<T> RefCell<T> {
/// Consumes the `RefCell`, returning the wrapped value.
pub fn unwrap(self) -> T {
assert!(self.borrow == UNUSED);
self.value
unsafe{self.value.unwrap()}
}
unsafe fn as_mut<'a>(&'a self) -> &'a mut RefCell<T> {
@ -198,7 +203,7 @@ impl<T> RefCell<T> {
#[inline]
pub fn set(&self, value: T) {
let mut reference = self.borrow_mut();
*reference.get() = value
*reference.get() = value;
}
}
@ -247,14 +252,14 @@ impl<'b, T> Ref<'b, T> {
/// Retrieve an immutable reference to the stored value.
#[inline]
pub fn get<'a>(&'a self) -> &'a T {
&self.parent.value
unsafe{ &*self.parent.value.get() }
}
}
impl<'b, T> Deref<T> for Ref<'b, T> {
#[inline]
fn deref<'a>(&'a self) -> &'a T {
&self.parent.value
unsafe{ &*self.parent.value.get() }
}
}
@ -275,21 +280,21 @@ impl<'b, T> RefMut<'b, T> {
/// Retrieve a mutable reference to the stored value.
#[inline]
pub fn get<'a>(&'a mut self) -> &'a mut T {
&mut self.parent.value
unsafe{ &mut *self.parent.value.get() }
}
}
impl<'b, T> Deref<T> for RefMut<'b, T> {
#[inline]
fn deref<'a>(&'a self) -> &'a T {
&self.parent.value
unsafe{ &*self.parent.value.get() }
}
}
impl<'b, T> DerefMut<T> for RefMut<'b, T> {
#[inline]
fn deref_mut<'a>(&'a mut self) -> &'a mut T {
&mut self.parent.value
unsafe{ &mut *self.parent.value.get() }
}
}

View File

@ -46,6 +46,22 @@ pub trait Pod {
// Empty.
}
/// Types that can be safely shared between threads, hence thread-safe.
#[cfg(stage0)]
pub trait Share {
// Empty
}
#[cfg(stage0)]
impl<T> Share for T {}
/// Types that can be safely shared between threads, hence thread-safe.
#[cfg(not(stage0))]
#[lang="share"]
pub trait Share {
// Empty
}
/// Marker types are special types that are used with unsafe code to
/// inform the compiler of special constraints. Marker types should
/// only be needed when you are creating an abstraction that is
@ -232,6 +248,13 @@ pub mod marker {
#[deriving(Eq,Clone)]
pub struct NoPod;
/// A type which is considered "not sharable", meaning that
/// its contents are not threadsafe, hence they cannot be
/// shared between tasks.
#[lang="no_share_bound"]
#[deriving(Eq,Clone)]
pub struct NoShare;
/// A type which is considered managed by the GC. This is typically
/// embedded in other types.
#[lang="managed_bound"]

View File

@ -83,6 +83,7 @@
#[cfg(test)] pub use kinds = realstd::kinds;
#[cfg(test)] pub use ops = realstd::ops;
#[cfg(test)] pub use cmp = realstd::cmp;
#[cfg(test)] pub use ty = realstd::ty;
#[cfg(stage0)]
pub use vec_ng = vec;
@ -141,6 +142,7 @@ pub mod gc;
#[cfg(not(test))] pub mod kinds;
#[cfg(not(test))] pub mod ops;
#[cfg(not(test))] pub mod cmp;
#[cfg(not(test))] pub mod ty;
/* Common traits */
@ -229,5 +231,6 @@ mod std {
pub use rt;
pub use str;
pub use to_str;
pub use ty;
pub use unstable;
}

View File

@ -20,7 +20,7 @@ generally useful to many Rust programs.
*/
// Reexported core operators
pub use kinds::{Freeze, Pod, Send, Sized};
pub use kinds::{Freeze, Pod, Send, Sized, Share};
pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not};
pub use ops::{BitAnd, BitOr, BitXor};
pub use ops::{Drop, Deref, DerefMut};

View File

@ -42,7 +42,8 @@ struct RcBox<T> {
#[unsafe_no_drop_flag]
pub struct Rc<T> {
priv ptr: *mut RcBox<T>,
priv marker: marker::NoSend
priv nosend: marker::NoSend,
priv noshare: marker::NoShare
}
impl<T> Rc<T> {
@ -56,7 +57,8 @@ impl<T> Rc<T> {
// strong destructor is running, even if the weak
// pointer is stored inside the strong one.
ptr: transmute(~RcBox { value: value, strong: 1, weak: 1 }),
marker: marker::NoSend,
nosend: marker::NoSend,
noshare: marker::NoShare
}
}
}
@ -67,7 +69,11 @@ impl<T> Rc<T> {
pub fn downgrade(&self) -> Weak<T> {
unsafe {
(*self.ptr).weak += 1;
Weak { ptr: self.ptr, marker: marker::NoSend }
Weak {
ptr: self.ptr,
nosend: marker::NoSend,
noshare: marker::NoShare
}
}
}
}
@ -107,7 +113,7 @@ impl<T> Clone for Rc<T> {
fn clone(&self) -> Rc<T> {
unsafe {
(*self.ptr).strong += 1;
Rc { ptr: self.ptr, marker: marker::NoSend }
Rc { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare }
}
}
}
@ -138,7 +144,8 @@ impl<T: Ord> Ord for Rc<T> {
#[unsafe_no_drop_flag]
pub struct Weak<T> {
priv ptr: *mut RcBox<T>,
priv marker: marker::NoSend
priv nosend: marker::NoSend,
priv noshare: marker::NoShare
}
impl<T> Weak<T> {
@ -149,7 +156,7 @@ impl<T> Weak<T> {
None
} else {
(*self.ptr).strong += 1;
Some(Rc { ptr: self.ptr, marker: marker::NoSend })
Some(Rc { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare })
}
}
}
@ -176,7 +183,7 @@ impl<T> Clone for Weak<T> {
fn clone(&self) -> Weak<T> {
unsafe {
(*self.ptr).weak += 1;
Weak { ptr: self.ptr, marker: marker::NoSend }
Weak { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare }
}
}
}

View File

@ -28,6 +28,7 @@ use ops::Drop;
use ptr::RawPtr;
use sync::atomics::{fence, AtomicUint, Relaxed, Acquire, Release};
use slice;
use ty::Unsafe;
/// An atomically reference counted pointer.
///
@ -39,11 +40,14 @@ pub struct UnsafeArc<T> {
struct ArcData<T> {
count: AtomicUint,
data: T,
data: Unsafe<T>,
}
unsafe fn new_inner<T: Send>(data: T, refcount: uint) -> *mut ArcData<T> {
let data = ~ArcData { count: AtomicUint::new(refcount), data: data };
let data = ~ArcData {
count: AtomicUint::new(refcount),
data: Unsafe::new(data)
};
cast::transmute(data)
}
@ -82,7 +86,7 @@ impl<T: Send> UnsafeArc<T> {
unsafe {
// FIXME(#12049): this needs some sort of debug assertion
if cfg!(test) { assert!((*self.data).count.load(Relaxed) > 0); }
return &mut (*self.data).data as *mut T;
return (*self.data).data.get();
}
}
@ -93,7 +97,7 @@ impl<T: Send> UnsafeArc<T> {
unsafe {
// FIXME(#12049): this needs some sort of debug assertion
if cfg!(test) { assert!((*self.data).count.load(Relaxed) > 0); }
return &(*self.data).data as *T;
return (*self.data).data.get() as *T;
}
}

View File

@ -114,35 +114,36 @@ use cast;
use std::kinds::marker;
use option::{Option,Some,None};
use ops::Drop;
use ty::Unsafe;
/// An atomic boolean type.
pub struct AtomicBool {
priv v: uint,
priv v: Unsafe<uint>,
priv nopod: marker::NoPod
}
/// A signed atomic integer type, supporting basic atomic arithmetic operations
pub struct AtomicInt {
priv v: int,
priv v: Unsafe<int>,
priv nopod: marker::NoPod
}
/// An unsigned atomic integer type, supporting basic atomic arithmetic operations
pub struct AtomicUint {
priv v: uint,
priv v: Unsafe<uint>,
priv nopod: marker::NoPod
}
/// An unsigned atomic integer type that is forced to be 64-bits. This does not
/// support all operations.
pub struct AtomicU64 {
priv v: u64,
priv v: Unsafe<u64>,
priv nopod: marker::NoPod
}
/// An unsafe atomic pointer. Only supports basic atomic operations
pub struct AtomicPtr<T> {
priv p: uint,
priv p: Unsafe<uint>,
priv nopod: marker::NoPod
}
@ -152,7 +153,7 @@ pub struct AtomicPtr<T> {
/// owned heap objects across tasks.
#[unsafe_no_drop_flag]
pub struct AtomicOption<T> {
priv p: uint,
priv p: Unsafe<uint>,
}
/// Atomic memory orderings
@ -186,13 +187,21 @@ pub enum Ordering {
}
/// An `AtomicBool` initialized to `false`
pub static INIT_ATOMIC_BOOL : AtomicBool = AtomicBool { v: 0, nopod: marker::NoPod };
pub static INIT_ATOMIC_BOOL : AtomicBool = AtomicBool { v: Unsafe{value: 0,
marker1: marker::InvariantType},
nopod: marker::NoPod };
/// An `AtomicInt` initialized to `0`
pub static INIT_ATOMIC_INT : AtomicInt = AtomicInt { v: 0, nopod: marker::NoPod };
pub static INIT_ATOMIC_INT : AtomicInt = AtomicInt { v: Unsafe{value: 0,
marker1: marker::InvariantType},
nopod: marker::NoPod };
/// An `AtomicUint` initialized to `0`
pub static INIT_ATOMIC_UINT : AtomicUint = AtomicUint { v: 0, nopod: marker::NoPod };
pub static INIT_ATOMIC_UINT : AtomicUint = AtomicUint { v: Unsafe{value: 0,
marker1: marker::InvariantType},
nopod: marker::NoPod };
/// An `AtomicU64` initialized to `0`
pub static INIT_ATOMIC_U64 : AtomicU64 = AtomicU64 { v: 0, nopod: marker::NoPod };
pub static INIT_ATOMIC_U64 : AtomicU64 = AtomicU64 { v: Unsafe{value: 0,
marker1: marker::InvariantType},
nopod: marker::NoPod };
// NB: Needs to be -1 (0b11111111...) to make fetch_nand work correctly
@ -201,13 +210,14 @@ static UINT_TRUE: uint = -1;
impl AtomicBool {
/// Create a new `AtomicBool`
pub fn new(v: bool) -> AtomicBool {
AtomicBool { v: if v { UINT_TRUE } else { 0 }, nopod: marker::NoPod }
let val = if v { UINT_TRUE } else { 0 };
AtomicBool { v: Unsafe::new(val), nopod: marker::NoPod }
}
/// Load the value
#[inline]
pub fn load(&self, order: Ordering) -> bool {
unsafe { atomic_load(&self.v, order) > 0 }
unsafe { atomic_load(&*self.v.get(), order) > 0 }
}
/// Store the value
@ -215,7 +225,7 @@ impl AtomicBool {
pub fn store(&mut self, val: bool, order: Ordering) {
let val = if val { UINT_TRUE } else { 0 };
unsafe { atomic_store(&mut self.v, val, order); }
unsafe { atomic_store(&mut *self.v.get(), val, order); }
}
/// Store a value, returning the old value
@ -223,7 +233,7 @@ impl AtomicBool {
pub fn swap(&mut self, val: bool, order: Ordering) -> bool {
let val = if val { UINT_TRUE } else { 0 };
unsafe { atomic_swap(&mut self.v, val, order) > 0 }
unsafe { atomic_swap(&mut *self.v.get(), val, order) > 0 }
}
/// If the current value is the same as expected, store a new value
@ -276,7 +286,7 @@ impl AtomicBool {
let old = if old { UINT_TRUE } else { 0 };
let new = if new { UINT_TRUE } else { 0 };
unsafe { atomic_compare_and_swap(&mut self.v, old, new, order) > 0 }
unsafe { atomic_compare_and_swap(&mut *self.v.get(), old, new, order) > 0 }
}
/// A logical "and" operation
@ -306,7 +316,7 @@ impl AtomicBool {
pub fn fetch_and(&mut self, val: bool, order: Ordering) -> bool {
let val = if val { UINT_TRUE } else { 0 };
unsafe { atomic_and(&mut self.v, val, order) > 0 }
unsafe { atomic_and(&mut *self.v.get(), val, order) > 0 }
}
/// A logical "nand" operation
@ -337,7 +347,7 @@ impl AtomicBool {
pub fn fetch_nand(&mut self, val: bool, order: Ordering) -> bool {
let val = if val { UINT_TRUE } else { 0 };
unsafe { atomic_nand(&mut self.v, val, order) > 0 }
unsafe { atomic_nand(&mut *self.v.get(), val, order) > 0 }
}
/// A logical "or" operation
@ -367,7 +377,7 @@ impl AtomicBool {
pub fn fetch_or(&mut self, val: bool, order: Ordering) -> bool {
let val = if val { UINT_TRUE } else { 0 };
unsafe { atomic_or(&mut self.v, val, order) > 0 }
unsafe { atomic_or(&mut *self.v.get(), val, order) > 0 }
}
/// A logical "xor" operation
@ -397,32 +407,32 @@ impl AtomicBool {
pub fn fetch_xor(&mut self, val: bool, order: Ordering) -> bool {
let val = if val { UINT_TRUE } else { 0 };
unsafe { atomic_xor(&mut self.v, val, order) > 0 }
unsafe { atomic_xor(&mut *self.v.get(), val, order) > 0 }
}
}
impl AtomicInt {
/// Create a new `AtomicInt`
pub fn new(v: int) -> AtomicInt {
AtomicInt { v:v, nopod: marker::NoPod}
AtomicInt {v: Unsafe::new(v), nopod: marker::NoPod}
}
/// Load the value
#[inline]
pub fn load(&self, order: Ordering) -> int {
unsafe { atomic_load(&self.v, order) }
unsafe { atomic_load(&*self.v.get(), order) }
}
/// Store the value
#[inline]
pub fn store(&mut self, val: int, order: Ordering) {
unsafe { atomic_store(&mut self.v, val, order); }
unsafe { atomic_store(&mut *self.v.get(), val, order); }
}
/// Store a value, returning the old value
#[inline]
pub fn swap(&mut self, val: int, order: Ordering) -> int {
unsafe { atomic_swap(&mut self.v, val, order) }
unsafe { atomic_swap(&mut *self.v.get(), val, order) }
}
/// If the current value is the same as expected, store a new value
@ -432,7 +442,7 @@ impl AtomicInt {
/// If the return value is equal to `old` then the value was updated.
#[inline]
pub fn compare_and_swap(&mut self, old: int, new: int, order: Ordering) -> int {
unsafe { atomic_compare_and_swap(&mut self.v, old, new, order) }
unsafe { atomic_compare_and_swap(&mut *self.v.get(), old, new, order) }
}
/// Add to the current value, returning the previous
@ -448,7 +458,7 @@ impl AtomicInt {
/// ```
#[inline]
pub fn fetch_add(&mut self, val: int, order: Ordering) -> int {
unsafe { atomic_add(&mut self.v, val, order) }
unsafe { atomic_add(&mut *self.v.get(), val, order) }
}
/// Subtract from the current value, returning the previous
@ -464,7 +474,7 @@ impl AtomicInt {
/// ```
#[inline]
pub fn fetch_sub(&mut self, val: int, order: Ordering) -> int {
unsafe { atomic_sub(&mut self.v, val, order) }
unsafe { atomic_sub(&mut *self.v.get(), val, order) }
}
}
@ -474,62 +484,62 @@ impl AtomicInt {
#[cfg(not(target_arch = "mips"))]
impl AtomicU64 {
pub fn new(v: u64) -> AtomicU64 {
AtomicU64 { v:v, nopod: marker::NoPod }
AtomicU64 { v: Unsafe::new(v), nopod: marker::NoPod }
}
#[inline]
pub fn load(&self, order: Ordering) -> u64 {
unsafe { atomic_load(&self.v, order) }
unsafe { atomic_load(&*self.v.get(), order) }
}
#[inline]
pub fn store(&mut self, val: u64, order: Ordering) {
unsafe { atomic_store(&mut self.v, val, order); }
unsafe { atomic_store(&mut *self.v.get(), val, order); }
}
#[inline]
pub fn swap(&mut self, val: u64, order: Ordering) -> u64 {
unsafe { atomic_swap(&mut self.v, val, order) }
unsafe { atomic_swap(&mut *self.v.get(), val, order) }
}
#[inline]
pub fn compare_and_swap(&mut self, old: u64, new: u64, order: Ordering) -> u64 {
unsafe { atomic_compare_and_swap(&mut self.v, old, new, order) }
unsafe { atomic_compare_and_swap(&mut *self.v.get(), old, new, order) }
}
#[inline]
pub fn fetch_add(&mut self, val: u64, order: Ordering) -> u64 {
unsafe { atomic_add(&mut self.v, val, order) }
unsafe { atomic_add(&mut *self.v.get(), val, order) }
}
#[inline]
pub fn fetch_sub(&mut self, val: u64, order: Ordering) -> u64 {
unsafe { atomic_sub(&mut self.v, val, order) }
unsafe { atomic_sub(&mut *self.v.get(), val, order) }
}
}
impl AtomicUint {
/// Create a new `AtomicUint`
pub fn new(v: uint) -> AtomicUint {
AtomicUint { v:v, nopod: marker::NoPod }
AtomicUint { v: Unsafe::new(v), nopod: marker::NoPod }
}
/// Load the value
#[inline]
pub fn load(&self, order: Ordering) -> uint {
unsafe { atomic_load(&self.v, order) }
unsafe { atomic_load(&*self.v.get(), order) }
}
/// Store the value
#[inline]
pub fn store(&mut self, val: uint, order: Ordering) {
unsafe { atomic_store(&mut self.v, val, order); }
unsafe { atomic_store(&mut *self.v.get(), val, order); }
}
/// Store a value, returning the old value
#[inline]
pub fn swap(&mut self, val: uint, order: Ordering) -> uint {
unsafe { atomic_swap(&mut self.v, val, order) }
unsafe { atomic_swap(&mut *self.v.get(), val, order) }
}
/// If the current value is the same as expected, store a new value
@ -539,7 +549,7 @@ impl AtomicUint {
/// If the return value is equal to `old` then the value was updated.
#[inline]
pub fn compare_and_swap(&mut self, old: uint, new: uint, order: Ordering) -> uint {
unsafe { atomic_compare_and_swap(&mut self.v, old, new, order) }
unsafe { atomic_compare_and_swap(&mut *self.v.get(), old, new, order) }
}
/// Add to the current value, returning the previous
@ -555,7 +565,7 @@ impl AtomicUint {
/// ```
#[inline]
pub fn fetch_add(&mut self, val: uint, order: Ordering) -> uint {
unsafe { atomic_add(&mut self.v, val, order) }
unsafe { atomic_add(&mut *self.v.get(), val, order) }
}
/// Subtract from the current value, returning the previous
@ -571,34 +581,34 @@ impl AtomicUint {
/// ```
#[inline]
pub fn fetch_sub(&mut self, val: uint, order: Ordering) -> uint {
unsafe { atomic_sub(&mut self.v, val, order) }
unsafe { atomic_sub(&mut *self.v.get(), val, order) }
}
}
impl<T> AtomicPtr<T> {
/// Create a new `AtomicPtr`
pub fn new(p: *mut T) -> AtomicPtr<T> {
AtomicPtr { p: p as uint, nopod: marker::NoPod }
AtomicPtr { p: Unsafe::new(p as uint), nopod: marker::NoPod }
}
/// Load the value
#[inline]
pub fn load(&self, order: Ordering) -> *mut T {
unsafe {
atomic_load(&self.p, order) as *mut T
atomic_load(&*self.p.get(), order) as *mut T
}
}
/// Store the value
#[inline]
pub fn store(&mut self, ptr: *mut T, order: Ordering) {
unsafe { atomic_store(&mut self.p, ptr as uint, order); }
unsafe { atomic_store(&mut *self.p.get(), ptr as uint, order); }
}
/// Store a value, returning the old value
#[inline]
pub fn swap(&mut self, ptr: *mut T, order: Ordering) -> *mut T {
unsafe { atomic_swap(&mut self.p, ptr as uint, order) as *mut T }
unsafe { atomic_swap(&mut *self.p.get(), ptr as uint, order) as *mut T }
}
/// If the current value is the same as expected, store a new value
@ -609,7 +619,7 @@ impl<T> AtomicPtr<T> {
#[inline]
pub fn compare_and_swap(&mut self, old: *mut T, new: *mut T, order: Ordering) -> *mut T {
unsafe {
atomic_compare_and_swap(&mut self.p, old as uint,
atomic_compare_and_swap(&mut *self.p.get(), old as uint,
new as uint, order) as *mut T
}
}
@ -618,11 +628,11 @@ impl<T> AtomicPtr<T> {
impl<T> AtomicOption<T> {
/// Create a new `AtomicOption`
pub fn new(p: ~T) -> AtomicOption<T> {
unsafe { AtomicOption { p: cast::transmute(p) } }
unsafe { AtomicOption { p: Unsafe::new(cast::transmute(p)) } }
}
/// Create a new `AtomicOption` that doesn't contain a value
pub fn empty() -> AtomicOption<T> { AtomicOption { p: 0 } }
pub fn empty() -> AtomicOption<T> { AtomicOption { p: Unsafe::new(0) } }
/// Store a value, returning the old value
#[inline]
@ -630,7 +640,7 @@ impl<T> AtomicOption<T> {
unsafe {
let val = cast::transmute(val);
let p = atomic_swap(&mut self.p, val, order);
let p = atomic_swap(&mut *self.p.get(), val, order);
if p as uint == 0 {
None
} else {
@ -655,7 +665,7 @@ impl<T> AtomicOption<T> {
unsafe {
let val = cast::transmute(val);
let expected = cast::transmute(0);
let oldval = atomic_compare_and_swap(&mut self.p, expected, val, order);
let oldval = atomic_compare_and_swap(&mut *self.p.get(), expected, val, order);
if oldval == expected {
None
} else {
@ -670,7 +680,7 @@ impl<T> AtomicOption<T> {
/// result does not get invalidated by another task after this returns.
#[inline]
pub fn is_empty(&mut self, order: Ordering) -> bool {
unsafe { atomic_load(&self.p, order) as uint == 0 }
unsafe { atomic_load(&*self.p.get(), order) as uint == 0 }
}
}

82
src/libstd/ty.rs Normal file
View File

@ -0,0 +1,82 @@
// Copyright 2012-2013 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Types dealing with unsafe actions.
use cast;
use kinds::marker;
/// Unsafe type that wraps a type T and indicates unsafe interior operations on the
/// wrapped type. Types with an `Unsafe<T>` field are considered to have an *unsafe
/// interior*. The Unsafe type is the only legal way to obtain aliasable data that is
/// considered mutable. In general, transmuting an &T type into an &mut T is considered
/// undefined behavior.
///
/// Although it is possible to put an Unsafe<T> into static item, it is not permitted to
/// take the address of the static item if the item is not declared as mutable. This rule
/// exists because immutable static items are stored in read-only memory, and thus any
/// attempt to mutate their interior can cause segfaults. Immutable static items containing
/// Unsafe<T> instances are still useful as read-only initializers, however, so we do not
/// forbid them altogether.
///
/// Types like `Cell` and `RefCell` use this type to wrap their internal data.
///
/// Unsafe doesn't opt-out from any kind, instead, types with an `Unsafe` interior
/// are expected to opt-out from kinds themselves.
///
/// # Example:
///
/// ```rust
/// use std::ty::Unsafe;
/// use std::kinds::marker;
///
/// struct NotThreadSafe<T> {
/// value: Unsafe<T>,
/// marker1: marker::NoShare
/// }
/// ```
///
/// **NOTE:** Unsafe<T> fields are public to allow static initializers. It is not recommended
/// to access its fields directly, `get` should be used instead.
#[cfg(not(stage0))]
#[lang="unsafe"]
pub struct Unsafe<T> {
/// Wrapped value
value: T,
/// Invariance marker
marker1: marker::InvariantType<T>
}
/// Unsafe type for stage0
#[cfg(stage0)]
pub struct Unsafe<T> {
/// Wrapped value
value: T,
/// Invariance marker
marker1: marker::InvariantType<T>
}
impl<T> Unsafe<T> {
/// Static constructor
pub fn new(value: T) -> Unsafe<T> {
Unsafe{value: value, marker1: marker::InvariantType}
}
/// Gets a mutable pointer to the wrapped value
#[inline]
pub unsafe fn get(&self) -> *mut T { cast::transmute(&self.value) }
/// Unwraps the value
#[inline]
pub unsafe fn unwrap(self) -> T { self.value }
}

View File

@ -54,6 +54,9 @@ use std::kinds::marker;
use std::sync::arc::UnsafeArc;
use std::task;
#[cfg(stage0)]
use std::kinds::Share;
/// As sync::condvar, a mechanism for unlock-and-descheduling and
/// signaling, for use with the Arc types.
pub struct ArcCondvar<'a> {
@ -122,7 +125,7 @@ pub struct Arc<T> { priv x: UnsafeArc<T> }
* Access the underlying data in an atomically reference counted
* wrapper.
*/
impl<T:Freeze+Send> Arc<T> {
impl<T: Share + Send> Arc<T> {
/// Create an atomically reference counted wrapper.
#[inline]
pub fn new(data: T) -> Arc<T> {
@ -135,7 +138,7 @@ impl<T:Freeze+Send> Arc<T> {
}
}
impl<T:Freeze + Send> Clone for Arc<T> {
impl<T: Share + Send> Clone for Arc<T> {
/**
* Duplicate an atomically reference counted wrapper.
*
@ -295,19 +298,21 @@ struct RWArcInner<T> { lock: RWLock, failed: bool, data: T }
pub struct RWArc<T> {
priv x: UnsafeArc<RWArcInner<T>>,
priv marker: marker::NoFreeze,
priv marker1: marker::NoShare,
}
impl<T:Freeze + Send> Clone for RWArc<T> {
impl<T: Share + Send> Clone for RWArc<T> {
/// Duplicate a rwlock-protected Arc. See arc::clone for more details.
#[inline]
fn clone(&self) -> RWArc<T> {
RWArc { x: self.x.clone(),
marker: marker::NoFreeze, }
marker: marker::NoFreeze,
marker1: marker::NoShare, }
}
}
impl<T:Freeze + Send> RWArc<T> {
impl<T: Share + Send> RWArc<T> {
/// Create a reader/writer Arc with the supplied data.
pub fn new(user_data: T) -> RWArc<T> {
RWArc::new_with_condvars(user_data, 1)
@ -323,7 +328,8 @@ impl<T:Freeze + Send> RWArc<T> {
failed: false, data: user_data
};
RWArc { x: UnsafeArc::new(data),
marker: marker::NoFreeze, }
marker: marker::NoFreeze,
marker1: marker::NoShare, }
}
/**
@ -454,7 +460,7 @@ impl<T:Freeze + Send> RWArc<T> {
// lock it. This wraps the unsafety, with the justification that the 'lock'
// field is never overwritten; only 'failed' and 'data'.
#[doc(hidden)]
fn borrow_rwlock<T:Freeze + Send>(state: *mut RWArcInner<T>) -> *RWLock {
fn borrow_rwlock<T: Share + Send>(state: *mut RWArcInner<T>) -> *RWLock {
unsafe { cast::transmute(&(*state).lock) }
}
@ -471,7 +477,7 @@ pub struct RWReadMode<'a, T> {
priv token: sync::RWLockReadMode<'a>,
}
impl<'a, T:Freeze + Send> RWWriteMode<'a, T> {
impl<'a, T: Share + Send> RWWriteMode<'a, T> {
/// Access the pre-downgrade RWArc in write mode.
pub fn write<U>(&mut self, blk: |x: &mut T| -> U) -> U {
match *self {
@ -510,7 +516,7 @@ impl<'a, T:Freeze + Send> RWWriteMode<'a, T> {
}
}
impl<'a, T:Freeze + Send> RWReadMode<'a, T> {
impl<'a, T: Share + Send> RWReadMode<'a, T> {
/// Access the post-downgrade rwlock in read mode.
pub fn read<U>(&self, blk: |x: &T| -> U) -> U {
match *self {
@ -534,7 +540,7 @@ pub struct CowArc<T> { priv x: UnsafeArc<T> }
/// mutation of the contents if there is only a single reference to
/// the data. If there are multiple references the data is automatically
/// cloned and the task modifies the cloned data in place of the shared data.
impl<T:Clone+Send+Freeze> CowArc<T> {
impl<T: Clone + Send + Share> CowArc<T> {
/// Create a copy-on-write atomically reference counted wrapper
#[inline]
pub fn new(data: T) -> CowArc<T> {
@ -558,7 +564,7 @@ impl<T:Clone+Send+Freeze> CowArc<T> {
}
}
impl<T:Clone+Send+Freeze> Clone for CowArc<T> {
impl<T: Clone + Send + Share> Clone for CowArc<T> {
/// Duplicate a Copy-on-write Arc. See arc::clone for more details.
fn clone(&self) -> CowArc<T> {
CowArc { x: self.x.clone() }

View File

@ -1159,14 +1159,6 @@ mod test {
use std::vec::Vec;
fn is_freeze<T: Freeze>() {}
// Assert that the AST remains Freeze (#10693).
#[test]
fn ast_is_freeze() {
is_freeze::<Item>();
}
// are ASTs encodable?
#[test]
fn check_asts_encodable() {

View File

@ -29,7 +29,7 @@ pub struct Interner<T> {
}
// when traits can extend traits, we should extend index<Name,T> to get []
impl<T:Eq + Hash + Freeze + Clone + 'static> Interner<T> {
impl<T: Eq + Hash + Clone + 'static> Interner<T> {
pub fn new() -> Interner<T> {
Interner {
map: RefCell::new(HashMap::new()),

View File

@ -16,17 +16,17 @@ struct arc_destruct<T> {
}
#[unsafe_destructor]
impl<T:Freeze> Drop for arc_destruct<T> {
impl<T: Share> Drop for arc_destruct<T> {
fn drop(&mut self) {}
}
fn arc_destruct<T:Freeze>(data: int) -> arc_destruct<T> {
fn arc_destruct<T: Share>(data: int) -> arc_destruct<T> {
arc_destruct {
_data: data
}
}
fn arc<T:Freeze>(_data: T) -> arc_destruct<T> {
fn arc<T: Share>(_data: T) -> arc_destruct<T> {
arc_destruct(0)
}

View File

@ -0,0 +1,47 @@
// Copyright 2014 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Verify that it is not possible to take the address of
// static items with usnafe interior.
use std::kinds::marker;
use std::ty::Unsafe;
struct MyUnsafe<T> {
value: Unsafe<T>
}
impl<T> MyUnsafe<T> {
fn forbidden(&self) {}
}
enum UnsafeEnum<T> {
VariantSafe,
VariantUnsafe(Unsafe<T>)
}
static STATIC1: UnsafeEnum<int> = VariantSafe;
static STATIC2: Unsafe<int> = Unsafe{value: 1, marker1: marker::InvariantType};
static STATIC3: MyUnsafe<int> = MyUnsafe{value: STATIC2};
static STATIC4: &'static Unsafe<int> = &'static STATIC2;
//~^ ERROR borrow of immutable static items with unsafe interior is not allowed
fn main() {
let a = &STATIC1;
//~^ ERROR borrow of immutable static items with unsafe interior is not allowed
STATIC3.forbidden()
//~^ ERROR borrow of immutable static items with unsafe interior is not allowed
}

View File

@ -11,12 +11,12 @@
// Test for traits that inherit from multiple builtin kinds at once,
// testing that all such kinds must be present on implementing types.
trait Foo : Send+Freeze { }
trait Foo : Send+Share { }
impl <T: Freeze> Foo for (T,) { } //~ ERROR cannot implement this trait
impl <T: Share> Foo for (T,) { } //~ ERROR cannot implement this trait
impl <T: Send> Foo for (T,T) { } //~ ERROR cannot implement this trait
impl <T: Send+Freeze> Foo for (T,T,T) { } // (ok)
impl <T: Send+Share> Foo for (T,T,T) { } // (ok)
fn main() { }

View File

@ -11,13 +11,13 @@
// Tests (negatively) the ability for the Self type in default methods
// to use capabilities granted by builtin kinds as supertraits.
trait Foo : Freeze {
trait Foo : Share {
fn foo(self, mut chan: Sender<Self>) {
chan.send(self); //~ ERROR does not fulfill `Send`
}
}
impl <T: Freeze> Foo for T { }
impl <T: Share> Foo for T { }
fn main() {
let (tx, rx) = channel();

View File

@ -12,6 +12,6 @@
trait Foo : Send { }
impl <T: Freeze> Foo for T { } //~ ERROR cannot implement this trait
impl <T: Share> Foo for T { } //~ ERROR cannot implement this trait
fn main() { }

View File

@ -14,6 +14,6 @@ struct X<T>(T);
impl <T> Send for X<T> { } //~ ERROR cannot provide an explicit implementation for a builtin kind
impl <T> Sized for X<T> { } //~ ERROR cannot provide an explicit implementation for a builtin kind
impl <T> Freeze for X<T> { } //~ ERROR cannot provide an explicit implementation for a builtin kind
impl <T> Share for X<T> { } //~ ERROR cannot provide an explicit implementation for a builtin kind
fn main() { }

View File

@ -124,30 +124,6 @@ static STATIC18: @SafeStruct = @SafeStruct{field1: Variant1, field2: Variant2(0)
static STATIC19: ~int = box 3;
//~^ ERROR static items are not allowed to have owned pointers
struct StructNoFreeze<'a> {
nf: &'a int
}
enum EnumNoFreeze<'a> {
FreezableVariant,
NonFreezableVariant(StructNoFreeze<'a>)
}
static STATIC20: StructNoFreeze<'static> = StructNoFreeze{nf: &'static mut 4};
//~^ ERROR immutable static items must be `Freeze`
static STATIC21: EnumNoFreeze<'static> = FreezableVariant;
static STATIC22: EnumNoFreeze<'static> = NonFreezableVariant(StructNoFreeze{nf: &'static mut 4});
//~^ ERROR immutable static items must be `Freeze`
struct NFMarker {
nf: marker::NoFreeze
}
static STATIC23: NFMarker = NFMarker{nf: marker::NoFreeze};
//~^ ERROR immutable static items must be `Freeze`
pub fn main() {
let y = { static x: ~int = ~3; x };
//~^ ERROR static items are not allowed to have owned pointers

View File

@ -8,10 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
fn test<T: Freeze>() {}
fn test<T: Share>() {}
fn main() {
test::<Sender<int>>(); //~ ERROR: does not fulfill `Freeze`
test::<Receiver<int>>(); //~ ERROR: does not fulfill `Freeze`
test::<Sender<int>>(); //~ ERROR: does not fulfill `Freeze`
test::<Sender<int>>(); //~ ERROR: does not fulfill `Share`
test::<Receiver<int>>(); //~ ERROR: does not fulfill `Share`
test::<Sender<int>>(); //~ ERROR: does not fulfill `Share`
}

View File

@ -20,7 +20,7 @@ struct E {
}
impl A for E {
fn b<F:Freeze,G>(_x: F) -> F { fail!() } //~ ERROR type parameter 0 requires `Freeze`
fn b<F: Share, G>(_x: F) -> F { fail!() } //~ ERROR type parameter 0 requires `Share`
}
fn main() {}

View File

@ -10,9 +10,9 @@
use std::kinds::marker;
fn foo<P:Freeze>(p: P) { }
fn foo<P: Share>(p: P) { }
fn main()
{
foo(marker::NoFreeze); //~ ERROR does not fulfill `Freeze`
foo(marker::NoShare); //~ ERROR does not fulfill `Share`
}

View File

@ -10,9 +10,9 @@
use std::cell::RefCell;
fn f<T: Freeze>(_: T) {}
fn f<T: Share>(_: T) {}
fn main() {
let x = RefCell::new(0);
f(x); //~ ERROR: which does not fulfill `Freeze`
f(x); //~ ERROR: which does not fulfill `Share`
}

View File

@ -10,13 +10,13 @@
use std::kinds::marker;
enum Foo { A(marker::NoFreeze) }
enum Foo { A(marker::NoShare) }
fn bar<T: Freeze>(_: T) {}
fn bar<T: Share>(_: T) {}
fn main() {
let x = A(marker::NoFreeze);
let x = A(marker::NoShare);
bar(x);
//~^ ERROR instantiating a type parameter with an incompatible type `Foo`,
// which does not fulfill `Freeze`
// which does not fulfill `Share`
}

View File

@ -11,11 +11,11 @@
use std::rc::Rc;
use std::cell::RefCell;
fn bar<T: Freeze>(_: T) {}
fn bar<T: Share>(_: T) {}
fn main() {
let x = Rc::new(RefCell::new(5));
bar(x);
//~^ ERROR instantiating a type parameter with an incompatible type
// `std::rc::Rc<std::cell::RefCell<int>>`, which does not fulfill `Freeze`
// `std::rc::Rc<std::cell::RefCell<int>>`, which does not fulfill `Share`
}

View File

@ -10,13 +10,13 @@
use std::kinds::marker;
struct Foo { a: int, m: marker::NoFreeze }
struct Foo { a: int, m: marker::NoShare }
fn bar<T: Freeze>(_: T) {}
fn bar<T: Share>(_: T) {}
fn main() {
let x = Foo { a: 5, m: marker::NoFreeze };
let x = Foo { a: 5, m: marker::NoShare };
bar(x);
//~^ ERROR instantiating a type parameter with an incompatible type `Foo`,
// which does not fulfill `Freeze`
// which does not fulfill `Share`
}

View File

@ -12,7 +12,7 @@
// are const.
fn foo<T:Freeze>(x: T) -> T { x }
fn foo<T: Share>(x: T) -> T { x }
struct F { field: int }

View File

@ -12,7 +12,7 @@
// than the traits require.
trait A {
fn b<C:Freeze,D>(x: C) -> C;
fn b<C:Share,D>(x: C) -> C;
}
struct E {

View File

@ -65,10 +65,10 @@ pub fn main() {
let dogge1 = Dogge { bark_decibels: 100, tricks_known: 42, name: ~"alan_turing" };
let dogge2 = Dogge { bark_decibels: 55, tricks_known: 11, name: ~"albert_einstein" };
let fishe = Goldfyshe { swim_speed: 998, name: ~"alec_guinness" };
let arc = Arc::new(~[~catte as ~Pet:Freeze+Send,
~dogge1 as ~Pet:Freeze+Send,
~fishe as ~Pet:Freeze+Send,
~dogge2 as ~Pet:Freeze+Send]);
let arc = Arc::new(~[~catte as ~Pet:Share+Send,
~dogge1 as ~Pet:Share+Send,
~fishe as ~Pet:Share+Send,
~dogge2 as ~Pet:Share+Send]);
let (tx1, rx1) = channel();
let arc1 = arc.clone();
task::spawn(proc() { check_legs(arc1); tx1.send(()); });
@ -83,21 +83,21 @@ pub fn main() {
rx3.recv();
}
fn check_legs(arc: Arc<~[~Pet:Freeze+Send]>) {
fn check_legs(arc: Arc<~[~Pet:Share+Send]>) {
let mut legs = 0;
for pet in arc.get().iter() {
legs += pet.num_legs();
}
assert!(legs == 12);
}
fn check_names(arc: Arc<~[~Pet:Freeze+Send]>) {
fn check_names(arc: Arc<~[~Pet:Share+Send]>) {
for pet in arc.get().iter() {
pet.name(|name| {
assert!(name[0] == 'a' as u8 && name[1] == 'l' as u8);
})
}
}
fn check_pedigree(arc: Arc<~[~Pet:Freeze+Send]>) {
fn check_pedigree(arc: Arc<~[~Pet:Share+Send]>) {
for pet in arc.get().iter() {
assert!(pet.of_good_pedigree());
}