about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-04-28 20:36:08 -0700
committerAlex Crichton <alex@alexcrichton.com>2014-05-07 23:43:39 -0700
commitab92ea526d455b402efbccc7160c8aec0237c88f (patch)
tree92e748f3e3496a48ac68dd290a0a08aa342740a1
parentef6daf9935da103f1b915a5c9904794da79b0b60 (diff)
downloadrust-ab92ea526d455b402efbccc7160c8aec0237c88f.tar.gz
rust-ab92ea526d455b402efbccc7160c8aec0237c88f.zip
std: Modernize the local_data api
This commit brings the local_data api up to modern rust standards with a few key
improvements:

* The `pop` and `set` methods have been combined into one method, `replace`

* The `get_mut` method has been removed. All interior mutability should be done
  through `RefCell`.

* All functionality is now exposed as a method on the keys themselves. Instead
  of importing std::local_data, you now use "key.replace()" and "key.get()".

* All closures have been removed in favor of RAII functionality. This means that
  get() and get_mut() no long require closures, but rather return
  Option<SmartPointer> where the smart pointer takes care of relinquishing the
  borrow and also implements the necessary Deref traits

* The modify() function was removed to cut the local_data interface down to its
  bare essentials (similarly to how RefCell removed set/get).

[breaking-change]
-rw-r--r--src/libcollections/hashmap.rs70
-rw-r--r--src/liblog/lib.rs9
-rw-r--r--src/librand/lib.rs18
-rw-r--r--src/librustc/middle/trans/base.rs35
-rw-r--r--src/librustc/util/common.rs8
-rw-r--r--src/librustdoc/clean.rs15
-rw-r--r--src/librustdoc/core.rs3
-rw-r--r--src/librustdoc/html/format.rs129
-rw-r--r--src/librustdoc/html/markdown.rs23
-rw-r--r--src/librustdoc/html/render.rs154
-rw-r--r--src/librustdoc/lib.rs3
-rw-r--r--src/librustdoc/passes.rs9
-rw-r--r--src/librustdoc/test.rs3
-rw-r--r--src/libstd/local_data.rs537
-rw-r--r--src/libstd/macros.rs6
-rw-r--r--src/libstd/rt/task.rs9
-rw-r--r--src/libstd/slice.rs1
-rw-r--r--src/libsyntax/ext/mtwt.rs39
-rw-r--r--src/libsyntax/parse/token.rs7
-rw-r--r--src/test/auxiliary/macro_crate_outlive_expansion_phase.rs3
-rw-r--r--src/test/compile-fail/core-tls-store-pointer.rs2
-rw-r--r--src/test/compile-fail/macro-local-data-key-priv.rs4
-rw-r--r--src/test/run-pass/macro-local-data-key.rs14
23 files changed, 442 insertions, 659 deletions
diff --git a/src/libcollections/hashmap.rs b/src/libcollections/hashmap.rs
index ce8e1474ee5..2d1de87fe06 100644
--- a/src/libcollections/hashmap.rs
+++ b/src/libcollections/hashmap.rs
@@ -1617,8 +1617,7 @@ mod test_map {
     use std::cmp::Equiv;
     use std::hash::Hash;
     use std::iter::{Iterator,range_inclusive,range_step_inclusive};
-    use std::local_data;
-    use std::vec;
+    use std::cell::RefCell;
 
     struct KindaIntLike(int);
 
@@ -1657,7 +1656,7 @@ mod test_map {
         assert_eq!(*m.find(&2).unwrap(), 4);
     }
 
-    local_data_key!(drop_vector: vec::Vec<int>)
+    local_data_key!(drop_vector: RefCell<Vec<int>>)
 
     #[deriving(Hash, Eq, TotalEq)]
     struct Dropable {
@@ -1667,8 +1666,8 @@ mod test_map {
 
     impl Dropable {
         fn new(k: uint) -> Dropable {
-            local_data::get_mut(drop_vector,
-                |v| { v.unwrap().as_mut_slice()[k] += 1; });
+            let v = drop_vector.get().unwrap();
+            v.borrow_mut().as_mut_slice()[k] += 1;
 
             Dropable { k: k }
         }
@@ -1676,23 +1675,23 @@ mod test_map {
 
     impl Drop for Dropable {
         fn drop(&mut self) {
-            local_data::get_mut(drop_vector, |v|
-                { v.unwrap().as_mut_slice()[self.k] -= 1; });
+            let v = drop_vector.get().unwrap();
+            v.borrow_mut().as_mut_slice()[self.k] -= 1;
         }
     }
 
     #[test]
     fn test_drops() {
-        local_data::set(drop_vector, vec::Vec::from_elem(200, 0));
+        drop_vector.replace(Some(RefCell::new(Vec::from_elem(200, 0))));
 
         {
             let mut m = HashMap::new();
 
-            local_data::get(drop_vector, |v| {
-                for i in range(0u, 200) {
-                    assert_eq!(v.unwrap().as_slice()[i], 0);
-                }
-            });
+            let v = drop_vector.get().unwrap();
+            for i in range(0u, 200) {
+                assert_eq!(v.borrow().as_slice()[i], 0);
+            }
+            drop(v);
 
             for i in range(0u, 100) {
                 let d1 = Dropable::new(i);
@@ -1700,11 +1699,11 @@ mod test_map {
                 m.insert(d1, d2);
             }
 
-            local_data::get(drop_vector, |v| {
-                for i in range(0u, 200) {
-                    assert_eq!(v.unwrap().as_slice()[i], 1);
-                }
-            });
+            let v = drop_vector.get().unwrap();
+            for i in range(0u, 200) {
+                assert_eq!(v.borrow().as_slice()[i], 1);
+            }
+            drop(v);
 
             for i in range(0u, 50) {
                 let k = Dropable::new(i);
@@ -1712,30 +1711,27 @@ mod test_map {
 
                 assert!(v.is_some());
 
-                local_data::get(drop_vector, |v| {
-                    assert_eq!(v.unwrap().as_slice()[i], 1);
-                    assert_eq!(v.unwrap().as_slice()[i+100], 1);
-                });
+                let v = drop_vector.get().unwrap();
+                assert_eq!(v.borrow().as_slice()[i], 1);
+                assert_eq!(v.borrow().as_slice()[i+100], 1);
             }
 
-            local_data::get(drop_vector, |v| {
-                for i in range(0u, 50) {
-                    assert_eq!(v.unwrap().as_slice()[i], 0);
-                    assert_eq!(v.unwrap().as_slice()[i+100], 0);
-                }
+            let v = drop_vector.get().unwrap();
+            for i in range(0u, 50) {
+                assert_eq!(v.borrow().as_slice()[i], 0);
+                assert_eq!(v.borrow().as_slice()[i+100], 0);
+            }
 
-                for i in range(50u, 100) {
-                    assert_eq!(v.unwrap().as_slice()[i], 1);
-                    assert_eq!(v.unwrap().as_slice()[i+100], 1);
-                }
-            });
+            for i in range(50u, 100) {
+                assert_eq!(v.borrow().as_slice()[i], 1);
+                assert_eq!(v.borrow().as_slice()[i+100], 1);
+            }
         }
 
-        local_data::get(drop_vector, |v| {
-            for i in range(0u, 200) {
-                assert_eq!(v.unwrap().as_slice()[i], 0);
-            }
-        });
+        let v = drop_vector.get().unwrap();
+        for i in range(0u, 200) {
+            assert_eq!(v.borrow().as_slice()[i], 0);
+        }
     }
 
     #[test]
diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs
index 035a81f4143..09e9cd83f3d 100644
--- a/src/liblog/lib.rs
+++ b/src/liblog/lib.rs
@@ -122,7 +122,6 @@ use std::cast;
 use std::fmt;
 use std::io::LineBufferedWriter;
 use std::io;
-use std::local_data;
 use std::os;
 use std::rt;
 use std::slice;
@@ -228,7 +227,7 @@ pub fn log(level: u32, loc: &'static LogLocation, args: &fmt::Arguments) {
     // Completely remove the local logger from TLS in case anyone attempts to
     // frob the slot while we're doing the logging. This will destroy any logger
     // set during logging.
-    let mut logger = local_data::pop(local_logger).unwrap_or_else(|| {
+    let mut logger = local_logger.replace(None).unwrap_or_else(|| {
         box DefaultLogger { handle: io::stderr() } as Box<Logger:Send>
     });
     logger.log(&LogRecord {
@@ -238,7 +237,7 @@ pub fn log(level: u32, loc: &'static LogLocation, args: &fmt::Arguments) {
         module_path: loc.module_path,
         line: loc.line,
     });
-    local_data::set(local_logger, logger);
+    local_logger.replace(Some(logger));
 }
 
 /// Getter for the global log level. This is a function so that it can be called
@@ -250,9 +249,7 @@ pub fn log_level() -> u32 { unsafe { LOG_LEVEL } }
 /// Replaces the task-local logger with the specified logger, returning the old
 /// logger.
 pub fn set_logger(logger: Box<Logger:Send>) -> Option<Box<Logger:Send>> {
-    let prev = local_data::pop(local_logger);
-    local_data::set(local_logger, logger);
-    return prev;
+    local_logger.replace(Some(logger))
 }
 
 /// A LogRecord is created by the logging macros, and passed as the only
diff --git a/src/librand/lib.rs b/src/librand/lib.rs
index d5a2c163a90..cb27f2f0ff8 100644
--- a/src/librand/lib.rs
+++ b/src/librand/lib.rs
@@ -79,7 +79,6 @@ println!("{:?}", tuple_ptr)
 use std::cast;
 use std::io::IoResult;
 use std::kinds::marker;
-use std::local_data;
 use std::strbuf::StrBuf;
 
 pub use isaac::{IsaacRng, Isaac64Rng};
@@ -581,9 +580,6 @@ pub struct TaskRng {
     marker: marker::NoSend,
 }
 
-// used to make space in TLS for a random number generator
-local_data_key!(TASK_RNG_KEY: Box<TaskRngInner>)
-
 /// Retrieve the lazily-initialized task-local random number
 /// generator, seeded by the system. Intended to be used in method
 /// chaining style, e.g. `task_rng().gen::<int>()`.
@@ -596,7 +592,10 @@ local_data_key!(TASK_RNG_KEY: Box<TaskRngInner>)
 /// the same sequence always. If absolute consistency is required,
 /// explicitly select an RNG, e.g. `IsaacRng` or `Isaac64Rng`.
 pub fn task_rng() -> TaskRng {
-    local_data::get_mut(TASK_RNG_KEY, |rng| match rng {
+    // used to make space in TLS for a random number generator
+    local_data_key!(TASK_RNG_KEY: Box<TaskRngInner>)
+
+    match TASK_RNG_KEY.get() {
         None => {
             let r = match StdRng::new() {
                 Ok(r) => r,
@@ -607,12 +606,15 @@ pub fn task_rng() -> TaskRng {
                                                         TaskRngReseeder);
             let ptr = &mut *rng as *mut TaskRngInner;
 
-            local_data::set(TASK_RNG_KEY, rng);
+            TASK_RNG_KEY.replace(Some(rng));
 
             TaskRng { rng: ptr, marker: marker::NoSend }
         }
-        Some(rng) => TaskRng { rng: &mut **rng, marker: marker::NoSend }
-    })
+        Some(rng) => TaskRng {
+            rng: &**rng as *_ as *mut TaskRngInner,
+            marker: marker::NoSend
+        }
+    }
 }
 
 impl Rng for TaskRng {
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index c002c47d35d..7b342b7cb95 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -74,7 +74,6 @@ use arena::TypedArena;
 use libc::c_uint;
 use std::c_str::ToCStr;
 use std::cell::{Cell, RefCell};
-use std::local_data;
 use std::rc::Rc;
 use syntax::abi::{X86, X86_64, Arm, Mips, Rust, RustIntrinsic};
 use syntax::ast_util::{local_def, is_local};
@@ -88,19 +87,17 @@ use syntax::{ast, ast_util, ast_map};
 
 use time;
 
-local_data_key!(task_local_insn_key: Vec<&'static str> )
+local_data_key!(task_local_insn_key: RefCell<Vec<&'static str>>)
 
 pub fn with_insn_ctxt(blk: |&[&'static str]|) {
-    local_data::get(task_local_insn_key, |c| {
-        match c {
-            Some(ctx) => blk(ctx.as_slice()),
-            None => ()
-        }
-    })
+    match task_local_insn_key.get() {
+        Some(ctx) => blk(ctx.borrow().as_slice()),
+        None => ()
+    }
 }
 
 pub fn init_insn_ctxt() {
-    local_data::set(task_local_insn_key, Vec::new());
+    task_local_insn_key.replace(Some(RefCell::new(Vec::new())));
 }
 
 pub struct _InsnCtxt { _x: () }
@@ -108,23 +105,19 @@ pub struct _InsnCtxt { _x: () }
 #[unsafe_destructor]
 impl Drop for _InsnCtxt {
     fn drop(&mut self) {
-        local_data::modify(task_local_insn_key, |c| {
-            c.map(|mut ctx| {
-                ctx.pop();
-                ctx
-            })
-        })
+        match task_local_insn_key.get() {
+            Some(ctx) => { ctx.borrow_mut().pop(); }
+            None => {}
+        }
     }
 }
 
 pub fn push_ctxt(s: &'static str) -> _InsnCtxt {
     debug!("new InsnCtxt: {}", s);
-    local_data::modify(task_local_insn_key, |c| {
-        c.map(|mut ctx| {
-            ctx.push(s);
-            ctx
-        })
-    });
+    match task_local_insn_key.get() {
+        Some(ctx) => ctx.borrow_mut().push(s),
+        None => {}
+    }
     _InsnCtxt { _x: () }
 }
 
diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs
index 0d14c036ba7..5ddae0c1bfe 100644
--- a/src/librustc/util/common.rs
+++ b/src/librustc/util/common.rs
@@ -14,23 +14,21 @@ use syntax::ast;
 use syntax::visit;
 use syntax::visit::Visitor;
 
-use std::local_data;
-
 use time;
 
 pub fn time<T, U>(do_it: bool, what: &str, u: U, f: |U| -> T) -> T {
     local_data_key!(depth: uint);
     if !do_it { return f(u); }
 
-    let old = local_data::get(depth, |d| d.map(|a| *a).unwrap_or(0));
-    local_data::set(depth, old + 1);
+    let old = depth.get().map(|d| *d).unwrap_or(0);
+    depth.replace(Some(old + 1));
 
     let start = time::precise_time_s();
     let rv = f(u);
     let end = time::precise_time_s();
 
     println!("{}time: {:3.3f} s\t{}", "  ".repeat(old), end - start, what);
-    local_data::set(depth, old);
+    depth.replace(Some(old));
 
     rv
 }
diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs
index 79fc0fbeada..be0fd85525d 100644
--- a/src/librustdoc/clean.rs
+++ b/src/librustdoc/clean.rs
@@ -26,7 +26,6 @@ use rustc::metadata::cstore;
 use rustc::metadata::csearch;
 use rustc::metadata::decoder;
 
-use std::local_data;
 use std::strbuf::StrBuf;
 
 use core;
@@ -77,7 +76,7 @@ pub struct Crate {
 
 impl<'a> Clean<Crate> for visit_ast::RustdocVisitor<'a> {
     fn clean(&self) -> Crate {
-        let cx = local_data::get(super::ctxtkey, |x| *x.unwrap());
+        let cx = super::ctxtkey.get().unwrap();
 
         let mut externs = Vec::new();
         cx.sess().cstore.iter_crate_data(|n, meta| {
@@ -251,7 +250,7 @@ impl Clean<Item> for doctree::Module {
         // determine if we should display the inner contents or
         // the outer `mod` item for the source code.
         let where = {
-            let ctxt = local_data::get(super::ctxtkey, |x| *x.unwrap());
+            let ctxt = super::ctxtkey.get().unwrap();
             let cm = ctxt.sess().codemap();
             let outer = cm.lookup_char_pos(self.where_outer.lo);
             let inner = cm.lookup_char_pos(self.where_inner.lo);
@@ -726,7 +725,7 @@ impl Clean<Type> for ast::Ty {
     fn clean(&self) -> Type {
         use syntax::ast::*;
         debug!("cleaning type `{:?}`", self);
-        let ctxt = local_data::get(super::ctxtkey, |x| *x.unwrap());
+        let ctxt = super::ctxtkey.get().unwrap();
         let codemap = ctxt.sess().codemap();
         debug!("span corresponds to `{}`", codemap.span_to_str(self.span));
         match self.node {
@@ -909,7 +908,7 @@ pub struct Span {
 
 impl Clean<Span> for syntax::codemap::Span {
     fn clean(&self) -> Span {
-        let ctxt = local_data::get(super::ctxtkey, |x| *x.unwrap());
+        let ctxt = super::ctxtkey.get().unwrap();
         let cm = ctxt.sess().codemap();
         let filename = cm.span_to_filename(*self);
         let lo = cm.lookup_char_pos(self.lo);
@@ -1237,7 +1236,7 @@ trait ToSource {
 impl ToSource for syntax::codemap::Span {
     fn to_src(&self) -> ~str {
         debug!("converting span {:?} to snippet", self.clean());
-        let ctxt = local_data::get(super::ctxtkey, |x| x.unwrap().clone());
+        let ctxt = super::ctxtkey.get().unwrap();
         let cm = ctxt.sess().codemap().clone();
         let sn = match cm.span_to_snippet(*self) {
             Some(x) => x,
@@ -1292,7 +1291,7 @@ fn name_from_pat(p: &ast::Pat) -> ~str {
 /// Given a Type, resolve it using the def_map
 fn resolve_type(path: Path, tpbs: Option<Vec<TyParamBound> >,
                 id: ast::NodeId) -> Type {
-    let cx = local_data::get(super::ctxtkey, |x| *x.unwrap());
+    let cx = super::ctxtkey.get().unwrap();
     let tycx = match cx.maybe_typed {
         core::Typed(ref tycx) => tycx,
         // If we're extracting tests, this return value doesn't matter.
@@ -1351,7 +1350,7 @@ fn resolve_use_source(path: Path, id: ast::NodeId) -> ImportSource {
 }
 
 fn resolve_def(id: ast::NodeId) -> Option<ast::DefId> {
-    let cx = local_data::get(super::ctxtkey, |x| *x.unwrap());
+    let cx = super::ctxtkey.get().unwrap();
     match cx.maybe_typed {
         core::Typed(ref tcx) => {
             tcx.def_map.borrow().find(&id).map(|&d| ast_util::def_id_of_def(d))
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 9f89da563cc..1916e053e98 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -20,7 +20,6 @@ use syntax;
 
 use std::cell::RefCell;
 use std::os;
-use std::local_data;
 use collections::HashSet;
 
 use visit_ast::RustdocVisitor;
@@ -109,7 +108,7 @@ pub fn run_core(libs: HashSet<Path>, cfgs: Vec<~str>, path: &Path)
                 -> (clean::Crate, CrateAnalysis) {
     let (ctxt, analysis) = get_ast_and_resolve(path, libs, cfgs);
     let ctxt = @ctxt;
-    local_data::set(super::ctxtkey, ctxt);
+    super::ctxtkey.replace(Some(ctxt));
 
     let krate = {
         let mut v = RustdocVisitor::new(ctxt, Some(&analysis));
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 1e2f89659cd..223f9341b73 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -17,7 +17,6 @@
 
 use std::fmt;
 use std::io;
-use std::local_data;
 use std::strbuf::StrBuf;
 
 use syntax::ast;
@@ -206,78 +205,72 @@ fn path(w: &mut io::Writer, path: &clean::Path, print_all: bool,
         generics.push_str("&gt;");
     }
 
-    // Did someone say rightward-drift?
-    local_data::get(current_location_key, |loc| {
-        let loc = loc.unwrap();
-
-        local_data::get(cache_key, |cache| {
-            let cache = cache.unwrap();
-            let abs_root = root(&**cache, loc.as_slice());
-            let rel_root = match path.segments.get(0).name.as_slice() {
-                "self" => Some("./".to_owned()),
-                _ => None,
-            };
-
-            if print_all {
-                let amt = path.segments.len() - 1;
-                match rel_root {
-                    Some(root) => {
-                        let mut root = StrBuf::from_str(root);
-                        for seg in path.segments.slice_to(amt).iter() {
-                            if "super" == seg.name || "self" == seg.name {
-                                try!(write!(w, "{}::", seg.name));
-                            } else {
-                                root.push_str(seg.name);
-                                root.push_str("/");
-                                try!(write!(w, "<a class='mod'
-                                                    href='{}index.html'>{}</a>::",
-                                              root.as_slice(),
-                                              seg.name));
-                            }
-                        }
-                    }
-                    None => {
-                        for seg in path.segments.slice_to(amt).iter() {
-                            try!(write!(w, "{}::", seg.name));
-                        }
+    let loc = current_location_key.get().unwrap();
+    let cache = cache_key.get().unwrap();
+    let abs_root = root(&**cache, loc.as_slice());
+    let rel_root = match path.segments.get(0).name.as_slice() {
+        "self" => Some("./".to_owned()),
+        _ => None,
+    };
+
+    if print_all {
+        let amt = path.segments.len() - 1;
+        match rel_root {
+            Some(root) => {
+                let mut root = StrBuf::from_str(root);
+                for seg in path.segments.slice_to(amt).iter() {
+                    if "super" == seg.name || "self" == seg.name {
+                        try!(write!(w, "{}::", seg.name));
+                    } else {
+                        root.push_str(seg.name);
+                        root.push_str("/");
+                        try!(write!(w, "<a class='mod'
+                                            href='{}index.html'>{}</a>::",
+                                      root.as_slice(),
+                                      seg.name));
                     }
                 }
             }
-
-            match info(&**cache) {
-                // This is a documented path, link to it!
-                Some((ref fqp, shortty)) if abs_root.is_some() => {
-                    let mut url = StrBuf::from_str(abs_root.unwrap());
-                    let to_link = fqp.slice_to(fqp.len() - 1);
-                    for component in to_link.iter() {
-                        url.push_str(*component);
-                        url.push_str("/");
-                    }
-                    match shortty {
-                        item_type::Module => {
-                            url.push_str(*fqp.last().unwrap());
-                            url.push_str("/index.html");
-                        }
-                        _ => {
-                            url.push_str(shortty.to_static_str());
-                            url.push_str(".");
-                            url.push_str(*fqp.last().unwrap());
-                            url.push_str(".html");
-                        }
-                    }
-
-                    try!(write!(w, "<a class='{}' href='{}' title='{}'>{}</a>",
-                                  shortty, url, fqp.connect("::"), last.name));
+            None => {
+                for seg in path.segments.slice_to(amt).iter() {
+                    try!(write!(w, "{}::", seg.name));
                 }
+            }
+        }
+    }
 
+    match info(&**cache) {
+        // This is a documented path, link to it!
+        Some((ref fqp, shortty)) if abs_root.is_some() => {
+            let mut url = StrBuf::from_str(abs_root.unwrap());
+            let to_link = fqp.slice_to(fqp.len() - 1);
+            for component in to_link.iter() {
+                url.push_str(*component);
+                url.push_str("/");
+            }
+            match shortty {
+                item_type::Module => {
+                    url.push_str(*fqp.last().unwrap());
+                    url.push_str("/index.html");
+                }
                 _ => {
-                    try!(write!(w, "{}", last.name));
+                    url.push_str(shortty.to_static_str());
+                    url.push_str(".");
+                    url.push_str(*fqp.last().unwrap());
+                    url.push_str(".html");
                 }
             }
-            try!(write!(w, "{}", generics.as_slice()));
-            Ok(())
-        })
-    })
+
+            try!(write!(w, "<a class='{}' href='{}' title='{}'>{}</a>",
+                          shortty, url, fqp.connect("::"), last.name));
+        }
+
+        _ => {
+            try!(write!(w, "{}", last.name));
+        }
+    }
+    try!(write!(w, "{}", generics.as_slice()));
+    Ok(())
 }
 
 /// Helper to render type parameters
@@ -302,10 +295,8 @@ impl fmt::Show for clean::Type {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             clean::TyParamBinder(id) | clean::Generic(id) => {
-                local_data::get(cache_key, |cache| {
-                    let m = cache.unwrap();
-                    f.buf.write(m.typarams.get(&id).as_bytes())
-                })
+                let m = cache_key.get().unwrap();
+                f.buf.write(m.typarams.get(&id).as_bytes())
             }
             clean::ResolvedPath{id, typarams: ref tp, path: ref path} => {
                 try!(resolved_path(f.buf, id, path, false));
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 9d6b0ec5517..0141df34a6c 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -27,11 +27,11 @@
 #![allow(non_camel_case_types)]
 
 use libc;
+use std::cell::RefCell;
 use std::fmt;
 use std::io;
-use std::local_data;
-use std::str;
 use std::slice;
+use std::str;
 use collections::HashMap;
 
 use html::toc::TocBuilder;
@@ -139,7 +139,7 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> {
     }
 }
 
-local_data_key!(used_header_map: HashMap<~str, uint>)
+local_data_key!(used_header_map: RefCell<HashMap<~str, uint>>)
 
 pub fn render(w: &mut io::Writer, s: &str, print_toc: bool) -> fmt::Result {
     extern fn block(ob: *mut hoedown_buffer, text: *hoedown_buffer,
@@ -216,15 +216,12 @@ pub fn render(w: &mut io::Writer, s: &str, print_toc: bool) -> fmt::Result {
         let opaque = unsafe { &mut *((*opaque).opaque as *mut MyOpaque) };
 
         // Make sure our hyphenated ID is unique for this page
-        let id = local_data::get_mut(used_header_map, |map| {
-            let map = map.unwrap();
-            match map.find_mut(&id) {
-                None => {}
-                Some(a) => { *a += 1; return format!("{}-{}", id, *a - 1) }
-            }
-            map.insert(id.clone(), 1);
-            id.clone()
-        });
+        let map = used_header_map.get().unwrap();
+        let id = match map.borrow_mut().find_mut(&id) {
+            None => id,
+            Some(a) => { *a += 1; format!("{}-{}", id, *a - 1) }
+        };
+        map.borrow_mut().insert(id.clone(), 1);
 
         let sec = match opaque.toc_builder {
             Some(ref mut builder) => {
@@ -348,7 +345,7 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) {
 /// used at the beginning of rendering an entire HTML page to reset from the
 /// previous state (if any).
 pub fn reset_headers() {
-    local_data::set(used_header_map, HashMap::new())
+    used_header_map.replace(Some(RefCell::new(HashMap::new())));
 }
 
 impl<'a> fmt::Show for Markdown<'a> {
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index a0d21bbf149..fe80d26d109 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -37,7 +37,6 @@ use collections::{HashMap, HashSet};
 use std::fmt;
 use std::io::{fs, File, BufferedWriter, MemWriter, BufferedReader};
 use std::io;
-use std::local_data;
 use std::str;
 use std::strbuf::StrBuf;
 
@@ -243,24 +242,22 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
     }
 
     // Crawl the crate to build various caches used for the output
-    let mut cache = local_data::get(::analysiskey, |analysis| {
-        let public_items = analysis.map(|a| a.public_items.clone());
-        let public_items = public_items.unwrap_or(NodeSet::new());
-        Cache {
-            impls: HashMap::new(),
-            typarams: HashMap::new(),
-            paths: HashMap::new(),
-            traits: HashMap::new(),
-            implementors: HashMap::new(),
-            stack: Vec::new(),
-            parent_stack: Vec::new(),
-            search_index: Vec::new(),
-            extern_locations: HashMap::new(),
-            privmod: false,
-            public_items: public_items,
-            orphan_methods: Vec::new(),
-        }
-    });
+    let public_items = ::analysiskey.get().map(|a| a.public_items.clone());
+    let public_items = public_items.unwrap_or(NodeSet::new());
+    let mut cache = Cache {
+        impls: HashMap::new(),
+        typarams: HashMap::new(),
+        paths: HashMap::new(),
+        traits: HashMap::new(),
+        implementors: HashMap::new(),
+        stack: Vec::new(),
+        parent_stack: Vec::new(),
+        search_index: Vec::new(),
+        extern_locations: HashMap::new(),
+        privmod: false,
+        public_items: public_items,
+        orphan_methods: Vec::new(),
+    };
     cache.stack.push(krate.name.clone());
     krate = cache.fold_crate(krate);
 
@@ -833,7 +830,7 @@ impl Context {
         item.name = Some(krate.name);
 
         // using a rwarc makes this parallelizable in the future
-        local_data::set(cache_key, Arc::new(cache));
+        cache_key.replace(Some(Arc::new(cache)));
 
         let mut work = vec!((self, item));
         loop {
@@ -859,7 +856,7 @@ impl Context {
             info!("Rendering an item to {}", w.path().display());
             // A little unfortunate that this is done like this, but it sure
             // does make formatting *a lot* nicer.
-            local_data::set(current_location_key, cx.current.clone());
+            current_location_key.replace(Some(cx.current.clone()));
 
             let mut title = StrBuf::from_str(cx.current.connect("::"));
             if pushname {
@@ -1299,31 +1296,28 @@ fn item_trait(w: &mut Writer, it: &clean::Item,
         try!(write!(w, "</div>"));
     }
 
-    local_data::get(cache_key, |cache| {
-        let cache = cache.unwrap();
-        match cache.implementors.find(&it.id) {
-            Some(implementors) => {
-                try!(write!(w, "
-                    <h2 id='implementors'>Implementors</h2>
-                    <ul class='item-list'>
-                "));
-                for i in implementors.iter() {
-                    match *i {
-                        PathType(ref ty) => {
-                            try!(write!(w, "<li><code>{}</code></li>", *ty));
-                        }
-                        OtherType(ref generics, ref trait_, ref for_) => {
-                            try!(write!(w, "<li><code>impl{} {} for {}</code></li>",
-                                          *generics, *trait_, *for_));
-                        }
+    match cache_key.get().unwrap().implementors.find(&it.id) {
+        Some(implementors) => {
+            try!(write!(w, "
+                <h2 id='implementors'>Implementors</h2>
+                <ul class='item-list'>
+            "));
+            for i in implementors.iter() {
+                match *i {
+                    PathType(ref ty) => {
+                        try!(write!(w, "<li><code>{}</code></li>", *ty));
+                    }
+                    OtherType(ref generics, ref trait_, ref for_) => {
+                        try!(write!(w, "<li><code>impl{} {} for {}</code></li>",
+                                      *generics, *trait_, *for_));
                     }
                 }
-                try!(write!(w, "</ul>"));
             }
-            None => {}
+            try!(write!(w, "</ul>"));
         }
-        Ok(())
-    })
+        None => {}
+    }
+    Ok(())
 }
 
 fn render_method(w: &mut Writer, meth: &clean::Item) -> fmt::Result {
@@ -1550,51 +1544,48 @@ fn render_struct(w: &mut Writer, it: &clean::Item,
 }
 
 fn render_methods(w: &mut Writer, it: &clean::Item) -> fmt::Result {
-    local_data::get(cache_key, |cache| {
-        let c = cache.unwrap();
-        match c.impls.find(&it.id) {
-            Some(v) => {
-                let mut non_trait = v.iter().filter(|p| {
-                    p.ref0().trait_.is_none()
-                });
-                let non_trait = non_trait.collect::<Vec<&(clean::Impl, Option<~str>)>>();
-                let mut traits = v.iter().filter(|p| {
-                    p.ref0().trait_.is_some()
-                });
-                let traits = traits.collect::<Vec<&(clean::Impl, Option<~str>)>>();
-
-                if non_trait.len() > 0 {
-                    try!(write!(w, "<h2 id='methods'>Methods</h2>"));
-                    for &(ref i, ref dox) in non_trait.move_iter() {
+    match cache_key.get().unwrap().impls.find(&it.id) {
+        Some(v) => {
+            let mut non_trait = v.iter().filter(|p| {
+                p.ref0().trait_.is_none()
+            });
+            let non_trait = non_trait.collect::<Vec<&(clean::Impl, Option<~str>)>>();
+            let mut traits = v.iter().filter(|p| {
+                p.ref0().trait_.is_some()
+            });
+            let traits = traits.collect::<Vec<&(clean::Impl, Option<~str>)>>();
+
+            if non_trait.len() > 0 {
+                try!(write!(w, "<h2 id='methods'>Methods</h2>"));
+                for &(ref i, ref dox) in non_trait.move_iter() {
+                    try!(render_impl(w, i, dox));
+                }
+            }
+            if traits.len() > 0 {
+                try!(write!(w, "<h2 id='implementations'>Trait \
+                                  Implementations</h2>"));
+                let mut any_derived = false;
+                for & &(ref i, ref dox) in traits.iter() {
+                    if !i.derived {
                         try!(render_impl(w, i, dox));
+                    } else {
+                        any_derived = true;
                     }
                 }
-                if traits.len() > 0 {
-                    try!(write!(w, "<h2 id='implementations'>Trait \
-                                      Implementations</h2>"));
-                    let mut any_derived = false;
-                    for & &(ref i, ref dox) in traits.iter() {
-                        if !i.derived {
+                if any_derived {
+                    try!(write!(w, "<h3 id='derived_implementations'>Derived Implementations \
+                                </h3>"));
+                    for &(ref i, ref dox) in traits.move_iter() {
+                        if i.derived {
                             try!(render_impl(w, i, dox));
-                        } else {
-                            any_derived = true;
-                        }
-                    }
-                    if any_derived {
-                        try!(write!(w, "<h3 id='derived_implementations'>Derived Implementations \
-                                    </h3>"));
-                        for &(ref i, ref dox) in traits.move_iter() {
-                            if i.derived {
-                                try!(render_impl(w, i, dox));
-                            }
                         }
                     }
                 }
             }
-            None => {}
         }
-        Ok(())
-    })
+        None => {}
+    }
+    Ok(())
 }
 
 fn render_impl(w: &mut Writer, i: &clean::Impl,
@@ -1644,9 +1635,8 @@ fn render_impl(w: &mut Writer, i: &clean::Impl,
     match trait_id {
         None => {}
         Some(id) => {
-            try!(local_data::get(cache_key, |cache| {
-                let cache = cache.unwrap();
-                match cache.traits.find(&id) {
+            try!({
+                match cache_key.get().unwrap().traits.find(&id) {
                     Some(t) => {
                         for method in t.methods.iter() {
                             let n = method.item().name.clone();
@@ -1661,7 +1651,7 @@ fn render_impl(w: &mut Writer, i: &clean::Impl,
                     None => {}
                 }
                 Ok(())
-            }))
+            })
         }
     }
     try!(write!(w, "</div>"));
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 24b3e1128ea..a79c8b30bba 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -28,7 +28,6 @@ extern crate time;
 extern crate log;
 extern crate libc;
 
-use std::local_data;
 use std::io;
 use std::io::{File, MemWriter};
 use std::str;
@@ -276,7 +275,7 @@ fn rust_input(cratefile: &str, matches: &getopts::Matches) -> Output {
                        &cr)
     }).unwrap();
     info!("finished with rustc");
-    local_data::set(analysiskey, analysis);
+    analysiskey.replace(Some(analysis));
 
     // Process all of the crate attributes, extracting plugin metadata along
     // with the passes which we are supposed to run.
diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs
index f8a2382c028..38d1b2a14e1 100644
--- a/src/librustdoc/passes.rs
+++ b/src/librustdoc/passes.rs
@@ -11,7 +11,6 @@
 use collections::HashSet;
 use rustc::util::nodemap::NodeSet;
 use std::cmp;
-use std::local_data;
 use std::strbuf::StrBuf;
 use std::uint;
 use syntax::ast;
@@ -86,13 +85,11 @@ pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult {
 
 /// Strip private items from the point of view of a crate or externally from a
 /// crate, specified by the `xcrate` flag.
-pub fn strip_private(krate: clean::Crate) -> plugins::PluginResult {
+pub fn strip_private(mut krate: clean::Crate) -> plugins::PluginResult {
     // This stripper collects all *retained* nodes.
     let mut retained = HashSet::new();
-    let exported_items = local_data::get(super::analysiskey, |analysis| {
-        analysis.unwrap().exported_items.clone()
-    });
-    let mut krate = krate;
+    let analysis = super::analysiskey.get().unwrap();
+    let exported_items = analysis.exported_items.clone();
 
     // strip all private items
     {
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 0b8434d7d17..898f5856694 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -12,7 +12,6 @@ use std::cell::RefCell;
 use std::char;
 use std::io;
 use std::io::{Process, TempDir};
-use std::local_data;
 use std::os;
 use std::str;
 use std::strbuf::StrBuf;
@@ -75,7 +74,7 @@ pub fn run(input: &str,
         maybe_typed: core::NotTyped(sess),
         src: input_path,
     };
-    local_data::set(super::ctxtkey, ctx);
+    super::ctxtkey.replace(Some(ctx));
 
     let mut v = RustdocVisitor::new(ctx, None);
     v.visit(&ctx.krate);
diff --git a/src/libstd/local_data.rs b/src/libstd/local_data.rs
index 9a029de8d6c..c3c04c5470f 100644
--- a/src/libstd/local_data.rs
+++ b/src/libstd/local_data.rs
@@ -23,16 +23,14 @@ named and annotated. This name is then passed to the functions in this module to
 modify/read the slot specified by the key.
 
 ```rust
-use std::local_data;
-
 local_data_key!(key_int: int)
 local_data_key!(key_vector: ~[int])
 
-local_data::set(key_int, 3);
-local_data::get(key_int, |opt| assert_eq!(opt.map(|x| *x), Some(3)));
+key_int.replace(Some(3));
+assert_eq!(*key_int.get().unwrap(), 3);
 
-local_data::set(key_vector, ~[4]);
-local_data::get(key_vector, |opt| assert_eq!(*opt.unwrap(), ~[4]));
+key_vector.replace(Some(~[4]));
+assert_eq!(*key_vector.get().unwrap(), ~[4]);
 ```
 
 */
@@ -43,9 +41,12 @@ local_data::get(key_vector, |opt| assert_eq!(*opt.unwrap(), ~[4]));
 use cast;
 use iter::{Iterator};
 use kinds::Send;
+use kinds::marker;
 use mem::replace;
+use ops::{Drop, Deref};
 use option::{None, Option, Some};
 use owned::Box;
+use raw;
 use rt::task::{Task, LocalStorage};
 use slice::{ImmutableVector, MutableVector};
 use vec::Vec;
@@ -66,7 +67,7 @@ pub type Key<T> = &'static KeyValue<T>;
 #[allow(missing_doc)]
 pub enum KeyValue<T> { Key }
 
-#[allow(missing_doc)]
+#[doc(hidden)]
 trait LocalData {}
 impl<T: 'static> LocalData for T {}
 
@@ -91,7 +92,7 @@ impl<T: 'static> LocalData for T {}
 // n.b. If TLS is used heavily in future, this could be made more efficient with
 //      a proper map.
 #[doc(hidden)]
-pub type Map = Vec<Option<(*u8, TLSValue, LoanState)>>;
+pub type Map = Vec<Option<(*u8, TLSValue, uint)>>;
 type TLSValue = Box<LocalData:Send>;
 
 // Gets the map from the runtime. Lazily initialises if not done so already.
@@ -111,243 +112,156 @@ unsafe fn get_local_map() -> &mut Map {
             *slot = Some(vec!());
             match *slot {
                 Some(ref mut map_ptr) => { return map_ptr }
-                None => abort()
+                None => unreachable!(),
             }
         }
     }
 }
 
-#[deriving(Eq)]
-enum LoanState {
-    NoLoan, ImmLoan, MutLoan
-}
-
-impl LoanState {
-    fn describe(&self) -> &'static str {
-        match *self {
-            NoLoan => "no loan",
-            ImmLoan => "immutable",
-            MutLoan => "mutable"
-        }
-    }
-}
-
 fn key_to_key_value<T: 'static>(key: Key<T>) -> *u8 {
-    unsafe { cast::transmute(key) }
+    key as *KeyValue<T> as *u8
 }
 
-/// Removes a task-local value from task-local storage. This will return
-/// Some(value) if the key was present in TLS, otherwise it will return None.
+/// An RAII immutable reference to a task-local value.
 ///
-/// A runtime assertion will be triggered it removal of TLS value is attempted
-/// while the value is still loaned out via `get` or `get_mut`.
-pub fn pop<T: 'static>(key: Key<T>) -> Option<T> {
-    let map = unsafe { get_local_map() };
-    let key_value = key_to_key_value(key);
-
-    for entry in map.mut_iter() {
-        match *entry {
-            Some((k, _, loan)) if k == key_value => {
-                if loan != NoLoan {
-                    fail!("TLS value cannot be removed because it is currently \
-                          borrowed as {}", loan.describe());
-                }
-                // Move the data out of the `entry` slot via prelude::replace.
-                // This is guaranteed to succeed because we already matched
-                // on `Some` above.
-                let data = match replace(entry, None) {
-                    Some((_, data, _)) => data,
-                    None => abort()
-                };
-
-                // Move `data` into transmute to get out the memory that it
-                // owns, we must free it manually later.
-                let (_vtable, alloc): (uint, Box<T>) = unsafe {
-                    cast::transmute(data)
-                };
-
-                // Now that we own `alloc`, we can just move out of it as we
-                // would with any other data.
-                return Some(*alloc);
-            }
-            _ => {}
-        }
-    }
-    return None;
+/// The task-local data can be accessed through this value, and when this
+/// structure is dropped it will return the borrow on the data.
+pub struct Ref<T> {
+    ptr: &'static T,
+    key: Key<T>,
+    index: uint,
+    nosend: marker::NoSend,
 }
 
-/// Retrieves a value from TLS. The closure provided is yielded `Some` of a
-/// reference to the value located in TLS if one exists, or `None` if the key
-/// provided is not present in TLS currently.
-///
-/// It is considered a runtime error to attempt to get a value which is already
-/// on loan via the `get_mut` method provided.
-pub fn get<T: 'static, U>(key: Key<T>, f: |Option<&T>| -> U) -> U {
-    get_with(key, ImmLoan, f)
-}
-
-/// Retrieves a mutable value from TLS. The closure provided is yielded `Some`
-/// of a reference to the mutable value located in TLS if one exists, or `None`
-/// if the key provided is not present in TLS currently.
-///
-/// It is considered a runtime error to attempt to get a value which is already
-/// on loan via this or the `get` methods.
-pub fn get_mut<T: 'static, U>(key: Key<T>, f: |Option<&mut T>| -> U) -> U {
-    get_with(key, MutLoan, |x| {
-        match x {
-            None => f(None),
-            // We're violating a lot of compiler guarantees with this
-            // invocation of `transmute`, but we're doing runtime checks to
-            // ensure that it's always valid (only one at a time).
-            //
-            // there is no need to be upset!
-            Some(x) => { f(Some(unsafe { cast::transmute::<&_, &mut _>(x) })) }
-        }
-    })
-}
+impl<T: 'static> KeyValue<T> {
+    /// Replaces a value in task local storage.
+    ///
+    /// If this key is already present in TLS, then the previous value is
+    /// replaced with the provided data, and then returned.
+    ///
+    /// # Failure
+    ///
+    /// This function will fail if this key is present in TLS and currently on
+    /// loan with the `get` method.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// local_data_key!(foo: int)
+    ///
+    /// assert_eq!(foo.replace(Some(10)), None);
+    /// assert_eq!(foo.replace(Some(4)), Some(10));
+    /// assert_eq!(foo.replace(None), Some(4));
+    /// ```
+    pub fn replace(&'static self, data: Option<T>) -> Option<T> {
+        let map = unsafe { get_local_map() };
+        let keyval = key_to_key_value(self);
+
+        // When the task-local map is destroyed, all the data needs to be
+        // cleaned up. For this reason we can't do some clever tricks to store
+        // '~T' as a '*c_void' or something like that. To solve the problem, we
+        // cast everything to a trait (LocalData) which is then stored inside
+        // the map.  Upon destruction of the map, all the objects will be
+        // destroyed and the traits have enough information about them to
+        // destroy themselves.
+        //
+        // Additionally, the type of the local data map must ascribe to Send, so
+        // we do the transmute here to add the Send bound back on. This doesn't
+        // actually matter because TLS will always own the data (until its moved
+        // out) and we're not actually sending it to other schedulers or
+        // anything.
+        let newval = data.map(|d| {
+            let d = box d as Box<LocalData>;
+            let d: Box<LocalData:Send> = unsafe { cast::transmute(d) };
+            (keyval, d, 0)
+        });
 
-fn get_with<T:'static,
-            U>(
-            key: Key<T>,
-            state: LoanState,
-            f: |Option<&T>| -> U)
-            -> U {
-    // This function must be extremely careful. Because TLS can store owned
-    // values, and we must have some form of `get` function other than `pop`,
-    // this function has to give a `&` reference back to the caller.
-    //
-    // One option is to return the reference, but this cannot be sound because
-    // the actual lifetime of the object is not known. The slot in TLS could not
-    // be modified until the object goes out of scope, but the TLS code cannot
-    // know when this happens.
-    //
-    // For this reason, the reference is yielded to a specified closure. This
-    // way the TLS code knows exactly what the lifetime of the yielded pointer
-    // is, allowing callers to acquire references to owned data. This is also
-    // sound so long as measures are taken to ensure that while a TLS slot is
-    // loaned out to a caller, it's not modified recursively.
-    let map = unsafe { get_local_map() };
-    let key_value = key_to_key_value(key);
-
-    let pos = map.iter().position(|entry| {
-        match *entry {
-            Some((k, _, _)) if k == key_value => true, _ => false
-        }
-    });
-    match pos {
-        None => { return f(None); }
-        Some(i) => {
-            let ret;
-            let mut return_loan = false;
-            match *map.get_mut(i) {
-                Some((_, ref data, ref mut loan)) => {
-                    match (state, *loan) {
-                        (_, NoLoan) => {
-                            *loan = state;
-                            return_loan = true;
-                        }
-                        (ImmLoan, ImmLoan) => {}
-                        (want, cur) => {
-                            fail!("TLS slot cannot be borrowed as {} because \
-                                    it is already borrowed as {}",
-                                  want.describe(), cur.describe());
-                        }
-                    }
-                    // data was created with `box T as Box<LocalData>`, so we
-                    // extract pointer part of the trait, (as Box<T>), and
-                    // then use compiler coercions to achieve a '&' pointer.
-                    unsafe {
-                        match *cast::transmute::<&TLSValue,
-                                                 &(uint, Box<T>)>(data){
-                            (_vtable, ref alloc) => {
-                                let value: &T = *alloc;
-                                ret = f(Some(value));
-                            }
-                        }
-                    }
-                }
-                _ => abort()
+        let pos = match self.find(map) {
+            Some((i, _, &0)) => Some(i),
+            Some((_, _, _)) => fail!("TLS value cannot be replaced because it \
+                                      is already borrowed"),
+            None => map.iter().position(|entry| entry.is_none()),
+        };
+
+        match pos {
+            Some(i) => {
+                replace(map.get_mut(i), newval).map(|(_, data, _)| {
+                    // Move `data` into transmute to get out the memory that it
+                    // owns, we must free it manually later.
+                    let t: raw::TraitObject = unsafe { cast::transmute(data) };
+                    let alloc: Box<T> = unsafe { cast::transmute(t.data) };
+
+                    // Now that we own `alloc`, we can just move out of it as we
+                    // would with any other data.
+                    *alloc
+                })
             }
-
-            // n.b. 'data' and 'loans' are both invalid pointers at the point
-            // 'f' returned because `f` could have appended more TLS items which
-            // in turn relocated the vector. Hence we do another lookup here to
-            // fixup the loans.
-            if return_loan {
-                match *map.get_mut(i) {
-                    Some((_, _, ref mut loan)) => { *loan = NoLoan; }
-                    None => abort()
-                }
+            None => {
+                map.push(newval);
+                None
             }
-            return ret;
         }
     }
-}
 
-fn abort() -> ! {
-    use intrinsics;
-    unsafe { intrinsics::abort() }
-}
+    /// Borrows a value from TLS.
+    ///
+    /// If `None` is returned, then this key is not present in TLS. If `Some` is
+    /// returned, then the returned data is a smart pointer representing a new
+    /// loan on this TLS key. While on loan, this key cannot be altered via the
+    /// `replace` method.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// local_data_key!(key: int)
+    ///
+    /// assert!(key.get().is_none());
+    ///
+    /// key.replace(Some(3));
+    /// assert_eq!(*key.get().unwrap(), 3);
+    /// ```
+    pub fn get(&'static self) -> Option<Ref<T>> {
+        let map = unsafe { get_local_map() };
+
+        self.find(map).map(|(pos, data, loan)| {
+            *loan += 1;
+
+            // data was created with `~T as ~LocalData`, so we extract
+            // pointer part of the trait, (as ~T), and then use
+            // compiler coercions to achieve a '&' pointer.
+            let ptr = unsafe {
+                let data = data as *Box<LocalData:Send> as *raw::TraitObject;
+                &mut *((*data).data as *mut T)
+            };
+            Ref { ptr: ptr, index: pos, nosend: marker::NoSend, key: self }
+        })
+    }
 
-/// Inserts a value into task local storage. If the key is already present in
-/// TLS, then the previous value is removed and replaced with the provided data.
-///
-/// It is considered a runtime error to attempt to set a key which is currently
-/// on loan via the `get` or `get_mut` methods.
-pub fn set<T: 'static>(key: Key<T>, data: T) {
-    let map = unsafe { get_local_map() };
-    let keyval = key_to_key_value(key);
-
-    // When the task-local map is destroyed, all the data needs to be cleaned
-    // up. For this reason we can't do some clever tricks to store 'Box<T>' as
-    // a '*c_void' or something like that. To solve the problem, we cast
-    // everything to a trait (LocalData) which is then stored inside the map.
-    // Upon destruction of the map, all the objects will be destroyed and the
-    // traits have enough information about them to destroy themselves.
-    let data = box data as Box<LocalData:>;
-
-    fn insertion_position(map: &mut Map,
-                          key: *u8) -> Option<uint> {
-        // First see if the map contains this key already
-        let curspot = map.iter().position(|entry| {
+    fn find<'a>(&'static self,
+                map: &'a mut Map) -> Option<(uint, &'a TLSValue, &'a mut uint)>{
+        let key_value = key_to_key_value(self);
+        map.mut_iter().enumerate().filter_map(|(i, entry)| {
             match *entry {
-                Some((ekey, _, loan)) if key == ekey => {
-                    if loan != NoLoan {
-                        fail!("TLS value cannot be overwritten because it is
-                               already borrowed as {}", loan.describe())
-                    }
-                    true
+                Some((k, ref data, ref mut loan)) if k == key_value => {
+                    Some((i, data, loan))
                 }
-                _ => false,
+                _ => None
             }
-        });
-        // If it doesn't contain the key, just find a slot that's None
-        match curspot {
-            Some(i) => Some(i),
-            None => map.iter().position(|entry| entry.is_none())
-        }
+        }).next()
     }
+}
 
-    // The type of the local data map must ascribe to Send, so we do the
-    // transmute here to add the Send bound back on. This doesn't actually
-    // matter because TLS will always own the data (until its moved out) and
-    // we're not actually sending it to other schedulers or anything.
-    let data: Box<LocalData:Send> = unsafe { cast::transmute(data) };
-    match insertion_position(map, keyval) {
-        Some(i) => { *map.get_mut(i) = Some((keyval, data, NoLoan)); }
-        None => { map.push(Some((keyval, data, NoLoan))); }
-    }
+impl<T: 'static> Deref<T> for Ref<T> {
+    fn deref<'a>(&'a self) -> &'a T { self.ptr }
 }
 
-/// Modifies a task-local value by temporarily removing it from task-local
-/// storage and then re-inserting if `Some` is returned from the closure.
-///
-/// This function will have the same runtime errors as generated from `pop` and
-/// `set` (the key must not currently be on loan
-pub fn modify<T: 'static>(key: Key<T>, f: |Option<T>| -> Option<T>) {
-    match f(pop(key)) {
-        Some(next) => { set(key, next); }
-        None => {}
+#[unsafe_destructor]
+impl<T: 'static> Drop for Ref<T> {
+    fn drop(&mut self) {
+        let map = unsafe { get_local_map() };
+
+        let (_, _, ref mut loan) = *map.get_mut(self.index).get_mut_ref();
+        *loan -= 1;
     }
 }
 
@@ -362,55 +276,36 @@ mod tests {
     #[test]
     fn test_tls_multitask() {
         static my_key: Key<~str> = &Key;
-        set(my_key, "parent data".to_owned());
+        my_key.replace(Some("parent data".to_owned()));
         task::spawn(proc() {
             // TLS shouldn't carry over.
-            assert!(get(my_key, |k| k.map(|k| (*k).clone())).is_none());
-            set(my_key, "child data".to_owned());
-            assert!(get(my_key, |k| k.map(|k| (*k).clone())).unwrap() ==
-                    "child data".to_owned());
+            assert!(my_key.get().is_none());
+            my_key.replace(Some("child data".to_owned()));
+            assert!(my_key.get().get_ref().as_slice() == "child data");
             // should be cleaned up for us
         });
+
         // Must work multiple times
-        assert!(get(my_key, |k| k.map(|k| (*k).clone())).unwrap() == "parent data".to_owned());
-        assert!(get(my_key, |k| k.map(|k| (*k).clone())).unwrap() == "parent data".to_owned());
-        assert!(get(my_key, |k| k.map(|k| (*k).clone())).unwrap() == "parent data".to_owned());
+        assert!(my_key.get().unwrap().as_slice() == "parent data");
+        assert!(my_key.get().unwrap().as_slice() == "parent data");
+        assert!(my_key.get().unwrap().as_slice() == "parent data");
     }
 
     #[test]
     fn test_tls_overwrite() {
         static my_key: Key<~str> = &Key;
-        set(my_key, "first data".to_owned());
-        set(my_key, "next data".to_owned()); // Shouldn't leak.
-        assert!(get(my_key, |k| k.map(|k| (*k).clone())).unwrap() == "next data".to_owned());
+        my_key.replace(Some("first data".to_owned()));
+        my_key.replace(Some("next data".to_owned())); // Shouldn't leak.
+        assert!(my_key.get().unwrap().as_slice() == "next data");
     }
 
     #[test]
     fn test_tls_pop() {
         static my_key: Key<~str> = &Key;
-        set(my_key, "weasel".to_owned());
-        assert!(pop(my_key).unwrap() == "weasel".to_owned());
+        my_key.replace(Some("weasel".to_owned()));
+        assert!(my_key.replace(None).unwrap() == "weasel".to_owned());
         // Pop must remove the data from the map.
-        assert!(pop(my_key).is_none());
-    }
-
-    #[test]
-    fn test_tls_modify() {
-        static my_key: Key<~str> = &Key;
-        modify(my_key, |data| {
-            match data {
-                Some(ref val) => fail!("unwelcome value: {}", *val),
-                None           => Some("first data".to_owned())
-            }
-        });
-        modify(my_key, |data| {
-            match data.as_ref().map(|s| s.as_slice()) {
-                Some("first data") => Some("next data".to_owned()),
-                Some(ref val)       => fail!("wrong value: {}", *val),
-                None                 => fail!("missing value")
-            }
-        });
-        assert!(pop(my_key).unwrap() == "next data".to_owned());
+        assert!(my_key.replace(None).is_none());
     }
 
     #[test]
@@ -423,7 +318,7 @@ mod tests {
         // a stack smaller than 1 MB.
         static my_key: Key<~str> = &Key;
         task::spawn(proc() {
-            set(my_key, "hax".to_owned());
+            my_key.replace(Some("hax".to_owned()));
         });
     }
 
@@ -433,28 +328,27 @@ mod tests {
         static box_key: Key<@()> = &Key;
         static int_key: Key<int> = &Key;
         task::spawn(proc() {
-            set(str_key, "string data".to_owned());
-            set(box_key, @());
-            set(int_key, 42);
+            str_key.replace(Some("string data".to_owned()));
+            box_key.replace(Some(@()));
+            int_key.replace(Some(42));
         });
     }
 
     #[test]
-    #[allow(dead_code)]
     fn test_tls_overwrite_multiple_types() {
         static str_key: Key<~str> = &Key;
         static box_key: Key<@()> = &Key;
         static int_key: Key<int> = &Key;
         task::spawn(proc() {
-            set(str_key, "string data".to_owned());
-            set(str_key, "string data 2".to_owned());
-            set(box_key, @());
-            set(box_key, @());
-            set(int_key, 42);
+            str_key.replace(Some("string data".to_owned()));
+            str_key.replace(Some("string data 2".to_owned()));
+            box_key.replace(Some(@()));
+            box_key.replace(Some(@()));
+            int_key.replace(Some(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);
+            int_key.replace(Some(31337));
         });
     }
 
@@ -464,17 +358,16 @@ mod tests {
         static str_key: Key<~str> = &Key;
         static box_key: Key<@()> = &Key;
         static int_key: Key<int> = &Key;
-        set(str_key, "parent data".to_owned());
-        set(box_key, @());
+        str_key.replace(Some("parent data".to_owned()));
+        box_key.replace(Some(@()));
         task::spawn(proc() {
-            // spawn_linked
-            set(str_key, "string data".to_owned());
-            set(box_key, @());
-            set(int_key, 42);
+            str_key.replace(Some("string data".to_owned()));
+            box_key.replace(Some(@()));
+            int_key.replace(Some(42));
             fail!();
         });
         // Not quite nondeterministic.
-        set(int_key, 31337);
+        int_key.replace(Some(31337));
         fail!();
     }
 
@@ -482,42 +375,24 @@ mod tests {
     fn test_static_pointer() {
         static key: Key<&'static int> = &Key;
         static VALUE: int = 0;
-        let v: &'static int = &VALUE;
-        set(key, v);
+        key.replace(Some(&VALUE));
     }
 
     #[test]
     fn test_owned() {
         static key: Key<Box<int>> = &Key;
-        set(key, box 1);
-
-        get(key, |v| {
-            get(key, |v| {
-                get(key, |v| {
-                    assert_eq!(**v.unwrap(), 1);
-                });
-                assert_eq!(**v.unwrap(), 1);
-            });
-            assert_eq!(**v.unwrap(), 1);
-        });
-        set(key, box 2);
-        get(key, |v| {
-            assert_eq!(**v.unwrap(), 2);
-        })
-    }
-
-    #[test]
-    fn test_get_mut() {
-        static key: Key<int> = &Key;
-        set(key, 1);
-
-        get_mut(key, |v| {
-            *v.unwrap() = 2;
-        });
-
-        get(key, |v| {
-            assert_eq!(*v.unwrap(), 2);
-        })
+        key.replace(Some(box 1));
+
+        {
+            let k1 = key.get().unwrap();
+            let k2 = key.get().unwrap();
+            let k3 = key.get().unwrap();
+            assert_eq!(**k1, 1);
+            assert_eq!(**k2, 1);
+            assert_eq!(**k3, 1);
+        }
+        key.replace(Some(box 2));
+        assert_eq!(**key.get().unwrap(), 2);
     }
 
     #[test]
@@ -527,56 +402,26 @@ mod tests {
         static key3: Key<int> = &Key;
         static key4: Key<int> = &Key;
         static key5: Key<int> = &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));
+        key1.replace(Some(1));
+        key2.replace(Some(2));
+        key3.replace(Some(3));
+        key4.replace(Some(4));
+        key5.replace(Some(5));
+
+        assert_eq!(*key1.get().unwrap(), 1);
+        assert_eq!(*key2.get().unwrap(), 2);
+        assert_eq!(*key3.get().unwrap(), 3);
+        assert_eq!(*key4.get().unwrap(), 4);
+        assert_eq!(*key5.get().unwrap(), 5);
     }
 
     #[test]
     #[should_fail]
     fn test_nested_get_set1() {
         static key: Key<int> = &Key;
-        set(key, 4);
-        get(key, |_| {
-            set(key, 4);
-        })
-    }
-
-    #[test]
-    #[should_fail]
-    fn test_nested_get_mut2() {
-        static key: Key<int> = &Key;
-        set(key, 4);
-        get(key, |_| {
-            get_mut(key, |_| {})
-        })
-    }
-
-    #[test]
-    #[should_fail]
-    fn test_nested_get_mut3() {
-        static key: Key<int> = &Key;
-        set(key, 4);
-        get_mut(key, |_| {
-            get(key, |_| {})
-        })
-    }
+        key.replace(Some(4));
 
-    #[test]
-    #[should_fail]
-    fn test_nested_get_mut4() {
-        static key: Key<int> = &Key;
-        set(key, 4);
-        get_mut(key, |_| {
-            get_mut(key, |_| {})
-        })
+        let _k = key.get();
+        key.replace(Some(4));
     }
 }
diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs
index 4ae3d453f03..1efe56756ed 100644
--- a/src/libstd/macros.rs
+++ b/src/libstd/macros.rs
@@ -289,12 +289,10 @@ macro_rules! println(
 /// # Example
 ///
 /// ```
-/// use std::local_data;
-///
 /// local_data_key!(my_integer: int)
 ///
-/// local_data::set(my_integer, 2);
-/// local_data::get(my_integer, |val| println!("{}", val.map(|i| *i)));
+/// my_integer.replace(Some(2));
+/// println!("{}", my_integer.get().map(|a| *a));
 /// ```
 #[macro_export]
 macro_rules! local_data_key(
diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs
index 5b29de5a8c1..68d8c446cf9 100644
--- a/src/libstd/rt/task.rs
+++ b/src/libstd/rt/task.rs
@@ -414,13 +414,12 @@ mod test {
 
     #[test]
     fn tls() {
-        use local_data;
         local_data_key!(key: @~str)
-        local_data::set(key, @"data".to_owned());
-        assert!(*local_data::get(key, |k| k.map(|k| *k)).unwrap() == "data".to_owned());
+        key.replace(Some(@"data".to_owned()));
+        assert_eq!(key.get().unwrap().as_slice(), "data");
         local_data_key!(key2: @~str)
-        local_data::set(key2, @"data".to_owned());
-        assert!(*local_data::get(key2, |k| k.map(|k| *k)).unwrap() == "data".to_owned());
+        key2.replace(Some(@"data".to_owned()));
+        assert_eq!(key2.get().unwrap().as_slice(), "data");
     }
 
     #[test]
diff --git a/src/libstd/slice.rs b/src/libstd/slice.rs
index 6c8a329446d..35800048d28 100644
--- a/src/libstd/slice.rs
+++ b/src/libstd/slice.rs
@@ -3112,7 +3112,6 @@ mod tests {
     #[test]
     #[should_fail]
     fn test_from_elem_fail() {
-        use cast;
         use cell::Cell;
         use rc::Rc;
 
diff --git a/src/libsyntax/ext/mtwt.rs b/src/libsyntax/ext/mtwt.rs
index 4ae9d436972..6ac3becf0b6 100644
--- a/src/libsyntax/ext/mtwt.rs
+++ b/src/libsyntax/ext/mtwt.rs
@@ -18,7 +18,6 @@
 use ast::{Ident, Mrk, Name, SyntaxContext};
 
 use std::cell::RefCell;
-use std::local_data;
 use std::rc::Rc;
 
 use collections::HashMap;
@@ -91,17 +90,14 @@ fn new_rename_internal(id: Ident,
 pub fn with_sctable<T>(op: |&SCTable| -> T) -> T {
     local_data_key!(sctable_key: Rc<SCTable>)
 
-    local_data::get(sctable_key, |opt_ts| {
-        let table = match opt_ts {
-            None => {
-                let ts = Rc::new(new_sctable_internal());
-                local_data::set(sctable_key, ts.clone());
-                ts
-            }
-            Some(ts) => ts.clone()
-        };
-        op(&*table)
-    })
+    match sctable_key.get() {
+        Some(ts) => op(&**ts),
+        None => {
+            let ts = Rc::new(new_sctable_internal());
+            sctable_key.replace(Some(ts.clone()));
+            op(&*ts)
+        }
+    }
 }
 
 // Make a fresh syntax context table with EmptyCtxt in slot zero
@@ -154,17 +150,14 @@ type ResolveTable = HashMap<(Name,SyntaxContext),Name>;
 fn with_resolve_table_mut<T>(op: |&mut ResolveTable| -> T) -> T {
     local_data_key!(resolve_table_key: Rc<RefCell<ResolveTable>>)
 
-    local_data::get(resolve_table_key, |opt_ts| {
-        let table = match opt_ts {
-            None => {
-                let ts = Rc::new(RefCell::new(HashMap::new()));
-                local_data::set(resolve_table_key, ts.clone());
-                ts
-            }
-            Some(ts) => ts.clone()
-        };
-        op(&mut *table.borrow_mut())
-    })
+    match resolve_table_key.get() {
+        Some(ts) => op(&mut *ts.borrow_mut()),
+        None => {
+            let ts = Rc::new(RefCell::new(HashMap::new()));
+            resolve_table_key.replace(Some(ts.clone()));
+            op(&mut *ts.borrow_mut())
+        }
+    }
 }
 
 // Resolve a syntax object to a name, per MTWT.
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index e4e71baad44..131e744d83d 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -19,7 +19,6 @@ use util::interner;
 use serialize::{Decodable, Decoder, Encodable, Encoder};
 use std::cast;
 use std::fmt;
-use std::local_data;
 use std::path::BytesContainer;
 use std::rc::Rc;
 use std::strbuf::StrBuf;
@@ -529,11 +528,11 @@ pub type IdentInterner = StrInterner;
 // FIXME(eddyb) #8726 This should probably use a task-local reference.
 pub fn get_ident_interner() -> Rc<IdentInterner> {
     local_data_key!(key: Rc<::parse::token::IdentInterner>)
-    match local_data::get(key, |k| k.map(|k| k.clone())) {
-        Some(interner) => interner,
+    match key.get() {
+        Some(interner) => interner.clone(),
         None => {
             let interner = Rc::new(mk_fresh_ident_interner());
-            local_data::set(key, interner.clone());
+            key.replace(Some(interner.clone()));
             interner
         }
     }
diff --git a/src/test/auxiliary/macro_crate_outlive_expansion_phase.rs b/src/test/auxiliary/macro_crate_outlive_expansion_phase.rs
index a2c7e3533d8..670673fe047 100644
--- a/src/test/auxiliary/macro_crate_outlive_expansion_phase.rs
+++ b/src/test/auxiliary/macro_crate_outlive_expansion_phase.rs
@@ -15,7 +15,6 @@
 extern crate syntax;
 
 use std::any::Any;
-use std::local_data;
 use syntax::ast::Name;
 use syntax::ext::base::SyntaxExtension;
 
@@ -30,6 +29,6 @@ impl Drop for Foo {
 #[macro_registrar]
 pub fn registrar(_: |Name, SyntaxExtension|) {
     local_data_key!(foo: Box<Any:Send>);
-    local_data::set(foo, box Foo { foo: 10 } as Box<Any:Send>);
+    foo.replace(Some(box Foo { foo: 10 } as Box<Any:Send>));
 }
 
diff --git a/src/test/compile-fail/core-tls-store-pointer.rs b/src/test/compile-fail/core-tls-store-pointer.rs
index d1541f23c70..2344bd0f090 100644
--- a/src/test/compile-fail/core-tls-store-pointer.rs
+++ b/src/test/compile-fail/core-tls-store-pointer.rs
@@ -10,8 +10,6 @@
 
 // Testing that we can't store a reference it task-local storage
 
-use std::local_data;
-
 local_data_key!(key: @&int)
 //~^ ERROR missing lifetime specifier
 
diff --git a/src/test/compile-fail/macro-local-data-key-priv.rs b/src/test/compile-fail/macro-local-data-key-priv.rs
index e87d57aaa56..ec0e656cc29 100644
--- a/src/test/compile-fail/macro-local-data-key-priv.rs
+++ b/src/test/compile-fail/macro-local-data-key-priv.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::local_data;
-
 // check that the local data keys are private by default.
 
 mod bar {
@@ -17,6 +15,6 @@ mod bar {
 }
 
 fn main() {
-    local_data::set(bar::baz, -10.0);
+    bar::baz.replace(Some(-10.0));
     //~^ ERROR static `baz` is private
 }
diff --git a/src/test/run-pass/macro-local-data-key.rs b/src/test/run-pass/macro-local-data-key.rs
index e03256bfe49..730b0b08d45 100644
--- a/src/test/run-pass/macro-local-data-key.rs
+++ b/src/test/run-pass/macro-local-data-key.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::local_data;
-
 local_data_key!(foo: int)
 
 mod bar {
@@ -17,12 +15,12 @@ mod bar {
 }
 
 pub fn main() {
-    local_data::get(foo, |x| assert!(x.is_none()));
-    local_data::get(bar::baz, |y| assert!(y.is_none()));
+    assert!(foo.get().is_none());
+    assert!(bar::baz.get().is_none());
 
-    local_data::set(foo, 3);
-    local_data::set(bar::baz, -10.0);
+    foo.replace(Some(3));
+    bar::baz.replace(Some(-10.0));
 
-    local_data::get(foo, |x| assert_eq!(*x.unwrap(), 3));
-    local_data::get(bar::baz, |y| assert_eq!(*y.unwrap(), -10.0));
+    assert_eq!(*foo.get().unwrap(), 3);
+    assert_eq!(*bar::baz.get().unwrap(), -10.0);
 }