diff --git a/src/libextra/rl.rs b/src/libextra/rl.rs index c1eeb5005b265..59801c945b626 100644 --- a/src/libextra/rl.rs +++ b/src/libextra/rl.rs @@ -66,24 +66,28 @@ pub unsafe fn read(prompt: &str) -> Option<~str> { } } -pub type CompletionCb<'self> = @fn(~str, &'self fn(~str)); +pub type CompletionCb = @fn(~str, @fn(~str)); -fn complete_key(_v: @CompletionCb) {} +#[cfg(not(stage0))] +static complete_key: local_data::Key<@CompletionCb> = &local_data::Key; +#[cfg(stage0)] +fn complete_key(_: @CompletionCb) {} /// Bind to the main completion callback pub unsafe fn complete(cb: CompletionCb) { - local_data::set(complete_key, @(cb)); + local_data::set(complete_key, @cb); extern fn callback(line: *c_char, completions: *()) { - unsafe { - let cb = *local_data::get(complete_key, |k| k.map(|&k| *k)) - .get(); - - do cb(str::raw::from_c_str(line)) |suggestion| { - do str::as_c_str(suggestion) |buf| { - rustrt::linenoiseAddCompletion(completions, buf); + do local_data::get(complete_key) |cb| { + let cb = **cb.unwrap(); + + unsafe { + do cb(str::raw::from_c_str(line)) |suggestion| { + do str::as_c_str(suggestion) |buf| { + rustrt::linenoiseAddCompletion(completions, buf); + } } - } +} } } diff --git a/src/libextra/sort.rs b/src/libextra/sort.rs index d4d6162a9198f..db4ad43e41d7a 100644 --- a/src/libextra/sort.rs +++ b/src/libextra/sort.rs @@ -1195,39 +1195,4 @@ mod big_tests { isSorted(arr); } } - - struct LVal<'self> { - val: uint, - key: &'self fn:Copy(@uint), - } - - #[unsafe_destructor] - impl<'self> Drop for LVal<'self> { - fn drop(&self) { - let x = unsafe { local_data::get(self.key, |k| k.map(|&k| *k)) }; - match x { - Some(@y) => { - unsafe { - local_data::set(self.key, @(y+1)); - } - } - _ => fail!("Expected key to work"), - } - } - } - - impl<'self> Ord for LVal<'self> { - fn lt<'a>(&self, other: &'a LVal<'self>) -> bool { - (*self).val < other.val - } - fn le<'a>(&self, other: &'a LVal<'self>) -> bool { - (*self).val <= other.val - } - fn gt<'a>(&self, other: &'a LVal<'self>) -> bool { - (*self).val > other.val - } - fn ge<'a>(&self, other: &'a LVal<'self>) -> bool { - (*self).val >= other.val - } - } } diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 593a1ed535d6b..aeed2d842c131 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -105,6 +105,7 @@ pub mod jit { use metadata::cstore; use std::cast; + #[cfg(not(stage0))] use std::local_data; use std::unstable::intrinsics; @@ -202,18 +203,19 @@ pub mod jit { // The stage1 compiler won't work, but that doesn't really matter. TLS // changed only very recently to allow storage of owned values. - fn engine_key(_: ~Engine) {} + #[cfg(not(stage0))] + static engine_key: local_data::Key<~Engine> = &local_data::Key; #[cfg(not(stage0))] fn set_engine(engine: ~Engine) { - unsafe { local_data::set(engine_key, engine) } + local_data::set(engine_key, engine) } #[cfg(stage0)] fn set_engine(_: ~Engine) {} #[cfg(not(stage0))] pub fn consume_engine() -> Option<~Engine> { - unsafe { local_data::pop(engine_key) } + local_data::pop(engine_key) } #[cfg(stage0)] pub fn consume_engine() -> Option<~Engine> { None } diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index 83eb2db2fe77c..b679da714a174 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -209,7 +209,7 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[ LintSpec { lint: non_uppercase_statics, desc: "static constants should have uppercase identifiers", - default: warn + default: allow }), ("managed_heap_memory", diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 1173fa4941963..7182f7ff8b7d4 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -87,21 +87,20 @@ use syntax::abi::{X86, X86_64, Arm, Mips}; pub use middle::trans::context::task_llcx; -fn task_local_insn_key(_v: @~[&'static str]) {} +#[cfg(not(stage0))] +static task_local_insn_key: local_data::Key<@~[&'static str]> = &local_data::Key; +#[cfg(stage0)] +fn task_local_insn_key(_: @~[&'static str]) {} pub fn with_insn_ctxt(blk: &fn(&[&'static str])) { - unsafe { - let opt = local_data::get(task_local_insn_key, |k| k.map(|&k| *k)); - if opt.is_some() { - blk(*opt.unwrap()); - } + let opt = local_data::get(task_local_insn_key, |k| k.map(|&k| *k)); + if opt.is_some() { + blk(*opt.unwrap()); } } pub fn init_insn_ctxt() { - unsafe { - local_data::set(task_local_insn_key, @~[]); - } + local_data::set(task_local_insn_key, @~[]); } pub struct _InsnCtxt { _x: () } @@ -109,13 +108,11 @@ pub struct _InsnCtxt { _x: () } #[unsafe_destructor] impl Drop for _InsnCtxt { fn drop(&self) { - unsafe { - do local_data::modify(task_local_insn_key) |c| { - do c.map_consume |ctx| { - let mut ctx = copy *ctx; - ctx.pop(); - @ctx - } + do local_data::modify(task_local_insn_key) |c| { + do c.map_consume |ctx| { + let mut ctx = copy *ctx; + ctx.pop(); + @ctx } } } @@ -123,13 +120,11 @@ impl Drop for _InsnCtxt { pub fn push_ctxt(s: &'static str) -> _InsnCtxt { debug!("new InsnCtxt: %s", s); - unsafe { - do local_data::modify(task_local_insn_key) |c| { - do c.map_consume |ctx| { - let mut ctx = copy *ctx; - ctx.push(s); - @ctx - } + do local_data::modify(task_local_insn_key) |c| { + do c.map_consume |ctx| { + let mut ctx = copy *ctx; + ctx.push(s); + @ctx } } _InsnCtxt { _x: () } @@ -1428,7 +1423,7 @@ pub fn with_scope(bcx: block, pub fn with_scope_result(bcx: block, opt_node_info: Option, - name: &str, + _name: &str, f: &fn(block) -> Result) -> Result { let _icx = push_ctxt("with_scope_result"); diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index 7b7989879a639..42f6a4dad6b74 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -197,7 +197,7 @@ fn get_impl_resolutions(bcx: block, impl_id: ast::def_id) -> typeck::vtable_res { if impl_id.crate == ast::local_crate { - *bcx.ccx().maps.vtable_map.get(&impl_id.node) + bcx.ccx().maps.vtable_map.get_copy(&impl_id.node) } else { // XXX: This is a temporary hack to work around not properly // exporting information about resolutions for impls. @@ -670,15 +670,13 @@ pub fn trans_call_inner(in_cx: block, None => { assert!(ty::type_is_immediate(bcx.tcx(), ret_ty)) } Some(expr::Ignore) => { // drop the value if it is not being saved. - unsafe { - if ty::type_needs_drop(bcx.tcx(), ret_ty) { - if ty::type_is_immediate(bcx.tcx(), ret_ty) { - let llscratchptr = alloc_ty(bcx, ret_ty, "__ret"); - Store(bcx, llresult, llscratchptr); - bcx = glue::drop_ty(bcx, llscratchptr, ret_ty); - } else { - bcx = glue::drop_ty(bcx, llretslot, ret_ty); - } + if ty::type_needs_drop(bcx.tcx(), ret_ty) { + if ty::type_is_immediate(bcx.tcx(), ret_ty) { + let llscratchptr = alloc_ty(bcx, ret_ty, "__ret"); + Store(bcx, llresult, llscratchptr); + bcx = glue::drop_ty(bcx, llscratchptr, ret_ty); + } else { + bcx = glue::drop_ty(bcx, llretslot, ret_ty); } } } diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs index 1557916658df7..ffebb87d5cf04 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -232,22 +232,24 @@ impl CrateContext { #[unsafe_destructor] impl Drop for CrateContext { fn drop(&self) { - unsafe { - unset_task_llcx(); - } + unset_task_llcx(); } } +#[cfg(stage0)] fn task_local_llcx_key(_v: @ContextRef) {} +#[cfg(not(stage0))] +static task_local_llcx_key: local_data::Key<@ContextRef> = &local_data::Key; + pub fn task_llcx() -> ContextRef { - let opt = unsafe { local_data::get(task_local_llcx_key, |k| k.map(|&k| *k)) }; + let opt = local_data::get(task_local_llcx_key, |k| k.map(|&k| *k)); *opt.expect("task-local LLVMContextRef wasn't ever set!") } -unsafe fn set_task_llcx(c: ContextRef) { +fn set_task_llcx(c: ContextRef) { local_data::set(task_local_llcx_key, @c); } -unsafe fn unset_task_llcx() { +fn unset_task_llcx() { local_data::pop(task_local_llcx_key); } diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs index 81260428f241b..e03a6e7c167cc 100644 --- a/src/librustc/middle/trans/controlflow.rs +++ b/src/librustc/middle/trans/controlflow.rs @@ -254,7 +254,7 @@ pub fn trans_break_cont(bcx: block, // Locate closest loop block, outputting cleanup as we go. let mut unwind = bcx; let mut cur_scope = unwind.scope; - let mut target = unwind; + let mut target; loop { cur_scope = match cur_scope { Some(@scope_info { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index a79f08b33c937..8e23f5431bcee 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3621,25 +3621,29 @@ pub fn trait_method_def_ids(cx: ctxt, id: ast::def_id) -> @~[def_id] { } pub fn impl_trait_ref(cx: ctxt, id: ast::def_id) -> Option<@TraitRef> { - *do cx.impl_trait_cache.find_or_insert_with(id) |_| { - if id.crate == ast::local_crate { - debug!("(impl_trait_ref) searching for trait impl %?", id); - match cx.items.find(&id.node) { - Some(&ast_map::node_item(@ast::item { - node: ast::item_impl(_, ref opt_trait, _, _), - _}, - _)) => { - match opt_trait { - &Some(ref t) => Some(ty::node_id_to_trait_ref(cx, t.ref_id)), - &None => None - } + match cx.impl_trait_cache.find(&id) { + Some(&ret) => { return ret; } + None => {} + } + let ret = if id.crate == ast::local_crate { + debug!("(impl_trait_ref) searching for trait impl %?", id); + match cx.items.find(&id.node) { + Some(&ast_map::node_item(@ast::item { + node: ast::item_impl(_, ref opt_trait, _, _), + _}, + _)) => { + match opt_trait { + &Some(ref t) => Some(ty::node_id_to_trait_ref(cx, t.ref_id)), + &None => None } - _ => None } - } else { - csearch::get_impl_trait(cx, id) + _ => None } - } + } else { + csearch::get_impl_trait(cx, id) + }; + cx.impl_trait_cache.insert(id, ret); + return ret; } pub fn ty_to_def_id(ty: t) -> Option { diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index 6f5dde74b5c10..b8b8ab3145d54 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -303,7 +303,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt, let tcx = ccx.tcx; let main_t = ty::node_id_to_type(tcx, main_id); match ty::get(main_t).sty { - ty::ty_bare_fn(ref fn_ty) => { + ty::ty_bare_fn(*) => { match tcx.items.find(&main_id) { Some(&ast_map::node_item(it,_)) => { match it.node { diff --git a/src/librustc/rustc.rs b/src/librustc/rustc.rs index 1e5e9ece288e8..787d8d5685a34 100644 --- a/src/librustc/rustc.rs +++ b/src/librustc/rustc.rs @@ -18,8 +18,6 @@ #[crate_type = "lib"]; #[allow(non_implicitly_copyable_typarams)]; -#[allow(non_camel_case_types)]; -#[allow(non_uppercase_statics)]; #[deny(deprecated_pattern)]; extern mod extra; diff --git a/src/librusti/program.rs b/src/librusti/program.rs index 716c7a2481eed..9031a001eca60 100644 --- a/src/librusti/program.rs +++ b/src/librusti/program.rs @@ -11,7 +11,6 @@ use std::cast; use std::hashmap::HashMap; use std::local_data; -use std::sys; use syntax::ast; use syntax::parse::token; @@ -58,7 +57,7 @@ struct LocalVariable { } type LocalCache = @mut HashMap<~str, @~[u8]>; -fn tls_key(_k: LocalCache) {} +static tls_key: local_data::Key = &local_data::Key; impl Program { pub fn new() -> Program { @@ -131,21 +130,16 @@ impl Program { fn main() { "); - let key: sys::Closure = unsafe { - let tls_key: &'static fn(LocalCache) = tls_key; - cast::transmute(tls_key) - }; + let key: uint= unsafe { cast::transmute(tls_key) }; // First, get a handle to the tls map which stores all the local // variables. This works by totally legitimately using the 'code' // pointer of the 'tls_key' function as a uint, and then casting it back // up to a function code.push_str(fmt!(" let __tls_map: @mut ::std::hashmap::HashMap<~str, @~[u8]> = unsafe { - let key = ::std::sys::Closure{ code: %? as *(), - env: ::std::ptr::null() }; - let key = ::std::cast::transmute(key); + let key = ::std::cast::transmute(%u); ::std::local_data::get(key, |k| k.map(|&x| *x)).unwrap() - };\n", key.code as uint)); + };\n", key as uint)); // Using this __tls_map handle, deserialize each variable binding that // we know about @@ -226,18 +220,14 @@ impl Program { for self.local_vars.iter().advance |(name, value)| { map.insert(copy *name, @copy value.data); } - unsafe { - local_data::set(tls_key, map); - } + local_data::set(tls_key, map); } /// Once the program has finished running, this function will consume the /// task-local cache of local variables. After the program finishes running, /// it updates this cache with the new values of each local variable. pub fn consume_cache(&mut self) { - let map = unsafe { - local_data::pop(tls_key).expect("tls is empty") - }; + let map = local_data::pop(tls_key).expect("tls is empty"); do map.consume |name, value| { match self.local_vars.find_mut(&name) { Some(v) => { v.data = copy *value; } diff --git a/src/libstd/condition.rs b/src/libstd/condition.rs index d6d09527f8301..3a5be12b3c586 100644 --- a/src/libstd/condition.rs +++ b/src/libstd/condition.rs @@ -23,13 +23,59 @@ pub struct Handler { prev: Option<@Handler>, } +#[cfg(stage0)] pub struct Condition<'self, T, U> { name: &'static str, key: local_data::Key<'self, @Handler> } +#[cfg(not(stage0))] +pub struct Condition { + name: &'static str, + key: local_data::Key<@Handler> +} + +#[cfg(not(stage0))] +impl Condition { + pub fn trap<'a>(&'a self, h: &'a fn(T) -> U) -> Trap<'a, T, U> { + unsafe { + let p : *RustClosure = ::cast::transmute(&h); + let prev = local_data::get(self.key, |k| k.map(|&x| *x)); + let h = @Handler { handle: *p, prev: prev }; + Trap { cond: self, handler: h } + } + } + + pub fn raise(&self, t: T) -> U { + let msg = fmt!("Unhandled condition: %s: %?", self.name, t); + self.raise_default(t, || fail!(copy msg)) + } + pub fn raise_default(&self, t: T, default: &fn() -> U) -> U { + unsafe { + match local_data::pop(self.key) { + None => { + debug!("Condition.raise: found no handler"); + default() + } + Some(handler) => { + debug!("Condition.raise: found handler"); + match handler.prev { + None => {} + Some(hp) => local_data::set(self.key, hp) + } + let handle : &fn(T) -> U = + ::cast::transmute(handler.handle); + let u = handle(t); + local_data::set(self.key, handler); + u + } + } + } + } +} +#[cfg(stage0)] impl<'self, T, U> Condition<'self, T, U> { - pub fn trap(&'self self, h: &'self fn(T) -> U) -> Trap<'self, T, U> { + pub fn trap<'a>(&'a self, h: &'a fn(T) -> U) -> Trap<'a, T, U> { unsafe { let p : *RustClosure = ::cast::transmute(&h); let prev = local_data::get(self.key, |k| k.map(|&x| *x)); @@ -67,38 +113,45 @@ impl<'self, T, U> Condition<'self, T, U> { } } +#[cfg(stage0)] struct Trap<'self, T, U> { cond: &'self Condition<'self, T, U>, handler: @Handler } +#[cfg(not(stage0))] +struct Trap<'self, T, U> { + cond: &'self Condition, + handler: @Handler +} impl<'self, T, U> Trap<'self, T, U> { pub fn in(&self, inner: &'self fn() -> V) -> V { - unsafe { - let _g = Guard { cond: self.cond }; - debug!("Trap: pushing handler to TLS"); - local_data::set(self.cond.key, self.handler); - inner() - } + let _g = Guard { cond: self.cond }; + debug!("Trap: pushing handler to TLS"); + local_data::set(self.cond.key, self.handler); + inner() } } +#[cfg(stage0)] struct Guard<'self, T, U> { cond: &'self Condition<'self, T, U> } +#[cfg(not(stage0))] +struct Guard<'self, T, U> { + cond: &'self Condition +} #[unsafe_destructor] impl<'self, T, U> Drop for Guard<'self, T, U> { fn drop(&self) { - unsafe { - debug!("Guard: popping handler from TLS"); - let curr = local_data::pop(self.cond.key); - match curr { + debug!("Guard: popping handler from TLS"); + let curr = local_data::pop(self.cond.key); + match curr { + None => {} + Some(h) => match h.prev { None => {} - Some(h) => match h.prev { - None => {} - Some(hp) => local_data::set(self.cond.key, hp) - } + Some(hp) => local_data::set(self.cond.key, hp) } } } diff --git a/src/libstd/local_data.rs b/src/libstd/local_data.rs index b241de887004c..be170cce07e54 100644 --- a/src/libstd/local_data.rs +++ b/src/libstd/local_data.rs @@ -12,27 +12,26 @@ Task local data management -Allows storing boxes with arbitrary types inside, to be accessed anywhere within -a task, keyed by a pointer to a global finaliser function. Useful for dynamic -variables, singletons, and interfacing with foreign code with bad callback -interfaces. +Allows storing arbitrary types inside task-local-storage (TLS), to be accessed +anywhere within a task, keyed by a global pointer parameterized over the type of +the TLS slot. Useful for dynamic variables, singletons, and interfacing with +foreign code with bad callback interfaces. -To use, declare a monomorphic (no type parameters) global function at the type -to store, and use it as the 'key' when accessing. +To use, declare a static variable of the type you wish to store. The +initialization should be `&local_data::Key`. This is then the key to what you +wish to store. ~~~{.rust} use std::local_data; -fn key_int(_: @int) {} -fn key_vector(_: @~[int]) {} +static key_int: local_data::Key = &local_data::Key; +static key_vector: local_data::Key<~[int]> = &local_data::Key; -unsafe { - local_data::set(key_int, @3); - assert!(local_data::get(key_int) == Some(@3)); +local_data::set(key_int, 3); +local_data::get(key_int, |opt| assert_eq!(opt, Some(&3))); - local_data::set(key_vector, @~[3]); - assert!(local_data::get(key_vector).unwrap()[0] == 3); -} +local_data::set(key_vector, ~[4]); +local_data::get(key_int, |opt| assert_eq!(opt, Some(&~[4]))); ~~~ Casting 'Arcane Sight' reveals an overwhelming aura of Transmutation @@ -47,76 +46,77 @@ use task::local_data_priv::{local_get, local_pop, local_set, Handle}; #[cfg(test)] use task; /** - * Indexes a task-local data slot. The function's code pointer is used for - * comparison. Recommended use is to write an empty function for each desired - * task-local data slot (and use class destructors, not code inside the - * function, if specific teardown is needed). DO NOT use multiple - * instantiations of a single polymorphic function to index data of different - * types; arbitrary type coercion is possible this way. - * - * One other exception is that this global state can be used in a destructor - * context to create a circular @-box reference, which will crash during task - * failure (see issue #3039). + * Indexes a task-local data slot. This pointer is used for comparison to + * differentiate keys from one another. The actual type `T` is not used anywhere + * as a member of this type, except that it is parameterized with it to define + * the type of each key's value. * - * These two cases aside, the interface is safe. + * The value of each Key is of the singleton enum KeyValue. These also have the + * same name as `Key` and their purpose is to take up space in the programs data + * sections to ensure that each value of the `Key` type points to a unique + * location. */ +#[cfg(not(stage0))] +pub type Key = &'static KeyValue; +#[cfg(stage0)] pub type Key<'self,T> = &'self fn:Copy(v: T); +pub enum KeyValue { Key } + /** * Remove a task-local data value from the table, returning the * reference that was originally created to insert it. */ #[cfg(stage0)] -pub unsafe fn pop(key: Key<@T>) -> Option<@T> { - local_pop(Handle::new(), key) +pub fn pop(key: Key<@T>) -> Option<@T> { + unsafe { local_pop(Handle::new(), key) } } /** * Remove a task-local data value from the table, returning the * reference that was originally created to insert it. */ #[cfg(not(stage0))] -pub unsafe fn pop(key: Key) -> Option { - local_pop(Handle::new(), key) +pub fn pop(key: Key) -> Option { + unsafe { local_pop(Handle::new(), key) } } /** * Retrieve a task-local data value. It will also be kept alive in the * table until explicitly removed. */ #[cfg(stage0)] -pub unsafe fn get(key: Key<@T>, f: &fn(Option<&@T>) -> U) -> U { - local_get(Handle::new(), key, f) +pub fn get(key: Key<@T>, f: &fn(Option<&@T>) -> U) -> U { + unsafe { local_get(Handle::new(), key, f) } } /** * Retrieve a task-local data value. It will also be kept alive in the * table until explicitly removed. */ #[cfg(not(stage0))] -pub unsafe fn get(key: Key, f: &fn(Option<&T>) -> U) -> U { - local_get(Handle::new(), key, f) +pub fn get(key: Key, f: &fn(Option<&T>) -> U) -> U { + unsafe { local_get(Handle::new(), key, f) } } /** * Store a value in task-local data. If this key already has a value, * that value is overwritten (and its destructor is run). */ #[cfg(stage0)] -pub unsafe fn set(key: Key<@T>, data: @T) { - local_set(Handle::new(), key, data) +pub fn set(key: Key<@T>, data: @T) { + unsafe { local_set(Handle::new(), key, data) } } /** * Store a value in task-local data. If this key already has a value, * that value is overwritten (and its destructor is run). */ #[cfg(not(stage0))] -pub unsafe fn set(key: Key, data: T) { - local_set(Handle::new(), key, data) +pub fn set(key: Key, data: T) { + unsafe { local_set(Handle::new(), key, data) } } /** * Modify a task-local data value. If the function returns 'None', the * data is removed (and its reference dropped). */ #[cfg(stage0)] -pub unsafe fn modify(key: Key<@T>, - f: &fn(Option<@T>) -> Option<@T>) { +pub fn modify(key: Key<@T>, f: &fn(Option<@T>) -> Option<@T>) { match f(pop(key)) { Some(next) => { set(key, next); } None => {} @@ -127,8 +127,7 @@ pub unsafe fn modify(key: Key<@T>, * data is removed (and its reference dropped). */ #[cfg(not(stage0))] -pub unsafe fn modify(key: Key, - f: &fn(Option) -> Option) { +pub fn modify(key: Key, f: &fn(Option) -> Option) { match f(pop(key)) { Some(next) => { set(key, next); } None => {} @@ -137,64 +136,56 @@ pub unsafe fn modify(key: Key, #[test] fn test_tls_multitask() { - unsafe { - fn my_key(_x: @~str) { } - set(my_key, @~"parent data"); - do task::spawn { - // TLS shouldn't carry over. - assert!(get(my_key, |k| k.map(|&k| *k)).is_none()); - set(my_key, @~"child data"); - assert!(*(get(my_key, |k| k.map(|&k| *k)).get()) == - ~"child data"); - // should be cleaned up for us - } - // Must work multiple times - assert!(*(get(my_key, |k| k.map(|&k| *k)).get()) == ~"parent data"); - assert!(*(get(my_key, |k| k.map(|&k| *k)).get()) == ~"parent data"); - assert!(*(get(my_key, |k| k.map(|&k| *k)).get()) == ~"parent data"); + static my_key: Key<@~str> = &Key; + set(my_key, @~"parent data"); + do task::spawn { + // TLS shouldn't carry over. + assert!(get(my_key, |k| k.map(|&k| *k)).is_none()); + set(my_key, @~"child data"); + assert!(*(get(my_key, |k| k.map(|&k| *k)).get()) == + ~"child data"); + // should be cleaned up for us } + // Must work multiple times + assert!(*(get(my_key, |k| k.map(|&k| *k)).get()) == ~"parent data"); + assert!(*(get(my_key, |k| k.map(|&k| *k)).get()) == ~"parent data"); + assert!(*(get(my_key, |k| k.map(|&k| *k)).get()) == ~"parent data"); } #[test] fn test_tls_overwrite() { - unsafe { - fn my_key(_x: @~str) { } - set(my_key, @~"first data"); - set(my_key, @~"next data"); // Shouldn't leak. - assert!(*(get(my_key, |k| k.map(|&k| *k)).get()) == ~"next data"); - } + static my_key: Key<@~str> = &Key; + set(my_key, @~"first data"); + set(my_key, @~"next data"); // Shouldn't leak. + assert!(*(get(my_key, |k| k.map(|&k| *k)).get()) == ~"next data"); } #[test] fn test_tls_pop() { - unsafe { - fn my_key(_x: @~str) { } - set(my_key, @~"weasel"); - assert!(*(pop(my_key).get()) == ~"weasel"); - // Pop must remove the data from the map. - assert!(pop(my_key).is_none()); - } + static my_key: Key<@~str> = &Key; + set(my_key, @~"weasel"); + assert!(*(pop(my_key).get()) == ~"weasel"); + // Pop must remove the data from the map. + assert!(pop(my_key).is_none()); } #[test] fn test_tls_modify() { - unsafe { - fn my_key(_x: @~str) { } - modify(my_key, |data| { - match data { - Some(@ref val) => fail!("unwelcome value: %s", *val), - None => Some(@~"first data") - } - }); - modify(my_key, |data| { - match data { - Some(@~"first data") => Some(@~"next data"), - Some(@ref val) => fail!("wrong value: %s", *val), - None => fail!("missing value") - } - }); - assert!(*(pop(my_key).get()) == ~"next data"); - } + static my_key: Key<@~str> = &Key; + modify(my_key, |data| { + match data { + Some(@ref val) => fail!("unwelcome value: %s", *val), + None => Some(@~"first data") + } + }); + modify(my_key, |data| { + match data { + Some(@~"first data") => Some(@~"next data"), + Some(@ref val) => fail!("wrong value: %s", *val), + None => fail!("missing value") + } + }); + assert!(*(pop(my_key).get()) == ~"next data"); } #[test] @@ -205,40 +196,36 @@ fn test_tls_crust_automorestack_memorial_bug() { // to get recorded as something within a rust stack segment. Then a // subsequent upcall (esp. for logging, think vsnprintf) would run on // a stack smaller than 1 MB. - fn my_key(_x: @~str) { } + static my_key: Key<@~str> = &Key; do task::spawn { - unsafe { set(my_key, @~"hax"); } + set(my_key, @~"hax"); } } #[test] fn test_tls_multiple_types() { - fn str_key(_x: @~str) { } - fn box_key(_x: @@()) { } - fn int_key(_x: @int) { } + static str_key: Key<@~str> = &Key; + static box_key: Key<@@()> = &Key; + static int_key: Key<@int> = &Key; do task::spawn { - unsafe { - set(str_key, @~"string data"); - set(box_key, @@()); - set(int_key, @42); - } + set(str_key, @~"string data"); + set(box_key, @@()); + set(int_key, @42); } } #[test] fn test_tls_overwrite_multiple_types() { - fn str_key(_x: @~str) { } - fn box_key(_x: @@()) { } - fn int_key(_x: @int) { } + static str_key: Key<@~str> = &Key; + static box_key: Key<@@()> = &Key; + static int_key: Key<@int> = &Key; do task::spawn { - unsafe { - set(str_key, @~"string data"); - set(int_key, @42); - // This could cause a segfault if overwriting-destruction is done - // with the crazy polymorphic transmute rather than the provided - // finaliser. - set(int_key, @31337); - } + set(str_key, @~"string data"); + set(int_key, @42); + // This could cause a segfault if overwriting-destruction is done + // with the crazy polymorphic transmute rather than the provided + // finaliser. + set(int_key, @31337); } } @@ -246,38 +233,53 @@ fn test_tls_overwrite_multiple_types() { #[should_fail] #[ignore(cfg(windows))] fn test_tls_cleanup_on_failure() { - unsafe { - fn str_key(_x: @~str) { } - fn box_key(_x: @@()) { } - fn int_key(_x: @int) { } - set(str_key, @~"parent data"); + static str_key: Key<@~str> = &Key; + static box_key: Key<@@()> = &Key; + static int_key: Key<@int> = &Key; + set(str_key, @~"parent data"); + set(box_key, @@()); + do task::spawn { + // spawn_linked + set(str_key, @~"string data"); set(box_key, @@()); - do task::spawn { - // spawn_linked - set(str_key, @~"string data"); - set(box_key, @@()); - set(int_key, @42); - fail!(); - } - // Not quite nondeterministic. - set(int_key, @31337); + set(int_key, @42); fail!(); } + // Not quite nondeterministic. + set(int_key, @31337); + fail!(); } #[test] fn test_static_pointer() { - unsafe { - fn key(_x: @&'static int) { } - static VALUE: int = 0; - set(key, @&VALUE); - } + static key: Key<@&'static int> = &Key; + static VALUE: int = 0; + let v: @&'static int = @&VALUE; + set(key, v); } #[test] fn test_owned() { - unsafe { - fn key(_x: ~int) { } - set(key, ~1); - } + static key: Key<~int> = &Key; + set(key, ~1); +} + +#[test] +fn test_same_key_type() { + static key1: Key = &Key; + static key2: Key = &Key; + static key3: Key = &Key; + static key4: Key = &Key; + static key5: Key = &Key; + set(key1, 1); + set(key2, 2); + set(key3, 3); + set(key4, 4); + set(key5, 5); + + get(key1, |x| assert_eq!(*x.unwrap(), 1)); + get(key2, |x| assert_eq!(*x.unwrap(), 2)); + get(key3, |x| assert_eq!(*x.unwrap(), 3)); + get(key4, |x| assert_eq!(*x.unwrap(), 4)); + get(key5, |x| assert_eq!(*x.unwrap(), 5)); } diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 8d70732641d8c..58175db1241d2 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -1239,7 +1239,10 @@ struct OverriddenArgs { val: ~[~str] } +#[cfg(stage0)] fn overridden_arg_key(_v: @OverriddenArgs) {} +#[cfg(not(stage0))] +static overridden_arg_key: local_data::Key<@OverriddenArgs> = &local_data::Key; /// Returns the arguments which this program was started with (normally passed /// via the command line). @@ -1247,11 +1250,9 @@ fn overridden_arg_key(_v: @OverriddenArgs) {} /// The return value of the function can be changed by invoking the /// `os::set_args` function. pub fn args() -> ~[~str] { - unsafe { - match local_data::get(overridden_arg_key, |k| k.map(|&k| *k)) { - None => real_args(), - Some(args) => copy args.val - } + match local_data::get(overridden_arg_key, |k| k.map(|&k| *k)) { + None => real_args(), + Some(args) => copy args.val } } @@ -1259,10 +1260,8 @@ pub fn args() -> ~[~str] { /// program had when it started. These new arguments are only available to the /// current task via the `os::args` method. pub fn set_args(new_args: ~[~str]) { - unsafe { - let overridden_args = @OverriddenArgs { val: copy new_args }; - local_data::set(overridden_arg_key, overridden_args); - } + let overridden_args = @OverriddenArgs { val: copy new_args }; + local_data::set(overridden_arg_key, overridden_args); } // FIXME #6100 we should really use an internal implementation of this - using diff --git a/src/libstd/rand.rs b/src/libstd/rand.rs index 2cf45ba70ec0e..6f89e7ffb0794 100644 --- a/src/libstd/rand.rs +++ b/src/libstd/rand.rs @@ -851,7 +851,10 @@ pub fn seed() -> ~[u8] { } // used to make space in TLS for a random number generator +#[cfg(stage0)] fn tls_rng_state(_v: @@mut IsaacRng) {} +#[cfg(not(stage0))] +static tls_rng_state: local_data::Key<@@mut IsaacRng> = &local_data::Key; /** * Gives back a lazily initialized task-local random number generator, @@ -860,17 +863,12 @@ fn tls_rng_state(_v: @@mut IsaacRng) {} */ #[inline] pub fn task_rng() -> @mut IsaacRng { - let r : Option<@@mut IsaacRng>; - unsafe { - r = local_data::get(tls_rng_state, |k| k.map(|&k| *k)); - } + let r = local_data::get(tls_rng_state, |k| k.map(|&k| *k)); match r { None => { - unsafe { - let rng = @@mut IsaacRng::new_seeded(seed()); - local_data::set(tls_rng_state, rng); - *rng - } + let rng = @@mut IsaacRng::new_seeded(seed()); + local_data::set(tls_rng_state, rng); + *rng } Some(rng) => *rng } diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index c5961be40ecbe..17d0d59660f1b 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -348,14 +348,12 @@ mod test { fn tls() { use local_data; do run_in_newsched_task() { - unsafe { - fn key(_x: @~str) { } - local_data::set(key, @~"data"); - assert!(*local_data::get(key, |k| k.map(|&k| *k)).get() == ~"data"); - fn key2(_x: @~str) { } - local_data::set(key2, @~"data"); - assert!(*local_data::get(key2, |k| k.map(|&k| *k)).get() == ~"data"); - } + static key: local_data::Key<@~str> = &local_data::Key; + local_data::set(key, @~"data"); + assert!(*local_data::get(key, |k| k.map(|&k| *k)).get() == ~"data"); + static key2: local_data::Key<@~str> = &local_data::Key; + local_data::set(key2, @~"data"); + assert!(*local_data::get(key2, |k| k.map(|&k| *k)).get() == ~"data"); } } diff --git a/src/libstd/std.rs b/src/libstd/std.rs index 8f86216d24070..03b895b38601a 100644 --- a/src/libstd/std.rs +++ b/src/libstd/std.rs @@ -222,6 +222,7 @@ mod std { pub use condition; pub use option; pub use kinds; + pub use local_data; pub use sys; pub use pipes; pub use unstable; diff --git a/src/libstd/task/local_data_priv.rs b/src/libstd/task/local_data_priv.rs index 42cfcbc16dbf8..d46e5707f14a9 100644 --- a/src/libstd/task/local_data_priv.rs +++ b/src/libstd/task/local_data_priv.rs @@ -15,7 +15,6 @@ use libc; use local_data; use prelude::*; use ptr; -use sys; use task::rt; use util; @@ -142,9 +141,8 @@ unsafe fn get_local_map(handle: Handle) -> &mut TaskLocalMap { } } -unsafe fn key_to_key_value(key: local_data::Key) -> *libc::c_void { - let pair: sys::Closure = cast::transmute(key); - return pair.code as *libc::c_void; +fn key_to_key_value(key: local_data::Key) -> *libc::c_void { + unsafe { cast::transmute(key) } } pub unsafe fn local_pop(handle: Handle, diff --git a/src/libstd/task/spawn.rs b/src/libstd/task/spawn.rs index 27cb1c2c1000a..206d19e175fe9 100644 --- a/src/libstd/task/spawn.rs +++ b/src/libstd/task/spawn.rs @@ -80,6 +80,7 @@ use cell::Cell; use container::MutableMap; use comm::{Chan, GenericChan}; use hashmap::HashSet; +use local_data; use task::local_data_priv::{local_get, local_set, OldHandle}; use task::rt::rust_task; use task::rt; @@ -465,10 +466,14 @@ fn kill_taskgroup(state: TaskGroupInner, me: *rust_task, is_main: bool) { // FIXME (#2912): Work around core-vs-coretest function duplication. Can't use // a proper closure because the #[test]s won't understand. Have to fake it. -macro_rules! taskgroup_key ( - // Use a "code pointer" value that will never be a real code pointer. - () => (cast::transmute((-2 as uint, 0u))) -) +#[cfg(not(stage0))] +fn taskgroup_key() -> local_data::Key<@@mut TCB> { + unsafe { cast::transmute(-2) } +} +#[cfg(stage0)] +fn taskgroup_key() -> local_data::Key<@@mut TCB> { + unsafe { cast::transmute((-2, 0)) } +} fn gen_child_taskgroup(linked: bool, supervised: bool) -> (TaskGroupArc, AncestorList, bool) { @@ -478,7 +483,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool) * Step 1. Get spawner's taskgroup info. *##################################################################*/ let spawner_group: @@mut TCB = - do local_get(OldHandle(spawner), taskgroup_key!()) |group| { + do local_get(OldHandle(spawner), taskgroup_key()) |group| { match group { None => { // Main task, doing first spawn ever. Lazily initialise @@ -495,7 +500,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool) AncestorList(None), true, None); - local_set(OldHandle(spawner), taskgroup_key!(), group); + local_set(OldHandle(spawner), taskgroup_key(), group); group } Some(&group) => group @@ -688,7 +693,7 @@ fn spawn_raw_oldsched(mut opts: TaskOpts, f: ~fn()) { is_main, notifier); unsafe { - local_set(OldHandle(child), taskgroup_key!(), group); + local_set(OldHandle(child), taskgroup_key(), group); } // Run the child's body. diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 7567dc0000be1..a1d209d19ac56 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -20,7 +20,6 @@ use std::hashmap::HashMap; use std::int; use std::num; use std::option; -use std::cast; use std::local_data; pub fn path_name_i(idents: &[ident]) -> ~str { @@ -695,18 +694,17 @@ pub fn new_sctable_internal() -> SCTable { // fetch the SCTable from TLS, create one if it doesn't yet exist. pub fn get_sctable() -> @mut SCTable { - unsafe { - let sctable_key = (cast::transmute::<(uint, uint), - &fn:Copy(v: @@mut SCTable)>( - (-4 as uint, 0u))); - match local_data::get(sctable_key, |k| k.map(|&k| *k)) { - None => { - let new_table = @@mut new_sctable_internal(); - local_data::set(sctable_key,new_table); - *new_table - }, - Some(intr) => *intr - } + #[cfg(not(stage0))] + static sctable_key: local_data::Key<@@mut SCTable> = &local_data::Key; + #[cfg(stage0)] + fn sctable_key(_: @@mut SCTable) {} + match local_data::get(sctable_key, |k| k.map(|&k| *k)) { + None => { + let new_table = @@mut new_sctable_internal(); + local_data::set(sctable_key,new_table); + *new_table + }, + Some(intr) => *intr } } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 2c3f42cca9aac..b45cde6a8e342 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -579,11 +579,13 @@ pub fn core_macros() -> @str { { pub $c:ident: $in:ty -> $out:ty; } => { pub mod $c { - fn key(_x: @::std::condition::Handler<$in,$out>) { } + #[allow(non_uppercase_statics)]; + static key: ::std::local_data::Key< + @::std::condition::Handler<$in, $out>> = + &::std::local_data::Key; - #[allow(non_uppercase_statics)] pub static cond : - ::std::condition::Condition<'static,$in,$out> = + ::std::condition::Condition<$in,$out> = ::std::condition::Condition { name: stringify!($c), key: key @@ -595,11 +597,13 @@ pub fn core_macros() -> @str { // FIXME (#6009): remove mod's `pub` below once variant above lands. pub mod $c { - fn key(_x: @::std::condition::Handler<$in,$out>) { } + #[allow(non_uppercase_statics)]; + static key: ::std::local_data::Key< + @::std::condition::Handler<$in, $out>> = + &::std::local_data::Key; - #[allow(non_uppercase_statics)] pub static cond : - ::std::condition::Condition<'static,$in,$out> = + ::std::condition::Condition<$in,$out> = ::std::condition::Condition { name: stringify!($c), key: key diff --git a/src/libsyntax/ext/pipes/proto.rs b/src/libsyntax/ext/pipes/proto.rs index 75424b60390d7..5866b8a5af55d 100644 --- a/src/libsyntax/ext/pipes/proto.rs +++ b/src/libsyntax/ext/pipes/proto.rs @@ -144,7 +144,8 @@ pub struct protocol_ { impl protocol_ { /// Get a state. pub fn get_state(&self, name: &str) -> state { - *self.states.iter().find_(|i| name == i.name).get() + let mut i = self.states.iter(); + *i.find_(|i| name == i.name).get() } pub fn get_state_by_id(&self, id: uint) -> state { self.states[id] } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 46e0ef32321a5..01860c3ae995b 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -15,7 +15,6 @@ use parse::token; use util::interner::StrInterner; use util::interner; -use std::cast; use std::cmp::Equiv; use std::local_data; use std::rand; @@ -485,18 +484,17 @@ fn mk_fresh_ident_interner() -> @ident_interner { // if an interner exists in TLS, return it. Otherwise, prepare a // fresh one. pub fn get_ident_interner() -> @ident_interner { - unsafe { - let key = - (cast::transmute::<(uint, uint), - &fn:Copy(v: @@::parse::token::ident_interner)>( - (-3 as uint, 0u))); - match local_data::get(key, |k| k.map(|&k| *k)) { - Some(interner) => *interner, - None => { - let interner = mk_fresh_ident_interner(); - local_data::set(key, @interner); - interner - } + #[cfg(not(stage0))] + static key: local_data::Key<@@::parse::token::ident_interner> = + &local_data::Key; + #[cfg(stage0)] + fn key(_: @@::parse::token::ident_interner) {} + match local_data::get(key, |k| k.map(|&k| *k)) { + Some(interner) => *interner, + None => { + let interner = mk_fresh_ident_interner(); + local_data::set(key, @interner); + interner } } } diff --git a/src/libsyntax/syntax.rs b/src/libsyntax/syntax.rs index 7cb211a402b49..7a1e9923ab720 100644 --- a/src/libsyntax/syntax.rs +++ b/src/libsyntax/syntax.rs @@ -20,8 +20,6 @@ #[license = "MIT/ASL2"]; #[crate_type = "lib"]; -#[allow(non_camel_case_types)]; -#[allow(non_uppercase_statics)]; #[deny(deprecated_pattern)]; extern mod extra; diff --git a/src/test/compile-fail/core-tls-store-pointer.rs b/src/test/compile-fail/core-tls-store-pointer.rs index 13c9966922889..576b1c452a5ec 100644 --- a/src/test/compile-fail/core-tls-store-pointer.rs +++ b/src/test/compile-fail/core-tls-store-pointer.rs @@ -12,10 +12,7 @@ use std::local_data; -fn key(_x: @&int) { } +static key: local_data::Key<@&int> = &local_data::Key; +//~^ ERROR only 'static is allowed -fn main() { - unsafe { - local_data::set(key, @&0); //~ ERROR does not fulfill `'static` - } -} +fn main() {}