diff --git a/doc/rust.md b/doc/rust.md index aa4ce002e02..489a10bb87c 100644 --- a/doc/rust.md +++ b/doc/rust.md @@ -3329,6 +3329,12 @@ The kinds are: This kind includes scalars, owning pointers, owned closures, and structural types containing only other owned types. All `Send` types are `'static`. +`Pod` + : Types of this kind consist of "Plain Old Data" + which can be copied by simply moving bits. + All values of this kind can be implicitly copied. + This kind includes scalars and immutable references, + as well as structural types containing other `Pod` types. `'static` : Types of this kind do not contain any borrowed pointers; this can be a useful guarantee for code diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 7a00afbc652..6896b951c77 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -395,6 +395,7 @@ fn enc_bounds(w: @mut MemWriter, cx: @ctxt, bs: &ty::ParamBounds) { ty::BoundFreeze => mywrite!(w, "K"), ty::BoundStatic => mywrite!(w, "O"), ty::BoundSized => mywrite!(w, "Z"), + ty::BoundPod => mywrite!(w, "P"), } } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index d77f0cb054a..97b6d10e05d 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -23,7 +23,7 @@ use driver::session::Session; use metadata::csearch::each_lang_item; use metadata::cstore::iter_crate_data; -use middle::ty::{BuiltinBound, BoundFreeze, BoundSend, BoundSized}; +use middle::ty::{BuiltinBound, BoundFreeze, BoundPod, BoundSend, BoundSized}; use syntax::ast; use syntax::ast_util::local_def; use syntax::attr::AttrMetaMethods; @@ -83,6 +83,8 @@ impl LanguageItems { Some(BoundSend) } else if Some(id) == self.sized_trait() { Some(BoundSized) + } else if Some(id) == self.pod_trait() { + Some(BoundPod) } else { None } @@ -206,56 +208,58 @@ pub fn collect_language_items(crate: &ast::Crate, } lets_do_this! { - There are 41 lang items. + There are 42 lang items. // ID, Variant name, Name, Method name; 0, FreezeTraitLangItem, "freeze", freeze_trait; 1, SendTraitLangItem, "send", send_trait; 2, SizedTraitLangItem, "sized", sized_trait; + 3, PodTraitLangItem, "pod", pod_trait; - 3, DropTraitLangItem, "drop", drop_trait; + 4, DropTraitLangItem, "drop", drop_trait; - 4, AddTraitLangItem, "add", add_trait; - 5, SubTraitLangItem, "sub", sub_trait; - 6, MulTraitLangItem, "mul", mul_trait; - 7, DivTraitLangItem, "div", div_trait; - 8, RemTraitLangItem, "rem", rem_trait; - 9, NegTraitLangItem, "neg", neg_trait; - 10, NotTraitLangItem, "not", not_trait; - 11, BitXorTraitLangItem, "bitxor", bitxor_trait; - 12, BitAndTraitLangItem, "bitand", bitand_trait; - 13, BitOrTraitLangItem, "bitor", bitor_trait; - 14, ShlTraitLangItem, "shl", shl_trait; - 15, ShrTraitLangItem, "shr", shr_trait; - 16, IndexTraitLangItem, "index", index_trait; + 5, AddTraitLangItem, "add", add_trait; + 6, SubTraitLangItem, "sub", sub_trait; + 7, MulTraitLangItem, "mul", mul_trait; + 8, DivTraitLangItem, "div", div_trait; + 9, RemTraitLangItem, "rem", rem_trait; + 10, NegTraitLangItem, "neg", neg_trait; + 11, NotTraitLangItem, "not", not_trait; + 12, BitXorTraitLangItem, "bitxor", bitxor_trait; + 13, BitAndTraitLangItem, "bitand", bitand_trait; + 14, BitOrTraitLangItem, "bitor", bitor_trait; + 15, ShlTraitLangItem, "shl", shl_trait; + 16, ShrTraitLangItem, "shr", shr_trait; + 17, IndexTraitLangItem, "index", index_trait; - 17, EqTraitLangItem, "eq", eq_trait; - 18, OrdTraitLangItem, "ord", ord_trait; + 18, EqTraitLangItem, "eq", eq_trait; + 19, OrdTraitLangItem, "ord", ord_trait; - 19, StrEqFnLangItem, "str_eq", str_eq_fn; - 20, UniqStrEqFnLangItem, "uniq_str_eq", uniq_str_eq_fn; - 21, FailFnLangItem, "fail_", fail_fn; - 22, FailBoundsCheckFnLangItem, "fail_bounds_check", fail_bounds_check_fn; - 23, ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn; - 24, ClosureExchangeMallocFnLangItem, "closure_exchange_malloc", closure_exchange_malloc_fn; - 25, ExchangeFreeFnLangItem, "exchange_free", exchange_free_fn; - 26, MallocFnLangItem, "malloc", malloc_fn; - 27, FreeFnLangItem, "free", free_fn; - 28, BorrowAsImmFnLangItem, "borrow_as_imm", borrow_as_imm_fn; - 29, BorrowAsMutFnLangItem, "borrow_as_mut", borrow_as_mut_fn; - 30, ReturnToMutFnLangItem, "return_to_mut", return_to_mut_fn; - 31, CheckNotBorrowedFnLangItem, "check_not_borrowed", check_not_borrowed_fn; - 32, StrDupUniqFnLangItem, "strdup_uniq", strdup_uniq_fn; - 33, RecordBorrowFnLangItem, "record_borrow", record_borrow_fn; - 34, UnrecordBorrowFnLangItem, "unrecord_borrow", unrecord_borrow_fn; + 20, StrEqFnLangItem, "str_eq", str_eq_fn; + 21, UniqStrEqFnLangItem, "uniq_str_eq", uniq_str_eq_fn; + 22, FailFnLangItem, "fail_", fail_fn; + 23, FailBoundsCheckFnLangItem, "fail_bounds_check", fail_bounds_check_fn; + 24, ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn; + 25, ClosureExchangeMallocFnLangItem, "closure_exchange_malloc", closure_exchange_malloc_fn; + 26, ExchangeFreeFnLangItem, "exchange_free", exchange_free_fn; + 27, MallocFnLangItem, "malloc", malloc_fn; + 28, FreeFnLangItem, "free", free_fn; + 29, BorrowAsImmFnLangItem, "borrow_as_imm", borrow_as_imm_fn; + 30, BorrowAsMutFnLangItem, "borrow_as_mut", borrow_as_mut_fn; + 31, ReturnToMutFnLangItem, "return_to_mut", return_to_mut_fn; + 32, CheckNotBorrowedFnLangItem, "check_not_borrowed", check_not_borrowed_fn; + 33, StrDupUniqFnLangItem, "strdup_uniq", strdup_uniq_fn; + 34, RecordBorrowFnLangItem, "record_borrow", record_borrow_fn; + 35, UnrecordBorrowFnLangItem, "unrecord_borrow", unrecord_borrow_fn; - 35, StartFnLangItem, "start", start_fn; + 36, StartFnLangItem, "start", start_fn; - 36, TyDescStructLangItem, "ty_desc", ty_desc; - 37, TyVisitorTraitLangItem, "ty_visitor", ty_visitor; - 38, OpaqueStructLangItem, "opaque", opaque; + 37, TyDescStructLangItem, "ty_desc", ty_desc; + 38, TyVisitorTraitLangItem, "ty_visitor", ty_visitor; + 39, OpaqueStructLangItem, "opaque", opaque; - 39, EventLoopFactoryLangItem, "event_loop_factory", event_loop_factory; + 40, EventLoopFactoryLangItem, "event_loop_factory", event_loop_factory; - 40, TypeIdLangItem, "type_id", type_id; + 41, TypeIdLangItem, "type_id", type_id; } + diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index cb0e8d3241e..86a7250d6b9 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -737,6 +737,7 @@ pub enum BuiltinBound { BoundSend, BoundFreeze, BoundSized, + BoundPod, } pub fn EmptyBuiltinBounds() -> BuiltinBounds { @@ -1805,6 +1806,9 @@ def_type_content_sets!( // Things that prevent values from being considered sized Nonsized = 0b0000__00000000__0001, + // Things that make values considered not POD (same as `Moves`) + Nonpod = 0b0000__00001111__0000, + // Bits to set when a managed value is encountered // // [1] Do not set the bits TC::OwnsManaged or @@ -1828,6 +1832,7 @@ impl TypeContents { BoundFreeze => self.is_freezable(cx), BoundSend => self.is_sendable(cx), BoundSized => self.is_sized(cx), + BoundPod => self.is_pod(cx), } } @@ -1859,6 +1864,10 @@ impl TypeContents { !self.intersects(TC::Nonsized) } + pub fn is_pod(&self, _: ctxt) -> bool { + !self.intersects(TC::Nonpod) + } + pub fn moves_by_default(&self, _: ctxt) -> bool { self.intersects(TC::Moves) } @@ -1876,15 +1885,32 @@ impl TypeContents { *self & (TC::OwnsAll | TC::ReachesAll)) } - pub fn other_pointer(&self, bits: TypeContents) -> TypeContents { + pub fn reference(&self, bits: TypeContents) -> TypeContents { /*! * Includes only those bits that still apply - * when indirected through a non-owning pointer (`&`, `@`) + * when indirected through a reference (`&`) */ bits | ( *self & TC::ReachesAll) } + pub fn managed_pointer(&self) -> TypeContents { + /*! + * Includes only those bits that still apply + * when indirected through a managed pointer (`@`) + */ + TC::Managed | ( + *self & TC::ReachesAll) + } + + pub fn unsafe_pointer(&self) -> TypeContents { + /*! + * Includes only those bits that still apply + * when indirected through an unsafe pointer (`*`) + */ + *self & TC::ReachesAll + } + pub fn union(v: &[T], f: |&T| -> TypeContents) -> TypeContents { v.iter().fold(TC::None, |tc, t| tc | f(t)) } @@ -1994,7 +2020,7 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { } ty_box(mt) => { - tc_mt(cx, mt, cache).other_pointer(TC::Managed) + tc_mt(cx, mt, cache).managed_pointer() } ty_trait(_, _, store, mutbl, bounds) => { @@ -2002,11 +2028,11 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { } ty_ptr(ref mt) => { - tc_ty(cx, mt.ty, cache).other_pointer(TC::None) + tc_ty(cx, mt.ty, cache).unsafe_pointer() } ty_rptr(r, ref mt) => { - tc_ty(cx, mt.ty, cache).other_pointer( + tc_ty(cx, mt.ty, cache).reference( borrowed_contents(r, mt.mutbl)) } @@ -2019,11 +2045,11 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { } ty_evec(mt, vstore_box) => { - tc_mt(cx, mt, cache).other_pointer(TC::Managed) + tc_mt(cx, mt, cache).managed_pointer() } ty_evec(ref mt, vstore_slice(r)) => { - tc_ty(cx, mt.ty, cache).other_pointer( + tc_ty(cx, mt.ty, cache).reference( borrowed_contents(r, mt.mutbl)) } @@ -2193,10 +2219,10 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { contents.owned_pointer() } BoxTraitStore => { - contents.other_pointer(TC::Managed) + contents.managed_pointer() } RegionTraitStore(r) => { - contents.other_pointer(borrowed_contents(r, mutbl)) + contents.reference(borrowed_contents(r, mutbl)) } } } @@ -2213,6 +2239,7 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { BoundSend => TC::Nonsendable, BoundFreeze => TC::Nonfreezable, BoundSized => TC::Nonsized, + BoundPod => TC::Nonpod, }; }); return tc; diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 9cc2d7dbb63..ca17d8aaab4 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -639,6 +639,7 @@ impl Repr for ty::ParamBounds { ty::BoundSend => ~"Send", ty::BoundFreeze => ~"Freeze", ty::BoundSized => ~"Sized", + ty::BoundPod => ~"Pod", }); } for t in self.trait_bounds.iter() { @@ -926,6 +927,7 @@ impl UserString for ty::BuiltinBound { ty::BoundSend => ~"Send", ty::BoundFreeze => ~"Freeze", ty::BoundSized => ~"Sized", + ty::BoundPod => ~"Pod", } } } diff --git a/src/libstd/cell.rs b/src/libstd/cell.rs index 1a87de63058..b33106a7f66 100644 --- a/src/libstd/cell.rs +++ b/src/libstd/cell.rs @@ -14,6 +14,71 @@ use prelude::*; use cast; use util::NonCopyable; +#[cfg(stage0)] +use unstable::intrinsics; + +/// A mutable memory location that admits only `Pod` data. +#[no_freeze] +#[deriving(Clone)] +pub struct Cell { + priv value: T, +} + +// NB: For `stage0`, we omit the `Pod` bound. This is unsound but will help +// us get started on removing `@mut` from `rustc`. + +#[cfg(stage0)] +impl Cell { + /// Creates a new `Cell` containing the given value. + pub fn new(value: T) -> Cell { + Cell { + value: value, + } + } + + /// Returns a copy of the contained value. + #[inline] + pub fn get(&self) -> T { + unsafe { + let mut result = intrinsics::uninit(); + intrinsics::copy_nonoverlapping_memory(&mut result, &self.value, 1); + result + } + } + + /// Sets the contained value. + #[inline] + pub fn set(&self, value: T) { + unsafe { + intrinsics::copy_nonoverlapping_memory(cast::transmute_mut(&self.value), &value, 1) + } + } +} + +#[cfg(not(stage0))] +impl Cell { + /// Creates a new `Cell` containing the given value. + pub fn new(value: T) -> Cell { + Cell { + value: value, + } + } + + /// Returns a copy of the contained value. + #[inline] + pub fn get(&self) -> T { + self.value + } + + /// Sets the contained value. + #[inline] + pub fn set(&self, value: T) { + unsafe { + *cast::transmute_mut(&self.value) = value + } + } +} + /// A mutable memory location with dynamically checked borrow rules #[no_freeze] pub struct RefCell { @@ -132,6 +197,30 @@ impl RefCell { let mut ptr = self.borrow_mut(); blk(ptr.get()) } + + /// Sets the value, replacing what was there. + /// + /// # Failure + /// + /// Fails if the value is currently borrowed. + #[inline] + pub fn set(&self, value: T) { + let mut reference = self.borrow_mut(); + *reference.get() = value + } +} + +impl RefCell { + /// Returns a copy of the contained value. + /// + /// # Failure + /// + /// Fails if the value is currently mutably borrowed. + #[inline] + pub fn get(&self) -> T { + let reference = self.borrow(); + (*reference.get()).clone() + } } impl Clone for RefCell { @@ -202,6 +291,17 @@ impl<'b, T> RefMut<'b, T> { mod test { use super::*; + #[test] + fn smoketest_cell() { + let x = Cell::new(10); + assert_eq!(x.get(), 10); + x.set(20); + assert_eq!(x.get(), 20); + + let y = Cell::new((30, 40)); + assert_eq!(y.get(), (30, 40)); + } + #[test] fn double_imm_borrow() { let x = RefCell::new(0); diff --git a/src/libstd/kinds.rs b/src/libstd/kinds.rs index 6a48e18a3cc..8d9fec1a4b7 100644 --- a/src/libstd/kinds.rs +++ b/src/libstd/kinds.rs @@ -37,3 +37,13 @@ pub trait Freeze { pub trait Sized { // Empty. } + +/// Types that can be copied by simply copying bits (i.e. `memcpy`). +/// +/// The name "POD" stands for "Plain Old Data" and is borrowed from C++. +#[cfg(not(stage0))] +#[lang="pod"] +pub trait Pod { + // Empty. +} + diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 83439d4c903..1a06ce1fb03 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -37,6 +37,9 @@ pub use ops::{Shl, Shr, Index}; pub use option::{Option, Some, None}; pub use result::{Result, Ok, Err}; +#[cfg(not(stage0))] +pub use kinds::Pod; + // Reexported functions pub use from_str::from_str; pub use iter::range; diff --git a/src/test/compile-fail/kindck-pod.rs b/src/test/compile-fail/kindck-pod.rs new file mode 100644 index 00000000000..60de67e214c --- /dev/null +++ b/src/test/compile-fail/kindck-pod.rs @@ -0,0 +1,86 @@ +// Copyright 2012 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. + +// Test which of the builtin types are considered POD. + +#[feature(managed_boxes)]; + +use std::rc::Rc; + +fn assert_pod() { } +trait Dummy { } + +struct MyStruct { + x: int, + y: int, +} + +struct MyNonpodStruct { + x: ~int, +} + +fn test<'a,T,U:Pod>(_: &'a int) { + // lifetime pointers are ok... + assert_pod::<&'static int>(); + assert_pod::<&'a int>(); + assert_pod::<&'a str>(); + assert_pod::<&'a [int]>(); + + // ...unless they are mutable + assert_pod::<&'static mut int>(); //~ ERROR does not fulfill `Pod` + assert_pod::<&'a mut int>(); //~ ERROR does not fulfill `Pod` + + // ~ pointers are not ok + assert_pod::<~int>(); //~ ERROR does not fulfill `Pod` + assert_pod::<~str>(); //~ ERROR does not fulfill `Pod` + assert_pod::<~[int]>(); //~ ERROR does not fulfill `Pod` + assert_pod::<~&'a mut int>(); //~ ERROR does not fulfill `Pod` + + // borrowed object types are generally ok + assert_pod::<&'a Dummy>(); + assert_pod::<&'a Dummy:Pod>(); + assert_pod::<&'static Dummy:Pod>(); + + // owned object types are not ok + assert_pod::<~Dummy>(); //~ ERROR does not fulfill `Pod` + assert_pod::<~Dummy:Pod>(); //~ ERROR does not fulfill `Pod` + + // mutable object types are not ok + assert_pod::<&'a mut Dummy:Pod>(); //~ ERROR does not fulfill `Pod` + + // closures are like an `&mut` object + assert_pod::<||>(); //~ ERROR does not fulfill `Pod` + + // unsafe ptrs are ok + assert_pod::<*int>(); + assert_pod::<*&'a mut int>(); + + // regular old ints and such are ok + assert_pod::(); + assert_pod::(); + assert_pod::<()>(); + + // tuples are ok + assert_pod::<(int,int)>(); + + // structs of POD are ok + assert_pod::(); + + // structs containing non-POD are not ok + assert_pod::(); //~ ERROR does not fulfill `Pod` + + // managed or ref counted types are not ok + assert_pod::<@int>(); //~ ERROR does not fulfill `Pod` + assert_pod::>(); //~ ERROR does not fulfill `Pod` +} + +pub fn main() { +} + diff --git a/src/test/run-pass/can-copy-pod.rs b/src/test/run-pass/can-copy-pod.rs new file mode 100644 index 00000000000..03341e6f946 --- /dev/null +++ b/src/test/run-pass/can-copy-pod.rs @@ -0,0 +1,15 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests that type parameters with the `Pod` are implicitly copyable. + +#[allow(dead_code)]; + +fn can_copy_pod(v: T) { + let _a = v; + let _b = v; +} + +pub fn main() {} + +