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:
commit
8e285208d5
@ -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`
|
||||
|
@ -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.
|
||||
|
@ -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)));
|
||||
}
|
||||
|
@ -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"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) => {
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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() }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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"]
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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};
|
||||
|
@ -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 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
82
src/libstd/ty.rs
Normal 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 }
|
||||
}
|
@ -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() }
|
||||
|
@ -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() {
|
||||
|
@ -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()),
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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() { }
|
||||
|
@ -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();
|
||||
|
@ -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() { }
|
||||
|
@ -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() { }
|
||||
|
@ -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
|
||||
|
@ -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`
|
||||
}
|
||||
|
@ -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() {}
|
||||
|
@ -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`
|
||||
}
|
@ -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`
|
||||
}
|
||||
|
@ -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`
|
||||
}
|
@ -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`
|
||||
}
|
@ -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`
|
||||
}
|
@ -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 }
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user