diff --git a/src/doc/guide-unsafe.md b/src/doc/guide-unsafe.md index b085fe21fac4b..9835e50d54765 100644 --- a/src/doc/guide-unsafe.md +++ b/src/doc/guide-unsafe.md @@ -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` diff --git a/src/doc/tutorial.md b/src/doc/tutorial.md index cdb521b96c42f..0a417a5a8bf11 100644 --- a/src/doc/tutorial.md +++ b/src/doc/tutorial.md @@ -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. diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 1abbf1307c119..157cc8cd0f08d 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -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))); } diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 0934b6407fb74..792fca5eca679 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -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"), } } diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index 841123906cc87..7dfaaa6900c97 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -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) => { diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index 3c3c4371ebb01..459c908cae2e7 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -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, _: ()) {} +} + +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, 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 => { - 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(()) } - 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(()) } } } diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index bb6956556b57e..dd2f02bf2416d 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -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)); diff --git a/src/librustc/middle/check_static.rs b/src/librustc/middle/check_static.rs index 83f987a0bd0b3..ecc3ba59dd5ab 100644 --- a/src/librustc/middle/check_static.rs +++ b/src/librustc/middle/check_static.rs @@ -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 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 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; - } } _ => {} } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 3b322d0278762..8ef4991be13c0 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -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 { + pub fn to_builtin_kind(&self, id: ast::DefId) -> Option { 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; } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 7c95815af54e5..49dbe668403de 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -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 { + pub fn freely_aliasable(&self, ctxt: &ty::ctxt) -> Option { /*! * 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(..) => { + let int_safe = if ty::type_interior_is_unsafe(ctxt, self.ty) { + InteriorUnsafe + } else { + InteriorSafe + }; + if self.mutbl.is_mutable() { - Some(AliasableStaticMut) + Some(AliasableStaticMut(int_safe)) } else { - Some(AliasableStatic) + Some(AliasableStatic(int_safe)) } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 61371cec49ea5..653b4372695ae 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -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; diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 7c03c1dc45dfb..2b6c6825c7e3f 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -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", } } } diff --git a/src/libstd/cell.rs b/src/libstd/cell.rs index 398091b60cae3..5733504c0d189 100644 --- a/src/libstd/cell.rs +++ b/src/libstd/cell.rs @@ -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 { - priv value: T, + priv value: Unsafe, priv marker1: marker::InvariantType, priv marker2: marker::NoFreeze, + priv marker3: marker::NoShare, } impl Cell { /// Creates a new `Cell` containing the given value. pub fn new(value: T) -> Cell { Cell { - value: value, + value: Unsafe{value: value, marker1: marker::InvariantType::}, marker1: marker::InvariantType::, 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 Eq for Cell { impl fmt::Show for Cell { 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 { - priv value: T, + priv value: Unsafe, priv borrow: BorrowFlag, priv marker1: marker::InvariantType, 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 RefCell { marker1: marker::InvariantType::, marker2: marker::NoFreeze, marker3: marker::NoPod, - value: value, + marker4: marker::NoShare, + value: Unsafe{value: value, marker1: marker::InvariantType::}, borrow: UNUSED, } } @@ -98,7 +103,7 @@ impl RefCell { /// 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 { @@ -198,7 +203,7 @@ impl RefCell { #[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 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 for RefMut<'b, T> { #[inline] fn deref<'a>(&'a self) -> &'a T { - &self.parent.value + unsafe{ &*self.parent.value.get() } } } impl<'b, T> DerefMut 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() } } } diff --git a/src/libstd/kinds.rs b/src/libstd/kinds.rs index da17119fd984c..b44616421d182 100644 --- a/src/libstd/kinds.rs +++ b/src/libstd/kinds.rs @@ -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 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"] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index c6a1d710a528a..73be83c254d3f 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -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; pub mod macros; @@ -138,6 +139,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 */ @@ -226,5 +228,6 @@ mod std { pub use rt; pub use str; pub use to_str; + pub use ty; pub use unstable; } diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 0b1de74330d14..f3a5bd3d3b582 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -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}; diff --git a/src/libstd/rc.rs b/src/libstd/rc.rs index 5c4b19b4e4b8c..605cbd3f28a12 100644 --- a/src/libstd/rc.rs +++ b/src/libstd/rc.rs @@ -42,7 +42,8 @@ struct RcBox { #[unsafe_no_drop_flag] pub struct Rc { priv ptr: *mut RcBox, - priv marker: marker::NoSend + priv nosend: marker::NoSend, + priv noshare: marker::NoShare } impl Rc { @@ -56,7 +57,8 @@ impl Rc { // 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 Rc { pub fn downgrade(&self) -> Weak { 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 Clone for Rc { fn clone(&self) -> Rc { 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 Ord for Rc { #[unsafe_no_drop_flag] pub struct Weak { priv ptr: *mut RcBox, - priv marker: marker::NoSend + priv nosend: marker::NoSend, + priv noshare: marker::NoShare } impl Weak { @@ -149,7 +156,7 @@ impl Weak { 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 Clone for Weak { fn clone(&self) -> Weak { unsafe { (*self.ptr).weak += 1; - Weak { ptr: self.ptr, marker: marker::NoSend } + Weak { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare } } } } diff --git a/src/libstd/sync/arc.rs b/src/libstd/sync/arc.rs index 883e81355e1ef..9297400530553 100644 --- a/src/libstd/sync/arc.rs +++ b/src/libstd/sync/arc.rs @@ -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 { struct ArcData { count: AtomicUint, - data: T, + data: Unsafe, } unsafe fn new_inner(data: T, refcount: uint) -> *mut ArcData { - 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 UnsafeArc { 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 UnsafeArc { 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; } } diff --git a/src/libstd/sync/atomics.rs b/src/libstd/sync/atomics.rs index 500ae04869be2..cbdb38c1c58b6 100644 --- a/src/libstd/sync/atomics.rs +++ b/src/libstd/sync/atomics.rs @@ -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, priv nopod: marker::NoPod } /// A signed atomic integer type, supporting basic atomic arithmetic operations pub struct AtomicInt { - priv v: int, + priv v: Unsafe, priv nopod: marker::NoPod } /// An unsigned atomic integer type, supporting basic atomic arithmetic operations pub struct AtomicUint { - priv v: uint, + priv v: Unsafe, 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, priv nopod: marker::NoPod } /// An unsafe atomic pointer. Only supports basic atomic operations pub struct AtomicPtr { - priv p: uint, + priv p: Unsafe, priv nopod: marker::NoPod } @@ -152,7 +153,7 @@ pub struct AtomicPtr { /// owned heap objects across tasks. #[unsafe_no_drop_flag] pub struct AtomicOption { - priv p: uint, + priv p: Unsafe, } /// 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 AtomicPtr { /// Create a new `AtomicPtr` pub fn new(p: *mut T) -> AtomicPtr { - 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 AtomicPtr { #[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 AtomicPtr { impl AtomicOption { /// Create a new `AtomicOption` pub fn new(p: ~T) -> AtomicOption { - 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 { AtomicOption { p: 0 } } + pub fn empty() -> AtomicOption { AtomicOption { p: Unsafe::new(0) } } /// Store a value, returning the old value #[inline] @@ -630,7 +640,7 @@ impl AtomicOption { 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 AtomicOption { 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 AtomicOption { /// 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 } } } diff --git a/src/libstd/ty.rs b/src/libstd/ty.rs new file mode 100644 index 0000000000000..344235053f350 --- /dev/null +++ b/src/libstd/ty.rs @@ -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 or the MIT license +// , 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` 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 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 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 { +/// value: Unsafe, +/// marker1: marker::NoShare +/// } +/// ``` +/// +/// **NOTE:** Unsafe 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 { + /// Wrapped value + value: T, + + /// Invariance marker + marker1: marker::InvariantType +} + +/// Unsafe type for stage0 +#[cfg(stage0)] +pub struct Unsafe { + /// Wrapped value + value: T, + + /// Invariance marker + marker1: marker::InvariantType +} + +impl Unsafe { + + /// Static constructor + pub fn new(value: T) -> Unsafe { + 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 } +} diff --git a/src/libsync/arc.rs b/src/libsync/arc.rs index 1d49771ed386a..71adab71734b9 100644 --- a/src/libsync/arc.rs +++ b/src/libsync/arc.rs @@ -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 { priv x: UnsafeArc } * Access the underlying data in an atomically reference counted * wrapper. */ -impl Arc { +impl Arc { /// Create an atomically reference counted wrapper. #[inline] pub fn new(data: T) -> Arc { @@ -135,7 +138,7 @@ impl Arc { } } -impl Clone for Arc { +impl Clone for Arc { /** * Duplicate an atomically reference counted wrapper. * @@ -295,19 +298,21 @@ struct RWArcInner { lock: RWLock, failed: bool, data: T } pub struct RWArc { priv x: UnsafeArc>, priv marker: marker::NoFreeze, + priv marker1: marker::NoShare, } -impl Clone for RWArc { +impl Clone for RWArc { /// Duplicate a rwlock-protected Arc. See arc::clone for more details. #[inline] fn clone(&self) -> RWArc { RWArc { x: self.x.clone(), - marker: marker::NoFreeze, } + marker: marker::NoFreeze, + marker1: marker::NoShare, } } } -impl RWArc { +impl RWArc { /// Create a reader/writer Arc with the supplied data. pub fn new(user_data: T) -> RWArc { RWArc::new_with_condvars(user_data, 1) @@ -323,7 +328,8 @@ impl RWArc { failed: false, data: user_data }; RWArc { x: UnsafeArc::new(data), - marker: marker::NoFreeze, } + marker: marker::NoFreeze, + marker1: marker::NoShare, } } /** @@ -454,7 +460,7 @@ impl RWArc { // 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(state: *mut RWArcInner) -> *RWLock { +fn borrow_rwlock(state: *mut RWArcInner) -> *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(&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(&self, blk: |x: &T| -> U) -> U { match *self { @@ -534,7 +540,7 @@ pub struct CowArc { priv x: UnsafeArc } /// 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 CowArc { +impl CowArc { /// Create a copy-on-write atomically reference counted wrapper #[inline] pub fn new(data: T) -> CowArc { @@ -558,7 +564,7 @@ impl CowArc { } } -impl Clone for CowArc { +impl Clone for CowArc { /// Duplicate a Copy-on-write Arc. See arc::clone for more details. fn clone(&self) -> CowArc { CowArc { x: self.x.clone() } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 77b0d4b5c9da5..e79bc5dfdf799 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1159,14 +1159,6 @@ mod test { use std::vec_ng::Vec; - fn is_freeze() {} - - // Assert that the AST remains Freeze (#10693). - #[test] - fn ast_is_freeze() { - is_freeze::(); - } - // are ASTs encodable? #[test] fn check_asts_encodable() { diff --git a/src/libsyntax/util/interner.rs b/src/libsyntax/util/interner.rs index c1ed96fe4de48..362d08a574895 100644 --- a/src/libsyntax/util/interner.rs +++ b/src/libsyntax/util/interner.rs @@ -29,7 +29,7 @@ pub struct Interner { } // when traits can extend traits, we should extend index to get [] -impl Interner { +impl Interner { pub fn new() -> Interner { Interner { map: RefCell::new(HashMap::new()), diff --git a/src/test/auxiliary/issue-2526.rs b/src/test/auxiliary/issue-2526.rs index ef5c141a3d508..51bbb59b77eca 100644 --- a/src/test/auxiliary/issue-2526.rs +++ b/src/test/auxiliary/issue-2526.rs @@ -16,17 +16,17 @@ struct arc_destruct { } #[unsafe_destructor] -impl Drop for arc_destruct { +impl Drop for arc_destruct { fn drop(&mut self) {} } -fn arc_destruct(data: int) -> arc_destruct { +fn arc_destruct(data: int) -> arc_destruct { arc_destruct { _data: data } } -fn arc(_data: T) -> arc_destruct { +fn arc(_data: T) -> arc_destruct { arc_destruct(0) } diff --git a/src/test/compile-fail/borrowck-forbid-static-unsafe-interior.rs b/src/test/compile-fail/borrowck-forbid-static-unsafe-interior.rs new file mode 100644 index 0000000000000..c790a040a91a4 --- /dev/null +++ b/src/test/compile-fail/borrowck-forbid-static-unsafe-interior.rs @@ -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 or the MIT license +// , 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 { + value: Unsafe +} + +impl MyUnsafe { + fn forbidden(&self) {} +} + +enum UnsafeEnum { + VariantSafe, + VariantUnsafe(Unsafe) +} + +static STATIC1: UnsafeEnum = VariantSafe; + +static STATIC2: Unsafe = Unsafe{value: 1, marker1: marker::InvariantType}; +static STATIC3: MyUnsafe = MyUnsafe{value: STATIC2}; + +static STATIC4: &'static Unsafe = &'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 +} + + diff --git a/src/test/compile-fail/builtin-superkinds-double-superkind.rs b/src/test/compile-fail/builtin-superkinds-double-superkind.rs index 15fa0b6643381..7de38e6173be1 100644 --- a/src/test/compile-fail/builtin-superkinds-double-superkind.rs +++ b/src/test/compile-fail/builtin-superkinds-double-superkind.rs @@ -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 Foo for (T,) { } //~ ERROR cannot implement this trait +impl Foo for (T,) { } //~ ERROR cannot implement this trait impl Foo for (T,T) { } //~ ERROR cannot implement this trait -impl Foo for (T,T,T) { } // (ok) +impl Foo for (T,T,T) { } // (ok) fn main() { } diff --git a/src/test/compile-fail/builtin-superkinds-self-type.rs b/src/test/compile-fail/builtin-superkinds-self-type.rs index 074c5d7bb761a..0d5a71559e867 100644 --- a/src/test/compile-fail/builtin-superkinds-self-type.rs +++ b/src/test/compile-fail/builtin-superkinds-self-type.rs @@ -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) { chan.send(self); //~ ERROR does not fulfill `Send` } } -impl Foo for T { } +impl Foo for T { } fn main() { let (tx, rx) = channel(); diff --git a/src/test/compile-fail/builtin-superkinds-typaram-not-send.rs b/src/test/compile-fail/builtin-superkinds-typaram-not-send.rs index 2a3d3c7df6132..bc0ad6dbb2938 100644 --- a/src/test/compile-fail/builtin-superkinds-typaram-not-send.rs +++ b/src/test/compile-fail/builtin-superkinds-typaram-not-send.rs @@ -12,6 +12,6 @@ trait Foo : Send { } -impl Foo for T { } //~ ERROR cannot implement this trait +impl Foo for T { } //~ ERROR cannot implement this trait fn main() { } diff --git a/src/test/compile-fail/cant-implement-builtin-kinds.rs b/src/test/compile-fail/cant-implement-builtin-kinds.rs index c35ca098372d3..6bedac6d12d6c 100644 --- a/src/test/compile-fail/cant-implement-builtin-kinds.rs +++ b/src/test/compile-fail/cant-implement-builtin-kinds.rs @@ -14,6 +14,6 @@ struct X(T); impl Send for X { } //~ ERROR cannot provide an explicit implementation for a builtin kind impl Sized for X { } //~ ERROR cannot provide an explicit implementation for a builtin kind -impl Freeze for X { } //~ ERROR cannot provide an explicit implementation for a builtin kind +impl Share for X { } //~ ERROR cannot provide an explicit implementation for a builtin kind fn main() { } diff --git a/src/test/compile-fail/check-static-values-constraints.rs b/src/test/compile-fail/check-static-values-constraints.rs index 852b06d00a64e..8ae40a74af188 100644 --- a/src/test/compile-fail/check-static-values-constraints.rs +++ b/src/test/compile-fail/check-static-values-constraints.rs @@ -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 diff --git a/src/test/compile-fail/comm-not-freeze.rs b/src/test/compile-fail/comm-not-freeze.rs index b7b87b2826440..3550922dc1462 100644 --- a/src/test/compile-fail/comm-not-freeze.rs +++ b/src/test/compile-fail/comm-not-freeze.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn test() {} +fn test() {} fn main() { - test::>(); //~ ERROR: does not fulfill `Freeze` - test::>(); //~ ERROR: does not fulfill `Freeze` - test::>(); //~ ERROR: does not fulfill `Freeze` + test::>(); //~ ERROR: does not fulfill `Share` + test::>(); //~ ERROR: does not fulfill `Share` + test::>(); //~ ERROR: does not fulfill `Share` } diff --git a/src/test/compile-fail/issue-2611-4.rs b/src/test/compile-fail/issue-2611-4.rs index c62c28745253d..b159337765e5f 100644 --- a/src/test/compile-fail/issue-2611-4.rs +++ b/src/test/compile-fail/issue-2611-4.rs @@ -20,7 +20,7 @@ struct E { } impl A for E { - fn b(_x: F) -> F { fail!() } //~ ERROR type parameter 0 requires `Freeze` + fn b(_x: F) -> F { fail!() } //~ ERROR type parameter 0 requires `Share` } fn main() {} diff --git a/src/test/compile-fail/marker-no-freeze.rs b/src/test/compile-fail/marker-no-share.rs similarity index 84% rename from src/test/compile-fail/marker-no-freeze.rs rename to src/test/compile-fail/marker-no-share.rs index 85f4f4fefd43e..84e856f5ac915 100644 --- a/src/test/compile-fail/marker-no-freeze.rs +++ b/src/test/compile-fail/marker-no-share.rs @@ -10,9 +10,9 @@ use std::kinds::marker; -fn foo(p: P) { } +fn foo(p: P) { } fn main() { - foo(marker::NoFreeze); //~ ERROR does not fulfill `Freeze` + foo(marker::NoShare); //~ ERROR does not fulfill `Share` } diff --git a/src/test/compile-fail/mut-not-freeze.rs b/src/test/compile-fail/mut-not-freeze.rs index 97fe49ca087f5..f1e7ef216c32c 100644 --- a/src/test/compile-fail/mut-not-freeze.rs +++ b/src/test/compile-fail/mut-not-freeze.rs @@ -10,9 +10,9 @@ use std::cell::RefCell; -fn f(_: T) {} +fn f(_: T) {} fn main() { let x = RefCell::new(0); - f(x); //~ ERROR: which does not fulfill `Freeze` + f(x); //~ ERROR: which does not fulfill `Share` } diff --git a/src/test/compile-fail/no_freeze-enum.rs b/src/test/compile-fail/no_share-enum.rs similarity index 81% rename from src/test/compile-fail/no_freeze-enum.rs rename to src/test/compile-fail/no_share-enum.rs index e27b9dd85b471..e68274fcb7940 100644 --- a/src/test/compile-fail/no_freeze-enum.rs +++ b/src/test/compile-fail/no_share-enum.rs @@ -10,13 +10,13 @@ use std::kinds::marker; -enum Foo { A(marker::NoFreeze) } +enum Foo { A(marker::NoShare) } -fn bar(_: T) {} +fn bar(_: 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` } diff --git a/src/test/compile-fail/no_freeze-rc.rs b/src/test/compile-fail/no_share-rc.rs similarity index 93% rename from src/test/compile-fail/no_freeze-rc.rs rename to src/test/compile-fail/no_share-rc.rs index b814a71dcbe63..ad79d03821206 100644 --- a/src/test/compile-fail/no_freeze-rc.rs +++ b/src/test/compile-fail/no_share-rc.rs @@ -11,11 +11,11 @@ use std::rc::Rc; use std::cell::RefCell; -fn bar(_: T) {} +fn bar(_: T) {} fn main() { let x = Rc::new(RefCell::new(5)); bar(x); //~^ ERROR instantiating a type parameter with an incompatible type - // `std::rc::Rc>`, which does not fulfill `Freeze` + // `std::rc::Rc>`, which does not fulfill `Share` } diff --git a/src/test/compile-fail/no_freeze-struct.rs b/src/test/compile-fail/no_share-struct.rs similarity index 78% rename from src/test/compile-fail/no_freeze-struct.rs rename to src/test/compile-fail/no_share-struct.rs index c85574438ba3b..7bb7d86e8d870 100644 --- a/src/test/compile-fail/no_freeze-struct.rs +++ b/src/test/compile-fail/no_share-struct.rs @@ -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) {} +fn bar(_: 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` } diff --git a/src/test/run-pass/const-bound.rs b/src/test/run-pass/const-bound.rs index 635ae704e4194..c8c2a11d8d649 100644 --- a/src/test/run-pass/const-bound.rs +++ b/src/test/run-pass/const-bound.rs @@ -12,7 +12,7 @@ // are const. -fn foo(x: T) -> T { x } +fn foo(x: T) -> T { x } struct F { field: int } diff --git a/src/test/run-pass/issue-2611-3.rs b/src/test/run-pass/issue-2611-3.rs index a3d51bb9014e8..f48a49a15eb3d 100644 --- a/src/test/run-pass/issue-2611-3.rs +++ b/src/test/run-pass/issue-2611-3.rs @@ -12,7 +12,7 @@ // than the traits require. trait A { - fn b(x: C) -> C; + fn b(x: C) -> C; } struct E { diff --git a/src/test/run-pass/trait-bounds-in-arc.rs b/src/test/run-pass/trait-bounds-in-arc.rs index f157f8ea95c82..0ed4fdb2c054d 100644 --- a/src/test/run-pass/trait-bounds-in-arc.rs +++ b/src/test/run-pass/trait-bounds-in-arc.rs @@ -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()); }