summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorPaul Stansifer <paul.stansifer@gmail.com>2012-07-18 16:18:02 -0700
committerPaul Stansifer <paul.stansifer@gmail.com>2012-08-22 14:59:25 -0700
commit1153b5dcc86c3567b0a86e441938f05d4f2e295b (patch)
treefdcbcea39abecb4ad1ea5145e62e8c013b05e930 /src/libsyntax
parent7317bf8792ebb3f27768109b7d574ee0806cc5e5 (diff)
downloadrust-1153b5dcc86c3567b0a86e441938f05d4f2e295b.tar.gz
rust-1153b5dcc86c3567b0a86e441938f05d4f2e295b.zip
intern identifiers
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs50
-rw-r--r--src/libsyntax/ast_map.rs37
-rw-r--r--src/libsyntax/ast_util.rs10
-rw-r--r--src/libsyntax/attr.rs112
-rw-r--r--src/libsyntax/ext/auto_serialize.rs73
-rw-r--r--src/libsyntax/ext/base.rs34
-rw-r--r--src/libsyntax/ext/concat_idents.rs8
-rw-r--r--src/libsyntax/ext/expand.rs16
-rw-r--r--src/libsyntax/ext/fmt.rs26
-rw-r--r--src/libsyntax/ext/ident_to_str.rs4
-rw-r--r--src/libsyntax/ext/log_syntax.rs3
-rw-r--r--src/libsyntax/ext/pipes.rs2
-rw-r--r--src/libsyntax/ext/pipes/ast_builder.rs15
-rw-r--r--src/libsyntax/ext/pipes/check.rs10
-rw-r--r--src/libsyntax/ext/pipes/liveness.rs6
-rw-r--r--src/libsyntax/ext/pipes/parse_proto.rs15
-rw-r--r--src/libsyntax/ext/pipes/pipec.rs142
-rw-r--r--src/libsyntax/ext/pipes/proto.rs41
-rw-r--r--src/libsyntax/ext/qquote.rs57
-rw-r--r--src/libsyntax/ext/simplext.rs33
-rw-r--r--src/libsyntax/ext/source_util.rs5
-rw-r--r--src/libsyntax/ext/trace_macros.rs6
-rw-r--r--src/libsyntax/ext/tt/earley_parser.rs13
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs19
-rw-r--r--src/libsyntax/ext/tt/transcribe.rs14
-rw-r--r--src/libsyntax/fold.rs5
-rw-r--r--src/libsyntax/parse/attr.rs12
-rw-r--r--src/libsyntax/parse/comments.rs2
-rw-r--r--src/libsyntax/parse/common.rs10
-rw-r--r--src/libsyntax/parse/eval.rs23
-rw-r--r--src/libsyntax/parse/parser.rs59
-rw-r--r--src/libsyntax/parse/token.rs76
-rw-r--r--src/libsyntax/print/pprust.rs179
-rw-r--r--src/libsyntax/util/interner.rs9
-rw-r--r--src/libsyntax/visit.rs6
35 files changed, 617 insertions, 515 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index c7ff6671e0f..7d9803b4cc3 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -30,8 +30,18 @@ fn deserialize_span<D>(_d: D) -> span {
 #[auto_serialize]
 type spanned<T> = {node: T, span: span};
 
-#[auto_serialize]
-type ident = @~str;
+fn serialize_ident<S: serializer>(s: S, i: ident) {
+    let intr = unsafe{ task::local_data_get(parse::token::interner_key) };
+
+    s.emit_str(*(*intr.get()).get(i));
+}
+fn deserialize_ident<D: deserializer>(d: D) -> ident  {
+    let intr = unsafe{ task::local_data_get(parse::token::interner_key) };
+
+    (*intr.get()).intern(@d.read_str())
+}
+
+type ident = token::str_num;
 
 // Functions may or may not have names.
 #[auto_serialize]
@@ -127,9 +137,9 @@ type meta_item = spanned<meta_item_>;
 
 #[auto_serialize]
 enum meta_item_ {
-    meta_word(ident),
-    meta_list(ident, ~[@meta_item]),
-    meta_name_value(ident, lit),
+    meta_word(~str),
+    meta_list(~str, ~[@meta_item]),
+    meta_name_value(~str, lit),
 }
 
 #[auto_serialize]
@@ -815,36 +825,6 @@ enum inlined_item {
     ii_dtor(class_dtor, ident, ~[ty_param], def_id /* parent id */)
 }
 
-// Convenience functions
-
-pure fn simple_path(id: ident, span: span) -> @path {
-    @{span: span,
-      global: false,
-      idents: ~[id],
-      rp: none,
-      types: ~[]}
-}
-
-pure fn empty_span() -> span {
-    {lo: 0, hi: 0, expn_info: none}
-}
-
-// Convenience implementations
-
-impl ident: ops::add<ident,@path> {
-    pure fn add(&&id: ident) -> @path {
-        simple_path(self, empty_span()) + id
-    }
-}
-
-impl @path: ops::add<ident,@path> {
-    pure fn add(&&id: ident) -> @path {
-        @{
-            idents: vec::append_one(self.idents, id)
-            with *self
-        }
-    }
-}
 
 //
 // Local Variables:
diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs
index 70aaa5e8be6..2cc8cb23f2e 100644
--- a/src/libsyntax/ast_map.rs
+++ b/src/libsyntax/ast_map.rs
@@ -4,31 +4,33 @@ import ast::*;
 import print::pprust;
 import ast_util::{path_to_ident, stmt_id};
 import diagnostic::span_handler;
+import parse::token::ident_interner;
 
 enum path_elt { path_mod(ident), path_name(ident) }
 type path = ~[path_elt];
 
 /* FIXMEs that say "bad" are as per #2543 */
-fn path_to_str_with_sep(p: path, sep: ~str) -> ~str {
+fn path_to_str_with_sep(p: path, sep: ~str, itr: ident_interner) -> ~str {
     let strs = do vec::map(p) |e| {
         match e {
-          path_mod(s) => /* FIXME (#2543) */ copy *s,
-          path_name(s) => /* FIXME (#2543) */ copy *s
+          path_mod(s) => *itr.get(s),
+          path_name(s) => *itr.get(s)
         }
     };
     str::connect(strs, sep)
 }
 
-fn path_ident_to_str(p: path, i: ident) -> ~str {
+fn path_ident_to_str(p: path, i: ident, itr: ident_interner) -> ~str {
     if vec::is_empty(p) {
-        /* FIXME (#2543) */ copy *i
+        //FIXME /* FIXME (#2543) */ copy *i
+        *itr.get(i)
     } else {
-        fmt!{"%s::%s", path_to_str(p), *i}
+        fmt!{"%s::%s", path_to_str(p, itr), *itr.get(i)}
     }
 }
 
-fn path_to_str(p: path) -> ~str {
-    path_to_str_with_sep(p, ~"::")
+fn path_to_str(p: path, itr: ident_interner) -> ~str {
+    path_to_str_with_sep(p, ~"::", itr)
 }
 
 enum ast_node {
@@ -291,43 +293,42 @@ fn map_stmt(stmt: @stmt, cx: ctx, v: vt) {
     visit::visit_stmt(stmt, cx, v);
 }
 
-fn node_id_to_str(map: map, id: node_id) -> ~str {
+fn node_id_to_str(map: map, id: node_id, itr: ident_interner) -> ~str {
     match map.find(id) {
       none => {
         fmt!{"unknown node (id=%d)", id}
       }
       some(node_item(item, path)) => {
-        fmt!{"item %s (id=%?)", path_ident_to_str(*path, item.ident), id}
+        fmt!{"item %s (id=%?)", path_ident_to_str(*path, item.ident, itr), id}
       }
       some(node_foreign_item(item, abi, path)) => {
         fmt!{"foreign item %s with abi %? (id=%?)",
-             path_ident_to_str(*path, item.ident), abi, id}
+             path_ident_to_str(*path, item.ident, itr), abi, id}
       }
       some(node_method(m, impl_did, path)) => {
         fmt!{"method %s in %s (id=%?)",
-             *m.ident, path_to_str(*path), id}
+             *itr.get(m.ident), path_to_str(*path, itr), id}
       }
       some(node_trait_method(tm, impl_did, path)) => {
         let m = ast_util::trait_method_to_ty_method(*tm);
         fmt!{"method %s in %s (id=%?)",
-             *m.ident, path_to_str(*path), id}
+             *itr.get(m.ident), path_to_str(*path, itr), id}
       }
       some(node_variant(variant, def_id, path)) => {
         fmt!{"variant %s in %s (id=%?)",
-             *variant.node.name, path_to_str(*path), id}
+             *itr.get(variant.node.name), path_to_str(*path, itr), id}
       }
       some(node_expr(expr)) => {
-        fmt!{"expr %s (id=%?)",
-             pprust::expr_to_str(expr), id}
+        fmt!{"expr %s (id=%?)", pprust::expr_to_str(expr, itr), id}
       }
       some(node_stmt(stmt)) => {
         fmt!{"stmt %s (id=%?)",
-             pprust::stmt_to_str(*stmt), id}
+             pprust::stmt_to_str(*stmt, itr), id}
       }
       // FIXMEs are as per #2410
       some(node_export(_, path)) => {
         fmt!{"export %s (id=%?)", // add more info here
-             path_to_str(*path), id}
+             path_to_str(*path, itr), id}
       }
       some(node_arg(_, _)) => { // add more info here
         fmt!{"arg (id=%?)", id}
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index d949c546155..fe1924d1dbe 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -21,13 +21,14 @@ pure fn mk_sp(lo: uint, hi: uint) -> span {
 // make this a const, once the compiler supports it
 pure fn dummy_sp() -> span { return mk_sp(0u, 0u); }
 
-pure fn path_name(p: @path) -> ~str { path_name_i(p.idents) }
 
-pure fn path_name_i(idents: ~[ident]) -> ~str {
+
+pure fn path_name_i(idents: ~[ident], intr: token::ident_interner) -> ~str {
     // FIXME: Bad copies (#2543 -- same for everything else that says "bad")
-    str::connect(idents.map(|i|*i), ~"::")
+    str::connect(idents.map(|i| *intr.get(i)), ~"::")
 }
 
+
 pure fn path_to_ident(p: @path) -> ident { vec::last(p.idents) }
 
 pure fn local_def(id: node_id) -> def_id { {crate: local_crate, node: id} }
@@ -408,7 +409,8 @@ fn dtor_dec() -> fn_decl {
     let nil_t = @{id: 0, node: ty_nil, span: dummy_sp()};
     // dtor has one argument, of type ()
     {inputs: ~[{mode: ast::expl(ast::by_ref),
-                ty: nil_t, ident: @~"_", id: 0}],
+                ty: nil_t, ident: parse::token::special_idents::underscore,
+                id: 0}],
      output: nil_t, purity: impure_fn, cf: return_val}
 }
 
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 7c04d6e4570..71fc7f94e36 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -49,23 +49,23 @@ export require_unique_names;
 
 /* Constructors */
 
-fn mk_name_value_item_str(+name: ast::ident, +value: ~str) ->
+fn mk_name_value_item_str(name: ~str, +value: ~str) ->
     @ast::meta_item {
     let value_lit = dummy_spanned(ast::lit_str(@value));
     return mk_name_value_item(name, value_lit);
 }
 
-fn mk_name_value_item(+name: ast::ident, +value: ast::lit)
+fn mk_name_value_item(name: ~str, +value: ast::lit)
         -> @ast::meta_item {
     return @dummy_spanned(ast::meta_name_value(name, value));
 }
 
-fn mk_list_item(+name: ast::ident, +items: ~[@ast::meta_item]) ->
+fn mk_list_item(name: ~str, +items: ~[@ast::meta_item]) ->
    @ast::meta_item {
     return @dummy_spanned(ast::meta_list(name, items));
 }
 
-fn mk_word_item(+name: ast::ident) -> @ast::meta_item {
+fn mk_word_item(name: ~str) -> @ast::meta_item {
     return @dummy_spanned(ast::meta_word(name));
 }
 
@@ -78,7 +78,7 @@ fn mk_sugared_doc_attr(text: ~str, lo: uint, hi: uint) -> ast::attribute {
     let lit = spanned(lo, hi, ast::lit_str(@text));
     let attr = {
         style: doc_comment_style(text),
-        value: spanned(lo, hi, ast::meta_name_value(@~"doc", lit)),
+        value: spanned(lo, hi, ast::meta_name_value(~"doc", lit)),
         is_sugared_doc: true
     };
     return spanned(lo, hi, attr);
@@ -98,8 +98,8 @@ fn attr_metas(attrs: ~[ast::attribute]) -> ~[@ast::meta_item] {
 fn desugar_doc_attr(attr: ast::attribute) -> ast::attribute {
     if attr.node.is_sugared_doc {
         let comment = get_meta_item_value_str(@attr.node.value).get();
-        let meta = mk_name_value_item_str(@~"doc",
-                                     strip_doc_comment_decoration(*comment));
+        let meta = mk_name_value_item_str(~"doc",
+                                     strip_doc_comment_decoration(comment));
         return mk_attr(meta);
     } else {
         attr
@@ -108,16 +108,15 @@ fn desugar_doc_attr(attr: ast::attribute) -> ast::attribute {
 
 /* Accessors */
 
-fn get_attr_name(attr: ast::attribute) -> ast::ident {
+fn get_attr_name(attr: ast::attribute) -> ~str {
     get_meta_item_name(@attr.node.value)
 }
 
-// All "bad" FIXME copies are as per #2543
-fn get_meta_item_name(meta: @ast::meta_item) -> ast::ident {
+fn get_meta_item_name(meta: @ast::meta_item) -> ~str {
     match meta.node {
-      ast::meta_word(n) => /* FIXME (#2543) */ copy n,
-      ast::meta_name_value(n, _) => /* FIXME (#2543) */ copy n,
-      ast::meta_list(n, _) => /* FIXME (#2543) */ copy n
+      ast::meta_word(n) => n,
+      ast::meta_name_value(n, _) => n,
+      ast::meta_list(n, _) => n
     }
 }
 
@@ -125,13 +124,13 @@ fn get_meta_item_name(meta: @ast::meta_item) -> ast::ident {
  * Gets the string value if the meta_item is a meta_name_value variant
  * containing a string, otherwise none
  */
-fn get_meta_item_value_str(meta: @ast::meta_item) -> option<@~str> {
+fn get_meta_item_value_str(meta: @ast::meta_item) -> option<~str> {
     match meta.node {
-      ast::meta_name_value(_, v) => match v.node {
-        ast::lit_str(s) => option::some(s),
+        ast::meta_name_value(_, v) => match v.node {
+            ast::lit_str(s) => option::some(*s),
+            _ => option::none
+        },
         _ => option::none
-      },
-      _ => option::none
     }
 }
 
@@ -147,9 +146,7 @@ fn get_meta_item_list(meta: @ast::meta_item) -> option<~[@ast::meta_item]> {
  * If the meta item is a nam-value type with a string value then returns
  * a tuple containing the name and string value, otherwise `none`
  */
-fn get_name_value_str_pair(
-    item: @ast::meta_item
-) -> option<(ast::ident, @~str)> {
+fn get_name_value_str_pair(item: @ast::meta_item) -> option<(~str, ~str)> {
     match attr::get_meta_item_value_str(item) {
       some(value) => {
         let name = attr::get_meta_item_name(item);
@@ -163,11 +160,11 @@ fn get_name_value_str_pair(
 /* Searching */
 
 /// Search a list of attributes and return only those with a specific name
-fn find_attrs_by_name(attrs: ~[ast::attribute], +name: ~str) ->
+fn find_attrs_by_name(attrs: ~[ast::attribute], name: ~str) ->
    ~[ast::attribute] {
     let filter = (
         fn@(a: ast::attribute) -> option<ast::attribute> {
-            if *get_attr_name(a) == name {
+            if get_attr_name(a) == name {
                 option::some(a)
             } else { option::none }
         }
@@ -176,10 +173,10 @@ fn find_attrs_by_name(attrs: ~[ast::attribute], +name: ~str) ->
 }
 
 /// Searcha list of meta items and return only those with a specific name
-fn find_meta_items_by_name(metas: ~[@ast::meta_item], +name: ~str) ->
+fn find_meta_items_by_name(metas: ~[@ast::meta_item], name: ~str) ->
    ~[@ast::meta_item] {
     let filter = fn@(&&m: @ast::meta_item) -> option<@ast::meta_item> {
-        if *get_meta_item_name(m) == name {
+        if get_meta_item_name(m) == name {
             option::some(m)
         } else { option::none }
     };
@@ -191,14 +188,9 @@ fn find_meta_items_by_name(metas: ~[@ast::meta_item], +name: ~str) ->
  * comparison is performed structurally.
  */
 fn contains(haystack: ~[@ast::meta_item], needle: @ast::meta_item) -> bool {
-    debug!{"looking for %s",
-           print::pprust::meta_item_to_str(*needle)};
     for haystack.each |item| {
-        debug!{"looking in %s",
-               print::pprust::meta_item_to_str(*item)};
-        if eq(item, needle) { debug!{"found it!"}; return true; }
+        if eq(item, needle) { return true; }
     }
-    #debug("found it not :(");
     return false;
 }
 
@@ -223,17 +215,18 @@ fn eq(a: @ast::meta_item, b: @ast::meta_item) -> bool {
         }
 }
 
-fn contains_name(metas: ~[@ast::meta_item], +name: ~str) -> bool {
+fn contains_name(metas: ~[@ast::meta_item], name: ~str) -> bool {
     let matches = find_meta_items_by_name(metas, name);
     return vec::len(matches) > 0u;
 }
 
-fn attrs_contains_name(attrs: ~[ast::attribute], +name: ~str) -> bool {
+fn attrs_contains_name(attrs: ~[ast::attribute], name: ~str) -> bool {
     vec::is_not_empty(find_attrs_by_name(attrs, name))
 }
 
-fn first_attr_value_str_by_name(attrs: ~[ast::attribute], +name: ~str)
-    -> option<@~str> {
+fn first_attr_value_str_by_name(attrs: ~[ast::attribute], name: ~str)
+    -> option<~str> {
+
     let mattrs = find_attrs_by_name(attrs, name);
     if vec::len(mattrs) > 0u {
         return get_meta_item_value_str(attr_meta(mattrs[0]));
@@ -241,18 +234,16 @@ fn first_attr_value_str_by_name(attrs: ~[ast::attribute], +name: ~str)
     return option::none;
 }
 
-fn last_meta_item_by_name(
-    items: ~[@ast::meta_item],
-    +name: ~str
-) -> option<@ast::meta_item> {
+fn last_meta_item_by_name(items: ~[@ast::meta_item], name: ~str)
+    -> option<@ast::meta_item> {
+
     let items = attr::find_meta_items_by_name(items, name);
     vec::last_opt(items)
 }
 
-fn last_meta_item_value_str_by_name(
-    items: ~[@ast::meta_item],
-    +name: ~str
-) -> option<@~str> {
+fn last_meta_item_value_str_by_name(items: ~[@ast::meta_item], name: ~str)
+    -> option<~str> {
+
     match last_meta_item_by_name(items, name) {
       some(item) => match attr::get_meta_item_value_str(item) {
         some(value) => some(value),
@@ -262,10 +253,9 @@ fn last_meta_item_value_str_by_name(
     }
 }
 
-fn last_meta_item_list_by_name(
-    items: ~[@ast::meta_item],
-    +name: ~str
-) -> option<~[@ast::meta_item]> {
+fn last_meta_item_list_by_name(items: ~[@ast::meta_item], name: ~str)
+    -> option<~[@ast::meta_item]> {
+
     match last_meta_item_by_name(items, name) {
       some(item) => attr::get_meta_item_list(item),
       none => none
@@ -279,11 +269,11 @@ fn last_meta_item_list_by_name(
 // the item name (See [Fixme-sorting])
 fn sort_meta_items(+items: ~[@ast::meta_item]) -> ~[@ast::meta_item] {
     pure fn lteq(ma: &@ast::meta_item, mb: &@ast::meta_item) -> bool {
-        pure fn key(m: &ast::meta_item) -> ast::ident {
+        pure fn key(m: &ast::meta_item) -> ~str {
             match m.node {
-              ast::meta_word(name) => /* FIXME (#2543) */ copy name,
-              ast::meta_name_value(name, _) => /* FIXME (#2543) */ copy name,
-              ast::meta_list(name, _) => /* FIXME (#2543) */ copy name
+              ast::meta_word(name) => name,
+              ast::meta_name_value(name, _) => name,
+              ast::meta_list(name, _) => name
             }
         }
         key(*ma) <= key(*mb)
@@ -295,7 +285,7 @@ fn sort_meta_items(+items: ~[@ast::meta_item]) -> ~[@ast::meta_item] {
     return vec::from_mut(v);
 }
 
-fn remove_meta_items_by_name(items: ~[@ast::meta_item], name: ast::ident) ->
+fn remove_meta_items_by_name(items: ~[@ast::meta_item], name: ~str) ->
    ~[@ast::meta_item] {
 
     return vec::filter_map(items, |item| {
@@ -335,17 +325,17 @@ fn foreign_abi(attrs: ~[ast::attribute]) -> Either<~str, ast::foreign_abi> {
       option::none => {
         either::Right(ast::foreign_abi_cdecl)
       }
-      option::some(@~"rust-intrinsic") => {
+      option::some(~"rust-intrinsic") => {
         either::Right(ast::foreign_abi_rust_intrinsic)
       }
-      option::some(@~"cdecl") => {
+      option::some(~"cdecl") => {
         either::Right(ast::foreign_abi_cdecl)
       }
-      option::some(@~"stdcall") => {
+      option::some(~"stdcall") => {
         either::Right(ast::foreign_abi_stdcall)
       }
       option::some(t) => {
-        either::Left(~"unsupported abi: " + *t)
+        either::Left(~"unsupported abi: " + t)
       }
     };
 }
@@ -362,8 +352,8 @@ fn find_inline_attr(attrs: ~[ast::attribute]) -> inline_attr {
     // FIXME (#2809)---validate the usage of #[inline] and #[inline(always)]
     do vec::foldl(ia_none, attrs) |ia,attr| {
         match attr.node.value.node {
-          ast::meta_word(@~"inline") => ia_hint,
-          ast::meta_list(@~"inline", items) => {
+          ast::meta_word(~"inline") => ia_hint,
+          ast::meta_list(~"inline", items) => {
             if !vec::is_empty(find_meta_items_by_name(items, ~"always")) {
                 ia_always
             } else if !vec::is_empty(
@@ -386,11 +376,11 @@ fn require_unique_names(diagnostic: span_handler,
         let name = get_meta_item_name(meta);
 
         // FIXME: How do I silence the warnings? --pcw (#2619)
-        if map.contains_key(*name) {
+        if map.contains_key(name) {
             diagnostic.span_fatal(meta.span,
-                                  fmt!{"duplicate meta item `%s`", *name});
+                                  fmt!{"duplicate meta item `%s`", name});
         }
-        map.insert(*name, ());
+        map.insert(name, ());
     }
 }
 
diff --git a/src/libsyntax/ext/auto_serialize.rs b/src/libsyntax/ext/auto_serialize.rs
index 1fc77bae8bf..e5b65b41fc8 100644
--- a/src/libsyntax/ext/auto_serialize.rs
+++ b/src/libsyntax/ext/auto_serialize.rs
@@ -84,15 +84,15 @@ mod syntax {
     export parse;
 }
 
-type ser_tps_map = map::hashmap<~str, fn@(@ast::expr) -> ~[@ast::stmt]>;
-type deser_tps_map = map::hashmap<~str, fn@() -> @ast::expr>;
+type ser_tps_map = map::hashmap<ast::ident, fn@(@ast::expr) -> ~[@ast::stmt]>;
+type deser_tps_map = map::hashmap<ast::ident, fn@() -> @ast::expr>;
 
 fn expand(cx: ext_ctxt,
           span: span,
           _mitem: ast::meta_item,
           in_items: ~[@ast::item]) -> ~[@ast::item] {
     fn not_auto_serialize(a: ast::attribute) -> bool {
-        attr::get_attr_name(a) != @~"auto_serialize"
+        attr::get_attr_name(a) != ~"auto_serialize"
     }
 
     fn filter_attrs(item: @ast::item) -> @ast::item {
@@ -156,7 +156,11 @@ impl ext_ctxt: ext_ctxt_helpers {
         let head = vec::init(base_path.idents);
         let tail = vec::last(base_path.idents);
         self.path(base_path.span,
-                  vec::append(head, ~[@(helper_name + ~"_" + *tail)]))
+                  vec::append(head,
+                              ~[self.parse_sess().interner.
+                                intern(@(helper_name + ~"_" +
+                                         *self.parse_sess().interner.get(
+                                             tail)))]))
     }
 
     fn path(span: span, strs: ~[ast::ident]) -> @ast::path {
@@ -181,7 +185,7 @@ impl ext_ctxt: ext_ctxt_helpers {
         let args = do vec::map(input_tys) |ty| {
             {mode: ast::expl(ast::by_ref),
              ty: ty,
-             ident: @~"",
+             ident: parse::token::special_idents::invalid,
              id: self.next_id()}
         };
 
@@ -352,7 +356,7 @@ fn ser_variant(cx: ext_ctxt,
                argfn: fn(-@ast::expr, uint, ast::blk) -> @ast::expr)
     -> ast::arm {
     let vnames = do vec::from_fn(vec::len(tys)) |i| {
-        @fmt!{"__v%u", i}
+        cx.parse_sess().interner.intern(@fmt!{"__v%u", i})
     };
     let pats = do vec::from_fn(vec::len(tys)) |i| {
         cx.binder_pat(tys[i].span, vnames[i])
@@ -384,7 +388,7 @@ fn is_vec_or_str(ty: @ast::ty) -> bool {
       // This may be wrong if the user has shadowed (!) str
       ast::ty_path(@{span: _, global: _, idents: ids,
                              rp: none, types: _}, _)
-      if ids == ~[@~"str"] => true,
+      if ids == ~[parse::token::special_idents::str] => true,
       _ => false
     }
 }
@@ -434,7 +438,8 @@ fn ser_ty(cx: ext_ctxt, tps: ser_tps_map,
                                              fld.node.ident,
                                              ~[]));
             let s = cx.clone(s);
-            let f = cx.lit_str(fld.span, fld.node.ident);
+            let f = cx.lit_str(fld.span, cx.parse_sess().interner.get(
+                fld.node.ident));
             let i = cx.lit_uint(fld.span, fidx);
             let l = ser_lambda(cx, tps, fld.node.mt.ty, cx.clone(s), vf);
             #ast[stmt]{$(s).emit_rec_field($(f), $(i), $(l));}
@@ -487,7 +492,7 @@ fn ser_ty(cx: ext_ctxt, tps: ser_tps_map,
             vec::is_empty(path.types) {
             let ident = path.idents[0];
 
-            match tps.find(*ident) {
+            match tps.find(ident) {
               some(f) => f(v),
               none => ser_path(cx, tps, path, s, v)
             }
@@ -545,7 +550,7 @@ fn mk_ser_fn(cx: ext_ctxt, span: span, name: ast::ident,
              ty: cx.ty_fn(span,
                           ~[cx.ty_path(span, ~[tp.ident], ~[])],
                           cx.ty_nil(span)),
-             ident: @(~"__s" + *tp.ident),
+             ident: cx.ident_of(~"__s" + cx.str_of(tp.ident)),
              id: cx.next_id()});
 
     debug!{"tp_inputs = %?", tp_inputs};
@@ -553,35 +558,36 @@ fn mk_ser_fn(cx: ext_ctxt, span: span, name: ast::ident,
 
     let ser_inputs: ~[ast::arg] =
         vec::append(~[{mode: ast::expl(ast::by_ref),
-                      ty: cx.ty_path(span, ~[@~"__S"], ~[]),
-                      ident: @~"__s",
+                      ty: cx.ty_path(span, ~[cx.ident_of(~"__S")], ~[]),
+                      ident: cx.ident_of(~"__s"),
                       id: cx.next_id()},
                      {mode: ast::expl(ast::by_ref),
                       ty: v_ty,
-                      ident: @~"__v",
+                      ident: cx.ident_of(~"__v"),
                       id: cx.next_id()}],
                     tp_inputs);
 
-    let tps_map = map::str_hash();
+    let tps_map = map::uint_hash();
     do vec::iter2(tps, tp_inputs) |tp, arg| {
         let arg_ident = arg.ident;
         tps_map.insert(
-            *tp.ident,
+            tp.ident,
             fn@(v: @ast::expr) -> ~[@ast::stmt] {
                 let f = cx.var_ref(span, arg_ident);
-                debug!{"serializing type arg %s", *arg_ident};
+                debug!{"serializing type arg %s", cx.str_of(arg_ident)};
                 ~[#ast[stmt]{$(f)($(v));}]
             });
     }
 
     let ser_bnds = @~[
         ast::bound_trait(cx.ty_path(span,
-                                    ~[@~"std", @~"serialization",
-                                     @~"serializer"],
+                                    ~[cx.ident_of(~"std"),
+                                      cx.ident_of(~"serialization"),
+                                      cx.ident_of(~"serializer")],
                                     ~[]))];
 
     let ser_tps: ~[ast::ty_param] =
-        vec::append(~[{ident: @~"__S",
+        vec::append(~[{ident: cx.ident_of(~"__S"),
                       id: cx.next_id(),
                       bounds: ser_bnds}],
                     vec::map(tps, |tp| cx.clone_ty_param(tp)));
@@ -593,7 +599,7 @@ fn mk_ser_fn(cx: ext_ctxt, span: span, name: ast::ident,
     let ser_blk = cx.blk(span,
                          f(cx, tps_map, #ast{ __s }, #ast{ __v }));
 
-    @{ident: @(~"serialize_" + *name),
+    @{ident: cx.ident_of(~"serialize_" + cx.str_of(name)),
       attrs: ~[],
       id: cx.next_id(),
       node: ast::item_fn({inputs: ser_inputs,
@@ -670,7 +676,7 @@ fn deser_ty(cx: ext_ctxt, tps: deser_tps_map,
         let fields = do vec::from_fn(vec::len(flds)) |fidx| {
             let fld = flds[fidx];
             let d = cx.clone(d);
-            let f = cx.lit_str(fld.span, fld.node.ident);
+            let f = cx.lit_str(fld.span, @cx.str_of(fld.node.ident));
             let i = cx.lit_uint(fld.span, fidx);
             let l = deser_lambda(cx, tps, fld.node.mt.ty, cx.clone(d));
             {node: {mutbl: fld.node.mt.mutbl,
@@ -713,7 +719,7 @@ fn deser_ty(cx: ext_ctxt, tps: deser_tps_map,
             vec::is_empty(path.types) {
             let ident = path.idents[0];
 
-            match tps.find(*ident) {
+            match tps.find(ident) {
               some(f) => f(),
               none => deser_path(cx, tps, path, d)
             }
@@ -756,23 +762,23 @@ fn mk_deser_fn(cx: ext_ctxt, span: span,
              ty: cx.ty_fn(span,
                           ~[],
                           cx.ty_path(span, ~[tp.ident], ~[])),
-             ident: @(~"__d" + *tp.ident),
+             ident: cx.ident_of(~"__d" + cx.str_of(tp.ident)),
              id: cx.next_id()});
 
     debug!{"tp_inputs = %?", tp_inputs};
 
     let deser_inputs: ~[ast::arg] =
         vec::append(~[{mode: ast::expl(ast::by_ref),
-                      ty: cx.ty_path(span, ~[@~"__D"], ~[]),
-                      ident: @~"__d",
+                      ty: cx.ty_path(span, ~[cx.ident_of(~"__D")], ~[]),
+                      ident: cx.ident_of(~"__d"),
                       id: cx.next_id()}],
                     tp_inputs);
 
-    let tps_map = map::str_hash();
+    let tps_map = map::uint_hash();
     do vec::iter2(tps, tp_inputs) |tp, arg| {
         let arg_ident = arg.ident;
         tps_map.insert(
-            *tp.ident,
+            tp.ident,
             fn@() -> @ast::expr {
                 let f = cx.var_ref(span, arg_ident);
                 #ast{ $(f)() }
@@ -782,11 +788,12 @@ fn mk_deser_fn(cx: ext_ctxt, span: span,
     let deser_bnds = @~[
         ast::bound_trait(cx.ty_path(
             span,
-            ~[@~"std", @~"serialization", @~"deserializer"],
+            ~[cx.ident_of(~"std"), cx.ident_of(~"serialization"),
+              cx.ident_of(~"deserializer")],
             ~[]))];
 
     let deser_tps: ~[ast::ty_param] =
-        vec::append(~[{ident: @~"__D",
+        vec::append(~[{ident: cx.ident_of(~"__D"),
                       id: cx.next_id(),
                       bounds: deser_bnds}],
                     vec::map(tps, |tp| {
@@ -798,7 +805,7 @@ fn mk_deser_fn(cx: ext_ctxt, span: span,
 
     let deser_blk = cx.expr_blk(f(cx, tps_map, #ast[expr]{__d}));
 
-    @{ident: @(~"deserialize_" + *name),
+    @{ident: cx.ident_of(~"deserialize_" + cx.str_of(name)),
       attrs: ~[],
       id: cx.next_id(),
       node: ast::item_fn({inputs: deser_inputs,
@@ -853,7 +860,7 @@ fn ser_enum(cx: ext_ctxt, tps: ser_tps_map, e_name: ast::ident,
                     // Generate body s.emit_enum_variant("foo", 0u,
                     //                                   3u, {|| blk })
                     |-s, blk| {
-                        let v_name = cx.lit_str(v_span, v_name);
+                        let v_name = cx.lit_str(v_span, @cx.str_of(v_name));
                         let v_id = cx.lit_uint(v_span, vidx);
                         let sz = cx.lit_uint(v_span, vec::len(variant_tys));
                         let body = cx.lambda(blk);
@@ -877,7 +884,7 @@ fn ser_enum(cx: ext_ctxt, tps: ser_tps_map, e_name: ast::ident,
         }
     };
     let lam = cx.lambda(cx.blk(e_span, ~[cx.alt_stmt(arms, e_span, v)]));
-    let e_name = cx.lit_str(e_span, e_name);
+    let e_name = cx.lit_str(e_span, @cx.str_of(e_name));
     ~[#ast[stmt]{ $(s).emit_enum($(e_name), $(lam)) }]
 }
 
@@ -935,7 +942,7 @@ fn deser_enum(cx: ext_ctxt, tps: deser_tps_map, e_name: ast::ident,
     arms += ~[impossible_case];
 
     // Generate code like:
-    let e_name = cx.lit_str(e_span, e_name);
+    let e_name = cx.lit_str(e_span, @cx.str_of(e_name));
     let alt_expr = cx.expr(e_span,
                    ast::expr_match(#ast{__i}, arms, ast::alt_exhaustive));
     let var_lambda = #ast{ |__i| $(alt_expr) };
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index b8c036f5724..bb8a845d731 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -23,7 +23,7 @@ type syntax_expander_ =
 // second argument is the origin of the macro, if user-defined
 type syntax_expander = {expander: syntax_expander_, span: option<span>};
 
-type macro_def = {ident: ast::ident, ext: syntax_extension};
+type macro_def = {name: ~str, ext: syntax_extension};
 
 // macro_definer is obsolete, remove when #old_macros go away.
 type macro_definer =
@@ -141,6 +141,9 @@ trait ext_ctxt {
     fn next_id() -> ast::node_id;
     pure fn trace_macros() -> bool;
     fn set_trace_macros(x: bool);
+    /* for unhygienic identifier transformation */
+    fn str_of(id: ast::ident) -> ~str;
+    fn ident_of(st: ~str) -> ast::ident;
 }
 
 fn mk_ctxt(parse_sess: parse::parse_sess,
@@ -211,6 +214,13 @@ fn mk_ctxt(parse_sess: parse::parse_sess,
         fn set_trace_macros(x: bool) {
             self.trace_mac = x
         }
+
+        fn str_of(id: ast::ident) -> ~str {
+            *self.parse_sess.interner.get(id)
+        }
+        fn ident_of(st: ~str) -> ast::ident {
+            self.parse_sess.interner.intern(@st)
+        }
     }
     let imp : ctxt_repr = {
         parse_sess: parse_sess,
@@ -264,12 +274,12 @@ fn get_mac_args(cx: ext_ctxt, sp: span, arg: ast::mac_arg,
                   cx.span_fatal(sp, fmt!{"#%s needs at least %u arguments.",
                                          name, min});
                 }
-                _ => return elts /* we're good */
+                _ => return elts /* we are good */
               }
           }
         _ => {
             cx.span_fatal(sp, fmt!{"#%s: malformed invocation", name})
-          }
+        }
       },
       none => cx.span_fatal(sp, fmt!{"#%s: missing arguments", name})
     }
@@ -298,22 +308,24 @@ fn tt_args_to_original_flavor(cx: ext_ctxt, sp: span, arg: ~[ast::token_tree])
     fn ms(m: matcher_) -> matcher {
         {node: m, span: {lo: 0u, hi: 0u, expn_info: none}}
     }
+    let arg_nm = cx.parse_sess().interner.gensym(@~"arg");
 
     let argument_gram = ~[ms(match_seq(~[
-        ms(match_nonterminal(@~"arg",@~"expr", 0u))
+        ms(match_nonterminal(arg_nm, parse::token::special_idents::expr, 0u))
     ], some(parse::token::COMMA), true, 0u, 1u))];
 
     let arg_reader = new_tt_reader(cx.parse_sess().span_diagnostic,
                                    cx.parse_sess().interner, none, arg);
     let args =
         match parse_or_else(cx.parse_sess(), cx.cfg(), arg_reader as reader,
-                          argument_gram).get(@~"arg") {
-          @matched_seq(s, _) => do s.map() |lf| {
-            match lf {
-              @matched_nonterminal(parse::token::nt_expr(arg)) => {
-                arg /* whew! list of exprs, here we come! */
-              }
-              _ => fail ~"badly-structured parse result"
+                          argument_gram).get(arg_nm) {
+          @matched_seq(s, _) => {
+            do s.map() |lf| {
+                match lf {
+                  @matched_nonterminal(parse::token::nt_expr(arg)) =>
+                    arg, /* whew! list of exprs, here we come! */
+                  _ => fail ~"badly-structured parse result"
+                }
             }
           },
           _ => fail ~"badly-structured parse result"
diff --git a/src/libsyntax/ext/concat_idents.rs b/src/libsyntax/ext/concat_idents.rs
index f5d22e6754c..b53a0439e59 100644
--- a/src/libsyntax/ext/concat_idents.rs
+++ b/src/libsyntax/ext/concat_idents.rs
@@ -3,14 +3,16 @@ import base::*;
 fn expand_syntax_ext(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg,
                      _body: ast::mac_body) -> @ast::expr {
     let args = get_mac_args_no_max(cx,sp,arg,1u,~"concat_idents");
-    let mut res = ~"";
+    let mut res_str = ~"";
     for args.each |e| {
-        res += *expr_to_ident(cx, e, ~"expected an ident");
+        res_str += *cx.parse_sess().interner.get(
+            expr_to_ident(cx, e, ~"expected an ident"));
     }
+    let res = cx.parse_sess().interner.intern(@res_str);
 
     return @{id: cx.next_id(),
           callee_id: cx.next_id(),
-          node: ast::expr_path(@{span: sp, global: false, idents: ~[@res],
+          node: ast::expr_path(@{span: sp, global: false, idents: ~[res],
                                  rp: none, types: ~[]}),
           span: sp};
 }
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 9b50101683a..fb083744321 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -25,7 +25,9 @@ fn expand_expr(exts: hashmap<~str, syntax_extension>, cx: ext_ctxt,
             match mac.node {
               mac_invoc(pth, args, body) => {
                 assert (vec::len(pth.idents) > 0u);
-                let extname = pth.idents[0];
+                /* using idents and token::special_idents would make the
+                the macro names be hygienic */
+                let extname = cx.parse_sess().interner.get(pth.idents[0]);
                 match exts.find(*extname) {
                   none => {
                     cx.span_fatal(pth.span,
@@ -49,7 +51,7 @@ fn expand_expr(exts: hashmap<~str, syntax_extension>, cx: ext_ctxt,
                   }
                   some(macro_defining(ext)) => {
                     let named_extension = ext(cx, mac.span, args, body);
-                    exts.insert(*named_extension.ident, named_extension.ext);
+                    exts.insert(named_extension.name, named_extension.ext);
                     (ast::expr_rec(~[], none), s)
                   }
                   some(expr_tt(_)) => {
@@ -68,7 +70,9 @@ fn expand_expr(exts: hashmap<~str, syntax_extension>, cx: ext_ctxt,
               // finished transitioning.
               mac_invoc_tt(pth, tts) => {
                 assert (vec::len(pth.idents) == 1u);
-                let extname = pth.idents[0];
+                /* using idents and token::special_idents would make the
+                the macro names be hygienic */
+                let extname = cx.parse_sess().interner.get(pth.idents[0]);
                 match exts.find(*extname) {
                   none => {
                     cx.span_fatal(pth.span,
@@ -146,7 +150,7 @@ fn expand_mod_items(exts: hashmap<~str, syntax_extension>, cx: ext_ctxt,
               ast::meta_name_value(n, _) => n,
               ast::meta_list(n, _) => n
             };
-            match exts.find(*mname) {
+            match exts.find(mname) {
               none | some(normal(_)) | some(macro_defining(_))
               | some(expr_tt(_)) | some(item_tt(*)) => items,
               some(item_decorator(dec_fn)) => {
@@ -194,7 +198,7 @@ fn expand_item_mac(exts: hashmap<~str, syntax_extension>,
                    fld: ast_fold) -> option<@ast::item> {
     match it.node {
       item_mac({node: mac_invoc_tt(pth, tts), span}) => {
-        let extname = pth.idents[0];
+        let extname = cx.parse_sess().interner.get(pth.idents[0]);
         match exts.find(*extname) {
           none => {
             cx.span_fatal(pth.span,
@@ -211,7 +215,7 @@ fn expand_item_mac(exts: hashmap<~str, syntax_extension>,
                                          ~"expr macro in item position: " +
                                          *extname),
               mr_def(mdef) => {
-                exts.insert(*mdef.ident, mdef.ext);
+                exts.insert(mdef.name, mdef.ext);
                 none
               }
             };
diff --git a/src/libsyntax/ext/fmt.rs b/src/libsyntax/ext/fmt.rs
index f8966196749..9392ea5ad3c 100644
--- a/src/libsyntax/ext/fmt.rs
+++ b/src/libsyntax/ext/fmt.rs
@@ -37,12 +37,13 @@ fn expand_syntax_ext(cx: ext_ctxt, sp: span, arg: ast::mac_arg,
 fn pieces_to_expr(cx: ext_ctxt, sp: span,
                   pieces: ~[piece], args: ~[@ast::expr])
    -> @ast::expr {
-    fn make_path_vec(_cx: ext_ctxt, ident: ast::ident) -> ~[ast::ident] {
-        return ~[@~"extfmt", @~"rt", ident];
+    fn make_path_vec(_cx: ext_ctxt, ident: @~str) -> ~[ast::ident] {
+        let intr = _cx.parse_sess().interner;
+        return ~[intr.intern(@~"extfmt"), intr.intern(@~"rt"),
+                 intr.intern(ident)];
     }
-    fn make_rt_path_expr(cx: ext_ctxt, sp: span,
-                         ident: ast::ident) -> @ast::expr {
-        let path = make_path_vec(cx, ident);
+    fn make_rt_path_expr(cx: ext_ctxt, sp: span, nm: @~str) -> @ast::expr {
+        let path = make_path_vec(cx, nm);
         return mk_path(cx, sp, path);
     }
     // Produces an AST expression that represents a RT::conv record,
@@ -94,11 +95,13 @@ fn pieces_to_expr(cx: ext_ctxt, sp: span,
         fn make_conv_rec(cx: ext_ctxt, sp: span, flags_expr: @ast::expr,
                          width_expr: @ast::expr, precision_expr: @ast::expr,
                          ty_expr: @ast::expr) -> @ast::expr {
+            let intr = cx.parse_sess().interner;
             return mk_rec_e(cx, sp,
-                         ~[{ident: @~"flags", ex: flags_expr},
-                          {ident: @~"width", ex: width_expr},
-                          {ident: @~"precision", ex: precision_expr},
-                          {ident: @~"ty", ex: ty_expr}]);
+                         ~[{ident: intr.intern(@~"flags"), ex: flags_expr},
+                           {ident: intr.intern(@~"width"), ex: width_expr},
+                           {ident: intr.intern(@~"precision"),
+                            ex: precision_expr},
+                           {ident: intr.intern(@~"ty"), ex: ty_expr}]);
         }
         let rt_conv_flags = make_flags(cx, sp, cnv.flags);
         let rt_conv_width = make_count(cx, sp, cnv.width);
@@ -268,7 +271,10 @@ fn pieces_to_expr(cx: ext_ctxt, sp: span,
     }
 
     let arg_vec = mk_fixed_vec_e(cx, fmt_sp, piece_exprs);
-    return mk_call(cx, fmt_sp, ~[@~"str", @~"concat"], ~[arg_vec]);
+    return mk_call(cx, fmt_sp,
+                   ~[cx.parse_sess().interner.intern(@~"str"),
+                     cx.parse_sess().interner.intern(@~"concat")],
+                   ~[arg_vec]);
 }
 //
 // Local Variables:
diff --git a/src/libsyntax/ext/ident_to_str.rs b/src/libsyntax/ext/ident_to_str.rs
index 06faff9ee1b..9daaf164562 100644
--- a/src/libsyntax/ext/ident_to_str.rs
+++ b/src/libsyntax/ext/ident_to_str.rs
@@ -6,6 +6,6 @@ fn expand_syntax_ext(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg,
                      _body: ast::mac_body) -> @ast::expr {
     let args = get_mac_args(cx,sp,arg,1u,option::some(1u),~"ident_to_str");
 
-    return mk_uniq_str(cx, sp, *expr_to_ident(cx, args[0u],
-                                           ~"expected an ident"));
+    return mk_uniq_str(cx, sp, *cx.parse_sess().interner.get(
+        expr_to_ident(cx, args[0u], ~"expected an ident")));
 }
diff --git a/src/libsyntax/ext/log_syntax.rs b/src/libsyntax/ext/log_syntax.rs
index 4ab3bb29045..61bb00fd6de 100644
--- a/src/libsyntax/ext/log_syntax.rs
+++ b/src/libsyntax/ext/log_syntax.rs
@@ -6,8 +6,7 @@ fn expand_syntax_ext(cx: ext_ctxt, sp: codemap::span, tt: ~[ast::token_tree])
 
     cx.print_backtrace();
     io::stdout().write_line(
-        print::pprust::unexpanded_tt_to_str(ast::tt_delim(tt),
-                                            cx.parse_sess().interner));
+        print::pprust::tt_to_str(ast::tt_delim(tt),cx.parse_sess().interner));
 
     //trivial expression
     return mr_expr(@{id: cx.next_id(), callee_id: cx.next_id(),
diff --git a/src/libsyntax/ext/pipes.rs b/src/libsyntax/ext/pipes.rs
index b9ff13c9578..beda46a2c3b 100644
--- a/src/libsyntax/ext/pipes.rs
+++ b/src/libsyntax/ext/pipes.rs
@@ -54,7 +54,7 @@ fn expand_proto(cx: ext_ctxt, _sp: span, id: ast::ident,
     let rdr = tt_rdr as reader;
     let rust_parser = parser(sess, cfg, rdr.dup(), SOURCE_FILE);
 
-    let proto = rust_parser.parse_proto(id);
+    let proto = rust_parser.parse_proto(cx.str_of(id));
 
     // check for errors
     visit(proto, cx);
diff --git a/src/libsyntax/ext/pipes/ast_builder.rs b/src/libsyntax/ext/pipes/ast_builder.rs
index 39132fd0d59..45873f81dea 100644
--- a/src/libsyntax/ext/pipes/ast_builder.rs
+++ b/src/libsyntax/ext/pipes/ast_builder.rs
@@ -15,14 +15,10 @@ mod syntax {
     export parse;
 }
 
-fn ident(s: &str) -> ast::ident {
-    @(s.to_unique())
-}
-
-fn path(id: ident, span: span) -> @ast::path {
+fn path(ids: ~[ident], span: span) -> @ast::path {
     @{span: span,
       global: false,
-      idents: ~[id],
+      idents: ids,
       rp: none,
       types: ~[]}
 }
@@ -94,7 +90,8 @@ trait ext_ctxt_ast_builder {
 
 impl ext_ctxt: ext_ctxt_ast_builder {
     fn ty_option(ty: @ast::ty) -> @ast::ty {
-        self.ty_path_ast_builder(path(@~"option", self.empty_span())
+        self.ty_path_ast_builder(path(~[self.ident_of(~"option")],
+                                      self.empty_span())
                                  .add_ty(ty))
     }
 
@@ -126,7 +123,7 @@ impl ext_ctxt: ext_ctxt_ast_builder {
                      ty: self.ty_infer(),
                      pat: @{id: self.next_id(),
                             node: ast::pat_ident(ast::bind_by_implicit_ref,
-                                                 path(ident,
+                                                 path(~[ident],
                                                       self.empty_span()),
                                                  none),
                             span: self.empty_span()},
@@ -301,6 +298,6 @@ impl ext_ctxt: ext_ctxt_ast_builder {
 
     fn ty_vars(+ty_params: ~[ast::ty_param]) -> ~[@ast::ty] {
         ty_params.map(|p| self.ty_path_ast_builder(
-            path(p.ident, self.empty_span())))
+            path(~[p.ident], self.empty_span())))
     }
 }
diff --git a/src/libsyntax/ext/pipes/check.rs b/src/libsyntax/ext/pipes/check.rs
index e286b4f76be..b7ad5c21bd9 100644
--- a/src/libsyntax/ext/pipes/check.rs
+++ b/src/libsyntax/ext/pipes/check.rs
@@ -21,8 +21,6 @@ that.
 
 import ext::base::ext_ctxt;
 
-import ast::{ident};
-
 import proto::{state, protocol, next_state};
 import ast_builder::empty_span;
 
@@ -36,11 +34,11 @@ impl ext_ctxt: proto::visitor<(), (), ()>  {
                 state.span, // use a real span!
                 fmt!{"state %s contains no messages, \
                       consider stepping to a terminal state instead",
-                     *state.name})
+                      state.name})
         }
     }
 
-    fn visit_message(name: ident, _span: span, _tys: &[@ast::ty],
+    fn visit_message(name: ~str, _span: span, _tys: &[@ast::ty],
                      this: state, next: next_state) {
         match next {
           some({state: next, tys: next_tys}) => {
@@ -51,7 +49,7 @@ impl ext_ctxt: proto::visitor<(), (), ()>  {
                 self.span_err(
                     proto.get_state(next).span,
                     fmt!{"message %s steps to undefined state, %s",
-                         *name, *next});
+                         name, next});
             }
             else {
                 let next = proto.get_state(next);
@@ -61,7 +59,7 @@ impl ext_ctxt: proto::visitor<(), (), ()>  {
                         next.span, // use a real span
                         fmt!{"message %s target (%s) \
                               needs %u type parameters, but got %u",
-                             *name, *next.name,
+                             name, next.name,
                              next.ty_params.len(),
                              next_tys.len()});
                 }
diff --git a/src/libsyntax/ext/pipes/liveness.rs b/src/libsyntax/ext/pipes/liveness.rs
index 17e569552a7..2325e4ed27d 100644
--- a/src/libsyntax/ext/pipes/liveness.rs
+++ b/src/libsyntax/ext/pipes/liveness.rs
@@ -70,10 +70,10 @@ fn analyze(proto: protocol, _cx: ext_ctxt) {
     }
 
     if self_live.len() > 0 {
-        let states = str::connect(self_live.map(|s| *s.name), ~" ");
+        let states = str::connect(self_live.map(|s| s.name), ~" ");
 
         debug!{"protocol %s is unbounded due to loops involving: %s",
-               *proto.name, states};
+               proto.name, states};
 
         // Someday this will be configurable with a warning
         //cx.span_warn(empty_span(),
@@ -85,7 +85,7 @@ fn analyze(proto: protocol, _cx: ext_ctxt) {
         proto.bounded = some(false);
     }
     else {
-        debug!{"protocol %s is bounded. yay!", *proto.name};
+        debug!{"protocol %s is bounded. yay!", proto.name};
         proto.bounded = some(true);
     }
 }
\ No newline at end of file
diff --git a/src/libsyntax/ext/pipes/parse_proto.rs b/src/libsyntax/ext/pipes/parse_proto.rs
index 84180ff3797..4dc61e54aa4 100644
--- a/src/libsyntax/ext/pipes/parse_proto.rs
+++ b/src/libsyntax/ext/pipes/parse_proto.rs
@@ -1,18 +1,17 @@
 // Parsing pipes protocols from token trees.
 
 import parse::parser;
-import ast::ident;
 import parse::token;
 
 import pipec::*;
 
 trait proto_parser {
-    fn parse_proto(id: ident) -> protocol;
+    fn parse_proto(id: ~str) -> protocol;
     fn parse_state(proto: protocol);
 }
 
 impl parser: proto_parser {
-    fn parse_proto(id: ident) -> protocol {
+    fn parse_proto(id: ~str) -> protocol {
         let proto = protocol(id, self.span);
 
         self.parse_seq_to_before_end(token::EOF,
@@ -24,9 +23,11 @@ impl parser: proto_parser {
 
     fn parse_state(proto: protocol) {
         let id = self.parse_ident();
+        let name = *self.interner.get(id);
+
         self.expect(token::COLON);
         let dir = match copy self.token {
-          token::IDENT(n, _) => self.get_str(n),
+          token::IDENT(n, _) => self.interner.get(n),
           _ => fail
         };
         self.bump();
@@ -41,7 +42,7 @@ impl parser: proto_parser {
         }
         else { ~[] };
 
-        let state = proto.add_state_poly(id, dir, typarms);
+        let state = proto.add_state_poly(name, id, dir, typarms);
 
         // parse the messages
         self.parse_unspanned_seq(
@@ -51,7 +52,7 @@ impl parser: proto_parser {
     }
 
     fn parse_message(state: state) {
-        let mname = self.parse_ident();
+        let mname = *self.interner.get(self.parse_ident());
 
         let args = if self.token == token::LPAREN {
             self.parse_unspanned_seq(token::LPAREN,
@@ -66,7 +67,7 @@ impl parser: proto_parser {
 
         let next = match copy self.token {
           token::IDENT(_, _) => {
-            let name = self.parse_ident();
+            let name = *self.interner.get(self.parse_ident());
             let ntys = if self.token == token::LT {
                 self.parse_unspanned_seq(token::LT,
                                          token::GT,
diff --git a/src/libsyntax/ext/pipes/pipec.rs b/src/libsyntax/ext/pipes/pipec.rs
index f7f2981f066..b5a1ae588a7 100644
--- a/src/libsyntax/ext/pipes/pipec.rs
+++ b/src/libsyntax/ext/pipes/pipec.rs
@@ -13,8 +13,7 @@ import parse;
 import parse::*;
 import proto::*;
 
-import ast_builder::append_types;
-import ast_builder::path;
+import ast_builder::{append_types, path, empty_span};
 
 // Transitional reexports so qquote can find the paths it is looking for
 mod syntax {
@@ -47,17 +46,17 @@ impl message: gen_send {
             debug!("pipec: next state exists");
             let next = this.proto.get_state(next);
             assert next_tys.len() == next.ty_params.len();
-            let arg_names = tys.mapi(|i, _ty| @(~"x_" + i.to_str()));
+            let arg_names = tys.mapi(|i, _ty| cx.ident_of(~"x_"+i.to_str()));
 
             let args_ast = (arg_names, tys).map(
                 |n, t| cx.arg_mode(n, t, ast::by_copy)
             );
 
             let pipe_ty = cx.ty_path_ast_builder(
-                path(this.data_name(), span)
+                path(~[this.data_name()], span)
                 .add_tys(cx.ty_vars(this.ty_params)));
             let args_ast = vec::append(
-                ~[cx.arg_mode(@~"pipe",
+                ~[cx.arg_mode(cx.ident_of(~"pipe"),
                               pipe_ty,
                               ast::by_copy)],
                 args_ast);
@@ -75,10 +74,10 @@ impl message: gen_send {
                 body += ~"let b = pipe.reuse_buffer();\n";
                 body += fmt!("let %s = pipes::send_packet_buffered(\
                               ptr::addr_of(b.buffer.data.%s));\n",
-                             sp, *next.name);
-                body += fmt!("let %s = pipes::recv_packet_buffered(\
+                             sp, next.name);
+                body += fmt!{"let %s = pipes::recv_packet_buffered(\
                               ptr::addr_of(b.buffer.data.%s));\n",
-                             rp, *next.name);
+                             rp, next.name};
             }
             else {
                 let pat = match (this.dir, next.dir) {
@@ -91,10 +90,10 @@ impl message: gen_send {
                 body += fmt!("let %s = pipes::entangle();\n", pat);
             }
             body += fmt!("let message = %s::%s(%s);\n",
-                         *this.proto.name,
-                         *self.name(),
-                         str::connect(vec::append_one(arg_names, @~"s")
-                                      .map(|x| *x),
+                         this.proto.name,
+                         self.name(),
+                         str::connect(vec::append_one(
+                             arg_names.map(|x| cx.str_of(x)), ~"s"),
                                       ~", "));
 
             if !try {
@@ -110,17 +109,15 @@ impl message: gen_send {
 
             let body = cx.parse_expr(body);
 
-            let mut rty = cx.ty_path_ast_builder(path(next.data_name(),
+            let mut rty = cx.ty_path_ast_builder(path(~[next.data_name()],
                                                       span)
                                                  .add_tys(next_tys));
             if try {
                 rty = cx.ty_option(rty);
             }
 
-            let name = if try {
-                @(~"try_" + *self.name())
-            }
-            else { self.name() };
+            let name = cx.ident_of(if try { ~"try_" + self.name()
+                                          } else { self.name() } );
 
             cx.item_fn_poly(name,
                             args_ast,
@@ -131,16 +128,16 @@ impl message: gen_send {
 
             message(id, span, tys, this, none) => {
                 debug!{"pipec: no next state"};
-                let arg_names = tys.mapi(|i, _ty| @(~"x_" + i.to_str()));
+                let arg_names = tys.mapi(|i, _ty| (~"x_" + i.to_str()));
 
                 let args_ast = (arg_names, tys).map(
-                    |n, t| cx.arg_mode(n, t, ast::by_copy)
+                    |n, t| cx.arg_mode(cx.ident_of(n), t, ast::by_copy)
                 );
 
                 let args_ast = vec::append(
-                    ~[cx.arg_mode(@~"pipe",
+                    ~[cx.arg_mode(cx.ident_of(~"pipe"),
                                   cx.ty_path_ast_builder(
-                                      path(this.data_name(), span)
+                                      path(~[this.data_name()], span)
                                       .add_tys(cx.ty_vars(this.ty_params))),
                                   ast::by_copy)],
                     args_ast);
@@ -149,13 +146,13 @@ impl message: gen_send {
                     ~""
                 }
                 else {
-                    ~"(" + str::connect(arg_names.map(|x| *x), ~", ") + ~")"
+                    ~"(" + str::connect(arg_names, ~", ") + ~")"
                 };
 
                 let mut body = ~"{ ";
                 body += fmt!{"let message = %s::%s%s;\n",
-                             *this.proto.name,
-                             *self.name(),
+                             this.proto.name,
+                             self.name(),
                              message_args};
 
                 if !try {
@@ -170,11 +167,11 @@ impl message: gen_send {
                 let body = cx.parse_expr(body);
 
                 let name = if try {
-                    @(~"try_" + *self.name())
+                    ~"try_" + self.name()
                 }
                 else { self.name() };
 
-                cx.item_fn_poly(name,
+                cx.item_fn_poly(cx.ident_of(name),
                                 args_ast,
                                 if try {
                                     cx.ty_option(cx.ty_nil_ast_builder())
@@ -188,7 +185,7 @@ impl message: gen_send {
         }
 
     fn to_ty(cx: ext_ctxt) -> @ast::ty {
-        cx.ty_path_ast_builder(path(self.name(), self.span())
+        cx.ty_path_ast_builder(path(~[cx.ident_of(self.name())], self.span())
           .add_tys(cx.ty_vars(self.get_params())))
     }
 }
@@ -212,21 +209,23 @@ impl state: to_type_decls {
             let tys = match next {
               some({state: next, tys: next_tys}) => {
                 let next = this.proto.get_state(next);
-                let next_name = next.data_name();
+                let next_name = cx.str_of(next.data_name());
 
                 let dir = match this.dir {
-                  send => @~"server",
-                  recv => @~"client"
+                  send => ~"server",
+                  recv => ~"client"
                 };
 
                 vec::append_one(tys,
-                                cx.ty_path_ast_builder((dir + next_name)
-                                           .add_tys(next_tys)))
+                                cx.ty_path_ast_builder(
+                                    path(~[cx.ident_of(dir),
+                                           cx.ident_of(next_name)], span)
+                                    .add_tys(next_tys)))
               }
               none => tys
             };
 
-            let v = cx.variant(name, span, tys);
+            let v = cx.variant(cx.ident_of(name), span, tys);
 
             vec::push(items_msg, v);
         }
@@ -258,9 +257,13 @@ impl state: to_type_decls {
                           self.data_name(),
                           self.span,
                           cx.ty_path_ast_builder(
-                              (@~"pipes" + @(dir.to_str() + ~"_packet"))
+                              path(~[cx.ident_of(~"pipes"),
+                                     cx.ident_of(dir.to_str() + ~"_packet")],
+                                   empty_span())
                               .add_ty(cx.ty_path_ast_builder(
-                                  (self.proto.name + self.data_name())
+                                  path(~[cx.ident_of(self.proto.name),
+                                         self.data_name()],
+                                       empty_span())
                                   .add_tys(cx.ty_vars(self.ty_params))))),
                           self.ty_params));
         }
@@ -270,10 +273,14 @@ impl state: to_type_decls {
                           self.data_name(),
                           self.span,
                           cx.ty_path_ast_builder(
-                              (@~"pipes" + @(dir.to_str()
-                                             + ~"_packet_buffered"))
+                              path(~[cx.ident_of(~"pipes"),
+                                     cx.ident_of(dir.to_str()
+                                                 + ~"_packet_buffered")],
+                                  empty_span())
                               .add_tys(~[cx.ty_path_ast_builder(
-                                  (self.proto.name + self.data_name())
+                                  path(~[cx.ident_of(self.proto.name),
+                                         self.data_name()],
+                                       empty_span())
                                   .add_tys(cx.ty_vars(self.ty_params))),
                                          self.proto.buffer_ty_path(cx)])),
                           self.ty_params));
@@ -315,16 +322,17 @@ impl protocol: gen_init {
 
         cx.parse_item(fmt!{"fn init%s() -> (client::%s, server::%s)\
                             { import pipes::has_buffer; %s }",
-                           start_state.ty_params.to_source(),
-                           start_state.to_ty(cx).to_source(),
-                           start_state.to_ty(cx).to_source(),
-                           body.to_source()})
+                           start_state.ty_params.to_source(cx),
+                           start_state.to_ty(cx).to_source(cx),
+                           start_state.to_ty(cx).to_source(cx),
+                           body.to_source(cx)})
     }
 
     fn gen_buffer_init(ext_cx: ext_ctxt) -> @ast::expr {
         ext_cx.rec(self.states.map_to_vec(|s| {
             let fty = s.to_ty(ext_cx);
-            ext_cx.field_imm(s.name, #ast { pipes::mk_packet::<$(fty)>() })
+            ext_cx.field_imm(ext_cx.ident_of(s.name),
+                             #ast { pipes::mk_packet::<$(fty)>() })
         }))
     }
 
@@ -341,9 +349,11 @@ impl protocol: gen_init {
             ext_cx.block(
                 self.states.map_to_vec(
                     |s| ext_cx.parse_stmt(
-                        fmt!{"data.%s.set_buffer(buffer)", *s.name})),
+                        fmt!{"data.%s.set_buffer(buffer)",
+                             s.name})),
                 ext_cx.parse_expr(
-                    fmt!{"ptr::addr_of(data.%s)", *self.states[0].name})));
+                    fmt!{"ptr::addr_of(data.%s)",
+                         self.states[0].name})));
 
         #ast {{
             let buffer = $(buffer);
@@ -357,14 +367,14 @@ impl protocol: gen_init {
         let mut params: ~[ast::ty_param] = ~[];
         for (copy self.states).each |s| {
             for s.ty_params.each |tp| {
-                match params.find(|tpp| *tp.ident == *tpp.ident) {
+                match params.find(|tpp| tp.ident == tpp.ident) {
                   none => vec::push(params, tp),
                   _ => ()
                 }
             }
         }
 
-        cx.ty_path_ast_builder(path(@~"__Buffer", self.span)
+        cx.ty_path_ast_builder(path(~[cx.ident_of(~"__Buffer")], self.span)
                                .add_tys(cx.ty_vars(params)))
     }
 
@@ -373,7 +383,7 @@ impl protocol: gen_init {
         let mut params: ~[ast::ty_param] = ~[];
         let fields = do (copy self.states).map_to_vec |s| {
             for s.ty_params.each |tp| {
-                match params.find(|tpp| *tp.ident == *tpp.ident) {
+                match params.find(|tpp| tp.ident == tpp.ident) {
                   none => vec::push(params, tp),
                   _ => ()
                 }
@@ -382,11 +392,11 @@ impl protocol: gen_init {
             let fty = #ast[ty] {
                 pipes::packet<$(ty)>
             };
-            cx.ty_field_imm(s.name, fty)
+            cx.ty_field_imm(cx.ident_of(s.name), fty)
         };
 
         cx.item_ty_poly(
-            @~"__Buffer",
+            cx.ident_of(~"__Buffer"),
             cx.empty_span(),
             cx.ty_rec(fields),
             params)
@@ -410,56 +420,56 @@ impl protocol: gen_init {
         }
 
         vec::push(items,
-                  cx.item_mod(@~"client",
+                  cx.item_mod(cx.ident_of(~"client"),
                               self.span,
                               client_states));
         vec::push(items,
-                  cx.item_mod(@~"server",
+                  cx.item_mod(cx.ident_of(~"server"),
                               self.span,
                               server_states));
 
-        cx.item_mod(self.name, self.span, items)
+        cx.item_mod(cx.ident_of(self.name), self.span, items)
     }
 }
 
 trait to_source {
     // Takes a thing and generates a string containing rust code for it.
-    fn to_source() -> ~str;
+    fn to_source(cx: ext_ctxt) -> ~str;
 }
 
 impl @ast::item: to_source {
-    fn to_source() -> ~str {
-        item_to_str(self)
+    fn to_source(cx: ext_ctxt) -> ~str {
+        item_to_str(self, cx.parse_sess().interner)
     }
 }
 
 impl ~[@ast::item]: to_source {
-    fn to_source() -> ~str {
-        str::connect(self.map(|i| i.to_source()), ~"\n\n")
+    fn to_source(cx: ext_ctxt) -> ~str {
+        str::connect(self.map(|i| i.to_source(cx)), ~"\n\n")
     }
 }
 
 impl @ast::ty: to_source {
-    fn to_source() -> ~str {
-        ty_to_str(self)
+    fn to_source(cx: ext_ctxt) -> ~str {
+        ty_to_str(self, cx.parse_sess().interner)
     }
 }
 
 impl ~[@ast::ty]: to_source {
-    fn to_source() -> ~str {
-        str::connect(self.map(|i| i.to_source()), ~", ")
+    fn to_source(cx: ext_ctxt) -> ~str {
+        str::connect(self.map(|i| i.to_source(cx)), ~", ")
     }
 }
 
 impl ~[ast::ty_param]: to_source {
-    fn to_source() -> ~str {
-        pprust::typarams_to_str(self)
+    fn to_source(cx: ext_ctxt) -> ~str {
+        pprust::typarams_to_str(self, cx.parse_sess().interner)
     }
 }
 
 impl @ast::expr: to_source {
-    fn to_source() -> ~str {
-        pprust::expr_to_str(self)
+    fn to_source(cx: ext_ctxt) -> ~str {
+        pprust::expr_to_str(self, cx.parse_sess().interner)
     }
 }
 
diff --git a/src/libsyntax/ext/pipes/proto.rs b/src/libsyntax/ext/pipes/proto.rs
index 9e44ce7acda..62c5329525f 100644
--- a/src/libsyntax/ext/pipes/proto.rs
+++ b/src/libsyntax/ext/pipes/proto.rs
@@ -1,8 +1,6 @@
 import to_str::ToStr;
 import dvec::{DVec, dvec};
 
-import ast::{ident};
-
 import ast_builder::{path, append_types};
 
 enum direction {
@@ -27,15 +25,15 @@ impl direction {
     }
 }
 
-type next_state = option<{state: ident, tys: ~[@ast::ty]}>;
+type next_state = option<{state: ~str, tys: ~[@ast::ty]}>;
 
 enum message {
     // name, span, data, current state, next state
-    message(ident, span, ~[@ast::ty], state, next_state)
+    message(~str, span, ~[@ast::ty], state, next_state)
 }
 
 impl message {
-    fn name() -> ident {
+    fn name() -> ~str {
         match self {
           message(id, _, _, _, _) => id
         }
@@ -58,7 +56,8 @@ impl message {
 enum state {
     state_(@{
         id: uint,
-        name: ident,
+        name: ~str,
+        ident: ast::ident,
         span: span,
         dir: direction,
         ty_params: ~[ast::ty_param],
@@ -68,7 +67,7 @@ enum state {
 }
 
 impl state {
-    fn add_message(name: ident, span: span,
+    fn add_message(name: ~str, span: span,
                    +data: ~[@ast::ty], next: next_state) {
         self.messages.push(message(name, span, data, self,
                                    next));
@@ -78,14 +77,15 @@ impl state {
         (*self).proto.filename()
     }
 
-    fn data_name() -> ident {
-        self.name
+    fn data_name() -> ast::ident {
+        self.ident
     }
 
     /// Returns the type that is used for the messages.
     fn to_ty(cx: ext_ctxt) -> @ast::ty {
         cx.ty_path_ast_builder
-            (path(self.name, self.span).add_tys(cx.ty_vars(self.ty_params)))
+            (path(~[cx.ident_of(self.name)],self.span).add_tys(
+                cx.ty_vars(self.ty_params)))
     }
 
     /// Iterate over the states that can be reached in one message
@@ -105,18 +105,18 @@ impl state {
 
 type protocol = @protocol_;
 
-fn protocol(name: ident, +span: span) -> protocol {
+fn protocol(name: ~str, +span: span) -> protocol {
     @protocol_(name, span)
 }
 
 struct protocol_ {
-    let name: ident;
+    let name: ~str;
     let span: span;
     let states: DVec<state>;
 
     let mut bounded: option<bool>;
 
-    new(name: ident, span: span) {
+    new(name: ~str, span: span) {
         self.name = name;
         self.span = span;
         self.states = dvec();
@@ -124,18 +124,18 @@ struct protocol_ {
     }
 
     /// Get a state.
-    fn get_state(name: ident) -> state {
+    fn get_state(name: ~str) -> state {
         self.states.find(|i| i.name == name).get()
     }
 
     fn get_state_by_id(id: uint) -> state { self.states[id] }
 
-    fn has_state(name: ident) -> bool {
+    fn has_state(name: ~str) -> bool {
         self.states.find(|i| i.name == name) != none
     }
 
     fn filename() -> ~str {
-        ~"proto://" + *self.name
+        ~"proto://" + self.name
     }
 
     fn num_states() -> uint { self.states.len() }
@@ -162,17 +162,14 @@ struct protocol_ {
 }
 
 impl protocol {
-    fn add_state(name: ident, dir: direction) -> state {
-        self.add_state_poly(name, dir, ~[])
-    }
-
-    fn add_state_poly(name: ident, dir: direction,
+    fn add_state_poly(name: ~str, ident: ast::ident, dir: direction,
                       +ty_params: ~[ast::ty_param]) -> state {
         let messages = dvec();
 
         let state = state_(@{
             id: self.states.len(),
             name: name,
+            ident: ident,
             span: self.span,
             dir: dir,
             ty_params: ty_params,
@@ -188,7 +185,7 @@ impl protocol {
 trait visitor<Tproto, Tstate, Tmessage> {
     fn visit_proto(proto: protocol, st: &[Tstate]) -> Tproto;
     fn visit_state(state: state, m: &[Tmessage]) -> Tstate;
-    fn visit_message(name: ident, spane: span, tys: &[@ast::ty],
+    fn visit_message(name: ~str, spane: span, tys: &[@ast::ty],
                      this: state, next: next_state) -> Tmessage;
 }
 
diff --git a/src/libsyntax/ext/qquote.rs b/src/libsyntax/ext/qquote.rs
index 6b5dce312d6..8024f5f9542 100644
--- a/src/libsyntax/ext/qquote.rs
+++ b/src/libsyntax/ext/qquote.rs
@@ -3,6 +3,7 @@ import ast::{crate, expr_, mac_invoc,
 import parse::parser;
 import parse::parser::parse_from_source_str;
 import dvec::{DVec, dvec};
+import parse::token::ident_interner;
 
 import fold::*;
 import visit::*;
@@ -26,6 +27,14 @@ enum fragment {
     from_ty(@ast::ty)
 }
 
+fn ids_ext(cx: ext_ctxt, strs: ~[~str]) -> ~[ast::ident] {
+    strs.map(|str| cx.parse_sess().interner.intern(@str))
+}
+fn id_ext(cx: ext_ctxt, str: ~str) -> ast::ident {
+    cx.parse_sess().interner.intern(@str)
+}
+
+
 trait qq_helper {
     fn span() -> span;
     fn visit(aq_ctxt, vt<aq_ctxt>);
@@ -40,7 +49,7 @@ impl @ast::crate: qq_helper {
     fn extract_mac() -> option<ast::mac_> {fail}
     fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr {
         mk_path(cx, sp,
-                ~[@~"syntax", @~"ext", @~"qquote", @~"parse_crate"])
+                ids_ext(cx, ~[~"syntax", ~"ext", ~"qquote", ~"parse_crate"]))
     }
     fn get_fold_fn() -> ~str {~"fold_crate"}
 }
@@ -55,7 +64,7 @@ impl @ast::expr: qq_helper {
     }
     fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr {
         mk_path(cx, sp,
-                ~[@~"syntax", @~"ext", @~"qquote", @~"parse_expr"])
+                ids_ext(cx, ~[~"syntax", ~"ext", ~"qquote", ~"parse_expr"]))
     }
     fn get_fold_fn() -> ~str {~"fold_expr"}
 }
@@ -70,7 +79,7 @@ impl @ast::ty: qq_helper {
     }
     fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr {
         mk_path(cx, sp,
-                ~[@~"syntax", @~"ext", @~"qquote", @~"parse_ty"])
+                ids_ext(cx, ~[~"syntax", ~"ext", ~"qquote", ~"parse_ty"]))
     }
     fn get_fold_fn() -> ~str {~"fold_ty"}
 }
@@ -80,7 +89,7 @@ impl @ast::item: qq_helper {
     fn extract_mac() -> option<ast::mac_> {fail}
     fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr {
         mk_path(cx, sp,
-                ~[@~"syntax", @~"ext", @~"qquote", @~"parse_item"])
+                ids_ext(cx, ~[~"syntax", ~"ext", ~"qquote", ~"parse_item"]))
     }
     fn get_fold_fn() -> ~str {~"fold_item"}
 }
@@ -90,7 +99,7 @@ impl @ast::stmt: qq_helper {
     fn extract_mac() -> option<ast::mac_> {fail}
     fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr {
         mk_path(cx, sp,
-                ~[@~"syntax", @~"ext", @~"qquote", @~"parse_stmt"])
+                ids_ext(cx, ~[~"syntax", ~"ext", ~"qquote", ~"parse_stmt"]))
     }
     fn get_fold_fn() -> ~str {~"fold_stmt"}
 }
@@ -99,7 +108,8 @@ impl @ast::pat: qq_helper {
     fn visit(cx: aq_ctxt, v: vt<aq_ctxt>) {visit_pat(self, cx, v);}
     fn extract_mac() -> option<ast::mac_> {fail}
     fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr {
-        mk_path(cx, sp, ~[@~"syntax", @~"ext", @~"qquote", @~"parse_pat"])
+        mk_path(cx, sp, ids_ext(cx, ~[~"syntax", ~"ext", ~"qquote",
+                                      ~"parse_pat"]))
     }
     fn get_fold_fn() -> ~str {~"fold_pat"}
 }
@@ -159,7 +169,7 @@ fn expand_ast(ecx: ext_ctxt, _sp: span,
         }
         match (args[0].node) {
           ast::expr_path(@{idents: id, _}) if vec::len(id) == 1u
-          => what = *id[0],
+            => what = *ecx.parse_sess().interner.get(id[0]),
           _ => ecx.span_fatal(args[0].span, ~"expected an identifier")
         }
     }
@@ -243,19 +253,21 @@ fn finish<T: qq_helper>
     let cx = ecx;
 
     let cfg_call = || mk_call_(
-        cx, sp, mk_access(cx, sp, ~[@~"ext_cx"], @~"cfg"), ~[]);
+        cx, sp, mk_access(cx, sp, ids_ext(cx, ~[~"ext_cx"]),
+                          id_ext(cx, ~"cfg")), ~[]);
 
     let parse_sess_call = || mk_call_(
-        cx, sp, mk_access(cx, sp, ~[@~"ext_cx"], @~"parse_sess"), ~[]);
+        cx, sp, mk_access(cx, sp, ids_ext(cx, ~[~"ext_cx"]),
+                          id_ext(cx, ~"parse_sess")), ~[]);
 
     let pcall = mk_call(cx,sp,
-                       ~[@~"syntax", @~"parse", @~"parser",
-                        @~"parse_from_source_str"],
+                       ids_ext(cx, ~[~"syntax", ~"parse", ~"parser",
+                        ~"parse_from_source_str"]),
                        ~[node.mk_parse_fn(cx,sp),
                         mk_uniq_str(cx,sp, fname),
                         mk_call(cx,sp,
-                                ~[@~"syntax",@~"ext",
-                                 @~"qquote", @~"mk_file_substr"],
+                                ids_ext(cx, ~[~"syntax",~"ext",
+                                 ~"qquote", ~"mk_file_substr"]),
                                 ~[mk_uniq_str(cx,sp, loc.file.name),
                                  mk_uint(cx,sp, loc.line),
                                  mk_uint(cx,sp, loc.col)]),
@@ -267,16 +279,17 @@ fn finish<T: qq_helper>
     let mut rcall = pcall;
     if (g_len > 0u) {
         rcall = mk_call(cx,sp,
-                        ~[@~"syntax", @~"ext", @~"qquote", @~"replace"],
+                        ids_ext(cx, ~[~"syntax", ~"ext", ~"qquote",
+                                      ~"replace"]),
                         ~[pcall,
                           mk_uniq_vec_e(cx,sp, qcx.gather.map_to_vec(|g| {
                              mk_call(cx,sp,
-                                     ~[@~"syntax", @~"ext",
-                                      @~"qquote", @g.constr],
+                                     ids_ext(cx, ~[~"syntax", ~"ext",
+                                                   ~"qquote", g.constr]),
                                      ~[g.e])})),
                          mk_path(cx,sp,
-                                 ~[@~"syntax", @~"ext", @~"qquote",
-                                  @node.get_fold_fn()])]);
+                                 ids_ext(cx, ~[~"syntax", ~"ext", ~"qquote",
+                                               node.get_fold_fn()]))]);
     }
     return rcall;
 }
@@ -331,14 +344,6 @@ fn replace_ty(repls: ~[fragment],
     }
 }
 
-fn print_expr(expr: @ast::expr) {
-    let stdout = io::stdout();
-    let pp = pprust::rust_printer(stdout);
-    pprust::print_expr(pp, expr);
-    pp::eof(pp.s);
-    stdout.write_str(~"\n");
-}
-
 fn mk_file_substr(fname: ~str, line: uint, col: uint) ->
     codemap::file_substr {
     codemap::fss_external({filename: fname, line: line, col: col})
diff --git a/src/libsyntax/ext/simplext.rs b/src/libsyntax/ext/simplext.rs
index e8899a2e541..5b9bac1948f 100644
--- a/src/libsyntax/ext/simplext.rs
+++ b/src/libsyntax/ext/simplext.rs
@@ -1,5 +1,5 @@
 import codemap::span;
-import std::map::{hashmap, str_hash, box_str_hash};
+import std::map::{hashmap, str_hash, uint_hash};
 import dvec::{DVec, dvec};
 
 import base::*;
@@ -135,7 +135,7 @@ fn acumm_bindings(_cx: ext_ctxt, _b_dest: bindings, _b_src: bindings) { }
 
 fn pattern_to_selectors(cx: ext_ctxt, e: @expr) -> binders {
     let res: binders =
-        {real_binders: box_str_hash::<selector>(),
+        {real_binders: uint_hash::<selector>(),
          literal_ast_matchers: dvec()};
     //this oughta return binders instead, but macro args are a sequence of
     //expressions, rather than a single expression
@@ -153,7 +153,7 @@ bindings. Most of the work is done in p_t_s, which generates the
 selectors. */
 
 fn use_selectors_to_bind(b: binders, e: @expr) -> option<bindings> {
-    let res = box_str_hash::<arb_depth<matchable>>();
+    let res = uint_hash::<arb_depth<matchable>>();
     //need to do this first, to check vec lengths.
     for b.literal_ast_matchers.each |sel| {
         match sel(match_expr(e)) { none => return none, _ => () }
@@ -237,7 +237,7 @@ fn follow_for_trans(cx: ext_ctxt, mmaybe: option<arb_depth<matchable>>,
 
 /* helper for transcribe_exprs: what vars from `b` occur in `e`? */
 fn free_vars(b: bindings, e: @expr, it: fn(ident)) {
-    let idents: hashmap<ident, ()> = box_str_hash::<()>();
+    let idents: hashmap<ident, ()> = uint_hash::<()>();
     fn mark_ident(&&i: ident, _fld: ast_fold, b: bindings,
                   idents: hashmap<ident, ()>) -> ident {
         if b.contains_key(i) { idents.insert(i, ()); }
@@ -253,6 +253,12 @@ fn free_vars(b: bindings, e: @expr, it: fn(ident)) {
     for idents.each_key |x| { it(x); };
 }
 
+fn wrong_occurs(cx: ext_ctxt, l: ident, l_c: uint, r: ident, r_c: uint)
+    -> ~str {
+    fmt!{"'%s' occurs %u times, but '%s' occurs %u times",
+         *cx.parse_sess().interner.get(l), l_c,
+         *cx.parse_sess().interner.get(r), r_c}
+}
 
 /* handle sequences (anywhere in the AST) of exprs, either real or ...ed */
 fn transcribe_exprs(cx: ext_ctxt, b: bindings, idx_path: @mut ~[uint],
@@ -279,10 +285,8 @@ fn transcribe_exprs(cx: ext_ctxt, b: bindings, idx_path: @mut ~[uint],
                       some({rep_count: old_len, name: old_name}) => {
                         let len = vec::len(*ms);
                         if old_len != len {
-                            let msg =
-                                fmt!{"'%s' occurs %u times, but ", *fv, len} +
-                                    fmt!{"'%s' occurs %u times", *old_name,
-                                         old_len};
+                            let msg = wrong_occurs(cx, fv, len,
+                                                   old_name, old_len);
                             cx.span_fatal(repeat_me.span, msg);
                         }
                       }
@@ -626,7 +630,7 @@ fn add_new_extension(cx: ext_ctxt, sp: span, arg: ast::mac_arg,
                      _body: ast::mac_body) -> base::macro_def {
     let args = get_mac_args_no_max(cx, sp, arg, 0u, ~"macro");
 
-    let mut macro_name: option<@~str> = none;
+    let mut macro_name: option<~str> = none;
     let mut clauses: ~[@clause] = ~[];
     for args.each |arg| {
         match arg.node {
@@ -643,12 +647,15 @@ fn add_new_extension(cx: ext_ctxt, sp: span, arg: ast::mac_arg,
                 match mac.node {
                   mac_invoc(pth, invoc_arg, body) => {
                     match path_to_ident(pth) {
-                      some(id) => match macro_name {
-                        none => macro_name = some(id),
-                        some(other_id) => if id != other_id {
+                      some(id) => {
+                        let id_str = cx.str_of(id);
+                        match macro_name {
+                          none => macro_name = some(id_str),
+                          some(other_id) => if id_str != other_id {
                             cx.span_fatal(pth.span,
                                           ~"macro name must be " +
                                           ~"consistent");
+                          }
                         }
                       },
                       none => cx.span_fatal(pth.span,
@@ -688,7 +695,7 @@ fn add_new_extension(cx: ext_ctxt, sp: span, arg: ast::mac_arg,
 
     let ext = |a,b,c,d, move clauses| generic_extension(a,b,c,d,clauses);
 
-    return {ident:
+    return {name:
              match macro_name {
                some(id) => id,
                none => cx.span_fatal(sp, ~"macro definition must have " +
diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs
index e05a713165b..c323f201b83 100644
--- a/src/libsyntax/ext/source_util.rs
+++ b/src/libsyntax/ext/source_util.rs
@@ -43,14 +43,15 @@ fn expand_file(cx: ext_ctxt, sp: span, arg: ast::mac_arg,
 fn expand_stringify(cx: ext_ctxt, sp: span, arg: ast::mac_arg,
                     _body: ast::mac_body) -> @ast::expr {
     let args = get_mac_args(cx, sp, arg, 1u, option::some(1u), ~"stringify");
-    return mk_uniq_str(cx, sp, pprust::expr_to_str(args[0]));
+    let s = pprust::expr_to_str(args[0], cx.parse_sess().interner);
+    return mk_uniq_str(cx, sp, s);
 }
 
 fn expand_mod(cx: ext_ctxt, sp: span, arg: ast::mac_arg, _body: ast::mac_body)
     -> @ast::expr {
     get_mac_args(cx, sp, arg, 0u, option::some(0u), ~"file");
     return mk_uniq_str(cx, sp,
-                    str::connect(cx.mod_path().map(|x|*x), ~"::"));
+                    str::connect(cx.mod_path().map(|x| cx.str_of(x)), ~"::"));
 }
 
 fn expand_include(cx: ext_ctxt, sp: span, arg: ast::mac_arg,
diff --git a/src/libsyntax/ext/trace_macros.rs b/src/libsyntax/ext/trace_macros.rs
index d4f1493169f..22f0aeaa2c0 100644
--- a/src/libsyntax/ext/trace_macros.rs
+++ b/src/libsyntax/ext/trace_macros.rs
@@ -15,10 +15,10 @@ fn expand_trace_macros(cx: ext_ctxt, sp: span,
     let rdr = tt_rdr as reader;
     let rust_parser = parser(sess, cfg, rdr.dup(), SOURCE_FILE);
 
-    let arg = rust_parser.parse_ident();
+    let arg = cx.str_of(rust_parser.parse_ident());
     match arg {
-      @~"true"  => cx.set_trace_macros(true),
-      @~"false" => cx.set_trace_macros(false),
+      ~"true"  => cx.set_trace_macros(true),
+      ~"false" => cx.set_trace_macros(false),
       _ => cx.span_fatal(sp, ~"trace_macros! only accepts `true` or `false`")
     }
     let rust_parser = parser(sess, cfg, rdr.dup(), SOURCE_FILE);
diff --git a/src/libsyntax/ext/tt/earley_parser.rs b/src/libsyntax/ext/tt/earley_parser.rs
index 77ba941015b..896b6f6e54f 100644
--- a/src/libsyntax/ext/tt/earley_parser.rs
+++ b/src/libsyntax/ext/tt/earley_parser.rs
@@ -10,7 +10,7 @@ import parse::parse_sess;
 import dvec::{DVec, dvec};
 import ast::{matcher, match_tok, match_seq, match_nonterminal, ident};
 import ast_util::mk_sp;
-import std::map::{hashmap, box_str_hash};
+import std::map::{hashmap, uint_hash};
 
 /* This is an Earley-like parser, without support for in-grammar nonterminals,
 onlyl calling out to the main rust parser for named nonterminals (which it
@@ -120,14 +120,14 @@ fn nameize(p_s: parse_sess, ms: ~[matcher], res: ~[@named_match])
           }
           {node: match_nonterminal(bind_name, _, idx), span: sp} => {
             if ret_val.contains_key(bind_name) {
-                p_s.span_diagnostic.span_fatal(sp, ~"Duplicated bind name: "
-                                               + *bind_name)
+                p_s.span_diagnostic.span_fatal(sp, ~"Duplicated bind name: "+
+                                               *p_s.interner.get(bind_name))
             }
             ret_val.insert(bind_name, res[idx]);
           }
         }
     }
-    let ret_val = box_str_hash::<@named_match>();
+    let ret_val = uint_hash::<@named_match>();
     for ms.each() |m| { n_rec(p_s, m, res, ret_val) }
     return ret_val;
 }
@@ -274,7 +274,8 @@ fn parse(sess: parse_sess, cfg: ast::crate_cfg, rdr: reader, ms: ~[matcher])
                 let nts = str::connect(vec::map(bb_eis, |ei| {
                     match ei.elts[ei.idx].node {
                       match_nonterminal(bind,name,_) => {
-                        fmt!{"%s ('%s')", *name, *bind}
+                        fmt!{"%s ('%s')", *sess.interner.get(name),
+                             *sess.interner.get(bind)}
                       }
                       _ => fail
                     } }), ~" or ");
@@ -298,7 +299,7 @@ fn parse(sess: parse_sess, cfg: ast::crate_cfg, rdr: reader, ms: ~[matcher])
                 match ei.elts[ei.idx].node {
                   match_nonterminal(_, name, idx) => {
                     ei.matches[idx].push(@matched_nonterminal(
-                        parse_nt(rust_parser, *name)));
+                        parse_nt(rust_parser, *sess.interner.get(name))));
                     ei.idx += 1u;
                   }
                   _ => fail
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 05db498a022..be7594ff843 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -8,6 +8,7 @@ import parse::parser::{parser, SOURCE_FILE};
 import earley_parser::{parse, parse_or_else, success, failure, named_match,
                        matched_seq, matched_nonterminal, error};
 import std::map::hashmap;
+import parse::token::special_idents;
 
 fn add_new_extension(cx: ext_ctxt, sp: span, name: ident,
                      arg: ~[ast::token_tree]) -> base::mac_result {
@@ -16,14 +17,17 @@ fn add_new_extension(cx: ext_ctxt, sp: span, name: ident,
         {node: m, span: {lo: 0u, hi: 0u, expn_info: none}}
     }
 
+    let lhs_nm =  cx.parse_sess().interner.gensym(@~"lhs");
+    let rhs_nm =  cx.parse_sess().interner.gensym(@~"rhs");
+
     // The grammar for macro_rules! is:
     // $( $lhs:mtcs => $rhs:tt );+
     // ...quasiquoting this would be nice.
     let argument_gram = ~[
         ms(match_seq(~[
-            ms(match_nonterminal(@~"lhs",@~"matchers", 0u)),
+            ms(match_nonterminal(lhs_nm, special_idents::matchers, 0u)),
             ms(match_tok(FAT_ARROW)),
-            ms(match_nonterminal(@~"rhs",@~"tt", 1u)),
+            ms(match_nonterminal(rhs_nm, special_idents::tt, 1u)),
         ], some(SEMI), false, 0u, 2u)),
         //to phase into semicolon-termination instead of
         //semicolon-separation
@@ -37,11 +41,11 @@ fn add_new_extension(cx: ext_ctxt, sp: span, name: ident,
                                      arg_reader as reader, argument_gram);
 
     // Extract the arguments:
-    let lhses:~[@named_match] = match argument_map.get(@~"lhs") {
+    let lhses:~[@named_match] = match argument_map.get(lhs_nm) {
       @matched_seq(s, sp) => s,
       _ => cx.span_bug(sp, ~"wrong-structured lhs")
     };
-    let rhses:~[@named_match] = match argument_map.get(@~"rhs") {
+    let rhses:~[@named_match] = match argument_map.get(rhs_nm) {
       @matched_seq(s, sp) => s,
       _ => cx.span_bug(sp, ~"wrong-structured rhs")
     };
@@ -53,8 +57,9 @@ fn add_new_extension(cx: ext_ctxt, sp: span, name: ident,
     -> mac_result {
 
         if cx.trace_macros() {
-            io::println(fmt!("%s! { %s }", *name,
-                             print::pprust::unexpanded_tt_to_str(
+            io::println(fmt!("%s! { %s }",
+                             cx.str_of(name),
+                             print::pprust::tt_to_str(
                                  ast::tt_delim(arg),
                                  cx.parse_sess().interner)));
         }
@@ -103,7 +108,7 @@ fn add_new_extension(cx: ext_ctxt, sp: span, name: ident,
                                               arg, lhses, rhses);
 
     return mr_def({
-        ident: name,
+        name: *cx.parse_sess().interner.get(name),
         ext: expr_tt({expander: exp, span: some(sp)})
     });
 }
\ No newline at end of file
diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs
index a166957231e..1653c57bf2c 100644
--- a/src/libsyntax/ext/tt/transcribe.rs
+++ b/src/libsyntax/ext/tt/transcribe.rs
@@ -47,7 +47,7 @@ fn new_tt_reader(sp_diag: span_handler, itr: ident_interner,
               mut cur: @{readme: src, mut idx: 0u, dotdotdoted: false,
                          sep: none, up: tt_frame_up(option::none)},
               interpolations: match interp { /* just a convienience */
-                none => std::map::box_str_hash::<@named_match>(),
+                none => std::map::uint_hash::<@named_match>(),
                 some(x) => x
               },
               mut repeat_idx: ~[mut], mut repeat_len: ~[],
@@ -100,8 +100,8 @@ enum lis {
     lis_unconstrained, lis_constraint(uint, ident), lis_contradiction(~str)
 }
 
-fn lockstep_iter_size(&&t: token_tree, &&r: tt_reader) -> lis {
-    fn lis_merge(lhs: lis, rhs: lis) -> lis {
+fn lockstep_iter_size(t: token_tree, r: tt_reader) -> lis {
+    fn lis_merge(lhs: lis, rhs: lis, r: tt_reader) -> lis {
         match lhs {
           lis_unconstrained => rhs,
           lis_contradiction(_) => lhs,
@@ -110,9 +110,11 @@ fn lockstep_iter_size(&&t: token_tree, &&r: tt_reader) -> lis {
             lis_contradiction(_) => rhs,
             lis_constraint(r_len, _) if l_len == r_len => lhs,
             lis_constraint(r_len, r_id) => {
+                let l_n = *r.interner.get(l_id);
+                let r_n = *r.interner.get(r_id);
                 lis_contradiction(fmt!{"Inconsistent lockstep iteration: \
                                        '%s' has %u items, but '%s' has %u",
-                                        *l_id, l_len, *r_id, r_len})
+                                        l_n, l_len, r_n, r_len})
             }
           }
         }
@@ -120,7 +122,7 @@ fn lockstep_iter_size(&&t: token_tree, &&r: tt_reader) -> lis {
     match t {
       tt_delim(tts) | tt_seq(_, tts, _, _) => {
         vec::foldl(lis_unconstrained, tts, {|lis, tt|
-            lis_merge(lis, lockstep_iter_size(tt, r)) })
+            lis_merge(lis, lockstep_iter_size(tt, r), r) })
       }
       tt_tok(*) => lis_unconstrained,
       tt_nonterminal(_, name) => match *lookup_cur_matched(r, name) {
@@ -230,7 +232,7 @@ fn tt_next_token(&&r: tt_reader) -> {tok: token, sp: span} {
                 r.sp_diag.span_fatal(
                     copy r.cur_span, /* blame the macro writer */
                     fmt!{"variable '%s' is still repeating at this depth",
-                         *ident});
+                         *r.interner.get(ident)});
               }
             }
           }
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 705f21895b6..05191c677a0 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -81,15 +81,14 @@ type ast_fold_precursor = @{
 fn fold_meta_item_(&&mi: @meta_item, fld: ast_fold) -> @meta_item {
     return @{node:
               match mi.node {
-                meta_word(id) => meta_word(fld.fold_ident(id)),
+                meta_word(id) => meta_word(id),
                 meta_list(id, mis) => {
                   let fold_meta_item = |x|fold_meta_item_(x, fld);
                   meta_list(/* FIXME: (#2543) */ copy id,
                             vec::map(mis, fold_meta_item))
                 }
                 meta_name_value(id, s) => {
-                  meta_name_value(fld.fold_ident(id),
-                                  /* FIXME (#2543) */ copy s)
+                  meta_name_value(id, /* FIXME (#2543) */ copy s)
                 }
               },
           span: fld.new_span(mi.span)};
diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs
index cbb6709d9c8..54b0e3388f7 100644
--- a/src/libsyntax/parse/attr.rs
+++ b/src/libsyntax/parse/attr.rs
@@ -66,7 +66,7 @@ impl parser: parser_attr {
               }
               token::DOC_COMMENT(s) => {
                 let attr = ::attr::mk_sugared_doc_attr(
-                        *self.get_str(s), self.span.lo, self.span.hi);
+                        *self.id_to_str(s), self.span.lo, self.span.hi);
                 if attr.node.style != ast::attr_outer {
                   self.fatal(~"expected outer comment");
                 }
@@ -128,7 +128,7 @@ impl parser: parser_attr {
               }
               token::DOC_COMMENT(s) => {
                 let attr = ::attr::mk_sugared_doc_attr(
-                        *self.get_str(s), self.span.lo, self.span.hi);
+                        *self.id_to_str(s), self.span.lo, self.span.hi);
                 self.bump();
                 if attr.node.style == ast::attr_inner {
                   inner_attrs += ~[attr];
@@ -145,22 +145,22 @@ impl parser: parser_attr {
 
     fn parse_meta_item() -> @ast::meta_item {
         let lo = self.span.lo;
-        let ident = self.parse_ident();
+        let name = *self.id_to_str(self.parse_ident());
         match self.token {
           token::EQ => {
             self.bump();
             let lit = self.parse_lit();
             let mut hi = self.span.hi;
-            return @spanned(lo, hi, ast::meta_name_value(ident, lit));
+            return @spanned(lo, hi, ast::meta_name_value(name, lit));
           }
           token::LPAREN => {
             let inner_items = self.parse_meta_seq();
             let mut hi = self.span.hi;
-            return @spanned(lo, hi, ast::meta_list(ident, inner_items));
+            return @spanned(lo, hi, ast::meta_list(name, inner_items));
           }
           _ => {
             let mut hi = self.span.hi;
-            return @spanned(lo, hi, ast::meta_word(ident));
+            return @spanned(lo, hi, ast::meta_word(name));
           }
         }
     }
diff --git a/src/libsyntax/parse/comments.rs b/src/libsyntax/parse/comments.rs
index b10da4482e4..09edbda4335 100644
--- a/src/libsyntax/parse/comments.rs
+++ b/src/libsyntax/parse/comments.rs
@@ -276,7 +276,7 @@ fn gather_comments_and_literals(span_diagnostic: diagnostic::span_handler,
                                 srdr: io::Reader) ->
    {cmnts: ~[cmnt], lits: ~[lit]} {
     let src = @str::from_bytes(srdr.read_whole_stream());
-    let itr = parse::token::mk_ident_interner();
+    let itr = parse::token::mk_fake_ident_interner();
     let rdr = lexer::new_low_level_string_reader
         (span_diagnostic, codemap::new_filemap(path, src, 0u, 0u), itr);
 
diff --git a/src/libsyntax/parse/common.rs b/src/libsyntax/parse/common.rs
index 59dad16dc44..1d260268d3f 100644
--- a/src/libsyntax/parse/common.rs
+++ b/src/libsyntax/parse/common.rs
@@ -85,7 +85,7 @@ impl parser: parser_common {
 
     fn parse_ident() -> ast::ident {
         match copy self.token {
-          token::IDENT(i, _) => { self.bump(); return self.get_str(i); }
+          token::IDENT(i, _) => { self.bump(); return i; }
           token::INTERPOLATED(token::nt_ident(*)) => { self.bug(
               ~"ident interpolation not converted to real token"); }
           _ => { self.fatal(~"expected ident, found `"
@@ -110,6 +110,8 @@ impl parser: parser_common {
         return if self.token == tok { self.bump(); true } else { false };
     }
 
+    // Storing keywords as interned idents instead of strings would be nifty.
+
     // A sanity check that the word we are asking for is a known keyword
     fn require_keyword(word: ~str) {
         if !self.keywords.contains_key_ref(&word) {
@@ -119,7 +121,7 @@ impl parser: parser_common {
 
     fn token_is_word(word: ~str, ++tok: token::token) -> bool {
         match tok {
-          token::IDENT(sid, false) => { word == *self.get_str(sid) }
+          token::IDENT(sid, false) => { *self.id_to_str(sid) == word }
           _ => { false }
         }
     }
@@ -136,7 +138,7 @@ impl parser: parser_common {
     fn is_any_keyword(tok: token::token) -> bool {
         match tok {
           token::IDENT(sid, false) => {
-            self.keywords.contains_key_ref(self.get_str(sid))
+            self.keywords.contains_key_ref(self.id_to_str(sid))
           }
           _ => false
         }
@@ -148,7 +150,7 @@ impl parser: parser_common {
         let mut bump = false;
         let val = match self.token {
           token::IDENT(sid, false) => {
-            if word == *self.get_str(sid) {
+            if word == *self.id_to_str(sid) {
                 bump = true;
                 true
             } else { false }
diff --git a/src/libsyntax/parse/eval.rs b/src/libsyntax/parse/eval.rs
index 6b0112922a5..60d2fadb04c 100644
--- a/src/libsyntax/parse/eval.rs
+++ b/src/libsyntax/parse/eval.rs
@@ -78,10 +78,10 @@ fn parse_companion_mod(cx: ctx, prefix: ~str, suffix: option<~str>)
     }
 }
 
-fn cdir_path_opt(id: ast::ident, attrs: ~[ast::attribute]) -> @~str {
+fn cdir_path_opt(default: ~str, attrs: ~[ast::attribute]) -> ~str {
     match ::attr::first_attr_value_str_by_name(attrs, ~"path") {
-      some(d) => return d,
-      none => return id
+      some(d) => d,
+      none => default
     }
 }
 
@@ -90,11 +90,12 @@ fn eval_crate_directive(cx: ctx, cdir: @ast::crate_directive, prefix: ~str,
                         &items: ~[@ast::item]) {
     match cdir.node {
       ast::cdir_src_mod(id, attrs) => {
-        let file_path = cdir_path_opt(@(*id + ~".rs"), attrs);
+        let file_path = cdir_path_opt((cx.sess.interner.get(id) + ~".rs"),
+                                      attrs);
         let full_path =
-            if path::path_is_absolute(*file_path) {
-                *file_path
-            } else { prefix + path::path_sep() + *file_path };
+            if path::path_is_absolute(file_path) {
+                file_path
+            } else { prefix + path::path_sep() + file_path };
         let (p0, r0) =
             new_parser_etc_from_file(cx.sess, cx.cfg, full_path, SOURCE_FILE);
         let inner_attrs = p0.parse_inner_attrs_and_next();
@@ -111,11 +112,11 @@ fn eval_crate_directive(cx: ctx, cdir: @ast::crate_directive, prefix: ~str,
         vec::push(items, i);
       }
       ast::cdir_dir_mod(id, cdirs, attrs) => {
-        let path = cdir_path_opt(id, attrs);
+        let path = cdir_path_opt(*cx.sess.interner.get(id), attrs);
         let full_path =
-            if path::path_is_absolute(*path) {
-                *path
-            } else { prefix + path::path_sep() + *path };
+            if path::path_is_absolute(path) {
+                path
+            } else { prefix + path::path_sep() + path };
         let (m0, a0) = eval_crate_directives_to_mod(
             cx, cdirs, full_path, none);
         let i =
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 648ec3e60db..fea79309c21 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -6,7 +6,7 @@ import std::map::{hashmap, str_hash};
 import token::{can_begin_expr, is_ident, is_ident_or_path, is_plain_ident,
                INTERPOLATED};
 import codemap::{span,fss_none};
-import util::interner;
+import util::interner::interner;
 import ast_util::{spanned, respan, mk_sp, ident_to_path, operator_prec};
 import lexer::reader;
 import prec::{as_prec, token_to_binop};
@@ -193,12 +193,14 @@ struct parser {
     let mut restriction: restriction;
     let mut quote_depth: uint; // not (yet) related to the quasiquoter
     let reader: reader;
+    let interner: interner<@~str>;
     let keywords: hashmap<~str, ()>;
     let restricted_keywords: hashmap<~str, ()>;
 
     new(sess: parse_sess, cfg: ast::crate_cfg, +rdr: reader, ftype: file_type)
     {
         self.reader <- rdr;
+        self.interner = self.reader.interner();
         let tok0 = self.reader.next_token();
         let span0 = tok0.sp;
         self.sess = sess;
@@ -268,11 +270,10 @@ struct parser {
     fn warn(m: ~str) {
         self.sess.span_diagnostic.span_warn(copy self.span, m)
     }
-    pure fn get_str(i: token::str_num) -> @~str {
-        self.reader.interner().get(i)
-    }
     fn get_id() -> node_id { next_node_id(self.sess) }
 
+    pure fn id_to_str(id: ident) -> @~str { self.sess.interner.get(id) }
+
     fn parse_ty_fn(purity: ast::purity) -> ty_ {
         let proto, bounds;
         if self.eat_keyword(~"extern") {
@@ -398,9 +399,9 @@ struct parser {
         }
     }
 
-    fn region_from_name(s: option<@~str>) -> @region {
+    fn region_from_name(s: option<ident>) -> @region {
         let r = match s {
-          some (string) => re_named(string),
+          some (id) => re_named(id),
           none => re_anon
         };
 
@@ -414,8 +415,7 @@ struct parser {
         match copy self.token {
           token::IDENT(sid, _) => {
             self.bump();
-            let n = self.get_str(sid);
-            self.region_from_name(some(n))
+            self.region_from_name(some(sid))
           }
           _ => {
             self.region_from_name(none)
@@ -430,7 +430,7 @@ struct parser {
               token::IDENT(sid, _) => {
                 if self.look_ahead(1u) == token::BINOP(token::SLASH) {
                     self.bump(); self.bump();
-                    some(self.get_str(sid))
+                    some(sid)
                 } else {
                     none
                 }
@@ -583,7 +583,7 @@ struct parser {
                 let name = self.parse_value_ident();
                 self.bump();
                 name
-            } else { @~"" }
+            } else { token::special_idents::invalid }
         };
 
         let t = self.parse_ty(false);
@@ -678,10 +678,10 @@ struct parser {
           token::LIT_INT(i, it) => lit_int(i, it),
           token::LIT_UINT(u, ut) => lit_uint(u, ut),
           token::LIT_INT_UNSUFFIXED(i) => lit_int_unsuffixed(i),
-          token::LIT_FLOAT(s, ft) => lit_float(self.get_str(s), ft),
-          token::LIT_STR(s) => lit_str(self.get_str(s)),
-          token::LPAREN => { self.expect(token::RPAREN); lit_nil }
-          _ => self.unexpected_last(tok)
+          token::LIT_FLOAT(s, ft) => lit_float(self.id_to_str(s), ft),
+          token::LIT_STR(s) => lit_str(self.id_to_str(s)),
+          token::LPAREN => { self.expect(token::RPAREN); lit_nil },
+          _ => { self.unexpected_last(tok); }
         }
     }
 
@@ -1140,8 +1140,7 @@ struct parser {
                         self.parse_seq_to_gt(some(token::COMMA),
                                              |p| p.parse_ty(false))
                     } else { ~[] };
-                    e = self.mk_pexpr(lo, hi, expr_field(self.to_expr(e),
-                                                         self.get_str(i),
+                    e = self.mk_pexpr(lo, hi, expr_field(self.to_expr(e), i,
                                                          tys));
                   }
                   _ => self.unexpected()
@@ -2123,9 +2122,6 @@ struct parser {
     }
 
     fn expr_is_complete(e: pexpr) -> bool {
-        log(debug, (~"expr_is_complete", self.restriction,
-                    print::pprust::expr_to_str(*e),
-                    classify::expr_requires_semi_to_be_stmt(*e)));
         return self.restriction == RESTRICT_STMT_EXPR &&
             !classify::expr_requires_semi_to_be_stmt(*e);
     }
@@ -2306,8 +2302,9 @@ struct parser {
 
     fn is_self_ident() -> bool {
         match self.token {
-            token::IDENT(sid, false) if ~"self" == *self.get_str(sid) => true,
-            _ => false
+          token::IDENT(id, false) if id == token::special_idents::self_
+            => true,
+          _ => false
         }
     }
 
@@ -2522,11 +2519,13 @@ struct parser {
         }
 
         // This is a new-style impl declaration.
-        let ident = @~"__extensions__";     // XXX: clownshoes
+        // XXX: clownshoes
+        let ident = token::special_idents::clownshoes_extensions;
 
         // Parse the type.
         let ty = self.parse_ty(false);
 
+
         // Parse traits, if necessary.
         let traits = if self.token == token::COLON {
             self.bump();
@@ -2595,7 +2594,8 @@ struct parser {
                       match the_ctor {
                         some((_, _, _, s_first)) => {
                           self.span_note(s, #fmt("Duplicate constructor \
-                                     declaration for class %s", *class_name));
+                                     declaration for class %s",
+                                     *self.interner.get(class_name)));
                            self.span_fatal(copy s_first, ~"First constructor \
                                                           declared here");
                         }
@@ -2608,7 +2608,8 @@ struct parser {
                       match the_dtor {
                         some((_, _, s_first)) => {
                           self.span_note(s, #fmt("Duplicate destructor \
-                                     declaration for class %s", *class_name));
+                                     declaration for class %s",
+                                     *self.interner.get(class_name)));
                           self.span_fatal(copy s_first, ~"First destructor \
                                                           declared here");
                         }
@@ -3081,7 +3082,7 @@ struct parser {
         let ty_params = self.parse_ty_params();
         // Newtype syntax
         if self.token == token::EQ {
-            self.check_restricted_keywords_(*id);
+            self.check_restricted_keywords_(*self.id_to_str(id));
             self.bump();
             let ty = self.parse_ty(false);
             self.expect(token::SEMI);
@@ -3297,7 +3298,7 @@ struct parser {
         let lo = self.span.lo;
         let first_ident = self.parse_ident();
         let mut path = ~[first_ident];
-        debug!{"parsed view_path: %s", *first_ident};
+        debug!{"parsed view_path: %s", *self.id_to_str(first_ident)};
         match self.token {
           token::EQ => {
             // x = foo::bar
@@ -3323,7 +3324,7 @@ struct parser {
 
                   token::IDENT(i, _) => {
                     self.bump();
-                    vec::push(path, self.get_str(i));
+                    vec::push(path, i);
                   }
 
                   // foo::bar::{a,b,c}
@@ -3458,8 +3459,8 @@ struct parser {
 
     fn parse_str() -> @~str {
         match copy self.token {
-          token::LIT_STR(s) => { self.bump(); self.get_str(s) }
-          _ => self.fatal(~"expected string literal")
+          token::LIT_STR(s) => { self.bump(); self.id_to_str(s) }
+          _ =>  self.fatal(~"expected string literal")
         }
     }
 
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 10fac8d0e23..8eb9270efe2 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -277,23 +277,83 @@ pure fn is_bar(t: token) -> bool {
     match t { BINOP(OR) | OROR => true, _ => false }
 }
 
-type ident_interner = util::interner::interner<@~str>;
 
 mod special_idents {
-    const underscore : uint = 0u;
-    const anon : uint = 1u;
-    const destr : uint = 2u; // 'drop', but that's reserved
+    import ast::ident;
+    const underscore : ident = 0u;
+    const anon : ident = 1u;
+    const dtor : ident = 2u; // 'drop', but that's reserved
+    const invalid : ident = 3u; // ''
+    const unary : ident = 4u;
+    const not_fn : ident = 5u;
+    const idx_fn : ident = 6u;
+    const unary_minus_fn : ident = 7u;
+    const clownshoes_extensions : ident = 8u;
+
+    const self_ : ident = 9u; // 'self'
+
+    /* for matcher NTs */
+    const item : ident = 10u;
+    const block : ident = 11u;
+    const stmt : ident = 12u;
+    const pat : ident = 13u;
+    const expr : ident = 14u;
+    const ty : ident = 15u;
+    const ident : ident = 16u;
+    const path : ident = 17u;
+    const tt : ident = 18u;
+    const matchers : ident = 19u;
+
+    const str : ident = 20u; // for the type
+
+    /* outside of libsyntax */
+    const ty_visitor : ident = 21u;
+    const arg : ident = 22u;
+    const descrim : ident = 23u;
+    const clownshoe_abi : ident = 24u;
+    const clownshoe_stack_shim : ident = 25u;
+    const tydesc : ident = 26u;
+    const literally_dtor : ident = 27u;
+    const main : ident = 28u;
+    const opaque : ident = 29u;
+    const blk : ident = 30u;
+    const static : ident = 31u;
+    const intrinsic : ident = 32u;
+
 }
 
+type ident_interner = util::interner::interner<@~str>;
+
+/** Key for thread-local data for sneaking interner information to the
+ * serializer/deserializer. It sounds like a hack because it is one. */
+fn interner_key(+_x: @@ident_interner) { }
+
 fn mk_ident_interner() -> ident_interner {
     /* the indices here must correspond to the numbers in special_idents */
-    let init_vec = ~[@~"_", @~"anon", @~"drop"];
-
-    let rv = @interner::mk_prefill::<@~str>(|x| str::hash(*x),
-                                            |x,y| str::eq(*x, *y), init_vec);
+    let init_vec = ~[@~"_", @~"anon", @~"drop", @~"", @~"unary", @~"!",
+                     @~"[]", @~"unary-", @~"__extensions__", @~"self",
+                     @~"item", @~"block", @~"stmt", @~"pat", @~"expr",
+                     @~"ty", @~"ident", @~"path", @~"tt", @~"matchers",
+                     @~"str", @~"ty_visitor", @~"arg", @~"descrim",
+                     @~"__rust_abi", @~"__rust_stack_shim", @~"tydesc",
+                     @~"dtor", @~"main", @~"<opaque>", @~"blk", @~"static",
+                     @~"intrinsic"];
+
+    let rv = interner::mk_prefill::<@~str>(|x| str::hash(*x),
+                                           |x,y| str::eq(*x, *y), init_vec);
+
+    /* having multiple interners will just confuse the serializer */
+    unsafe{ assert task::local_data_get(interner_key) == none };
+    unsafe{ task::local_data_set(interner_key, @rv) };
     rv
 }
 
+/* for when we don't care about the contents; doesn't interact with TLD or
+   serialization */
+fn mk_fake_ident_interner() -> ident_interner {
+    interner::mk::<@~str>(|x| str::hash(*x), |x,y| str::eq(*x, *y))
+}
+
 /**
  * All the valid words that have meaning in the Rust language.
  *
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index b8872f76d8d..573eeffd968 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -8,9 +8,7 @@ import ast::{required, provided};
 import ast_util::{operator_prec};
 import dvec::{DVec, dvec};
 import parse::classify::*;
-import util::interner;
-
-type ident_interner = interner::interner<@~str>;
+import parse::token::ident_interner;
 
 // The ps is stored here to prevent recursive type.
 enum ann_node {
@@ -47,19 +45,7 @@ fn end(s: ps) {
     pp::end(s.s);
 }
 
-fn rust_printer(writer: io::Writer) -> ps {
-    return @{s: pp::mk_printer(writer, default_columns),
-             cm: none::<codemap>,
-             intr: token::mk_ident_interner(),
-             comments: none::<~[comments::cmnt]>,
-             literals: none::<~[comments::lit]>,
-             mut cur_cmnt: 0u,
-             mut cur_lit: 0u,
-             boxes: dvec(),
-             ann: no_ann()};
-}
-
-fn unexpanded_rust_printer(writer: io::Writer, intr: ident_interner) -> ps {
+fn rust_printer(writer: io::Writer, intr: ident_interner) -> ps {
     return @{s: pp::mk_printer(writer, default_columns),
              cm: none::<codemap>,
              intr: intr,
@@ -79,7 +65,7 @@ const default_columns: uint = 78u;
 // Requires you to pass an input filename and reader so that
 // it can scan the input text for comments and literals to
 // copy forward.
-fn print_crate(cm: codemap, intr: interner::interner<@~str>,
+fn print_crate(cm: codemap, intr: ident_interner,
                span_diagnostic: diagnostic::span_handler,
                crate: @ast::crate, filename: ~str, in: io::Reader,
                out: io::Writer, ann: pp_ann, is_expanded: bool) {
@@ -107,41 +93,46 @@ fn print_crate_(s: ps, &&crate: @ast::crate) {
     eof(s.s);
 }
 
-fn ty_to_str(ty: @ast::ty) -> ~str { return to_str(ty, print_type); }
+fn ty_to_str(ty: @ast::ty, intr: ident_interner) -> ~str {
+    to_str(ty, print_type, intr)
+}
 
-fn pat_to_str(pat: @ast::pat) -> ~str { return to_str(pat, print_pat); }
+fn pat_to_str(pat: @ast::pat, intr: ident_interner) -> ~str {
+    to_str(pat, print_pat, intr)
+}
 
-fn expr_to_str(e: @ast::expr) -> ~str { return to_str(e, print_expr); }
+fn expr_to_str(e: @ast::expr, intr: ident_interner) -> ~str {
+    to_str(e, print_expr, intr)
+}
 
-fn unexpanded_tt_to_str(tt: ast::token_tree, intr: ident_interner)
-    -> ~str {
-    let buffer = io::mem_buffer();
-    let s = unexpanded_rust_printer(io::mem_buffer_writer(buffer), intr);
-    print_tt(s, tt);
-    eof(s.s);
-    io::mem_buffer_str(buffer)
+fn tt_to_str(tt: ast::token_tree, intr: ident_interner) -> ~str {
+    to_str(tt, print_tt, intr)
 }
 
-fn stmt_to_str(s: ast::stmt) -> ~str { return to_str(s, print_stmt); }
+fn stmt_to_str(s: ast::stmt, intr: ident_interner) -> ~str {
+    to_str(s, print_stmt, intr)
+}
 
-fn item_to_str(i: @ast::item) -> ~str { return to_str(i, print_item); }
+fn item_to_str(i: @ast::item, intr: ident_interner) -> ~str {
+    to_str(i, print_item, intr)
+}
 
-fn attr_to_str(i: ast::attribute) -> ~str {
-    return to_str(i, print_attribute);
+fn attr_to_str(i: ast::attribute, intr: ident_interner) -> ~str {
+    to_str(i, print_attribute, intr)
 }
 
-fn typarams_to_str(tps: ~[ast::ty_param]) -> ~str {
-    return to_str(tps, print_type_params)
+fn typarams_to_str(tps: ~[ast::ty_param], intr: ident_interner) -> ~str {
+    to_str(tps, print_type_params, intr)
 }
 
-fn path_to_str(&&p: @ast::path) -> ~str {
-    return to_str(p, |a,b| print_path(a, b, false));
+fn path_to_str(&&p: @ast::path, intr: ident_interner) -> ~str {
+    to_str(p, |a,b| print_path(a, b, false), intr)
 }
 
 fn fun_to_str(decl: ast::fn_decl, name: ast::ident,
-              params: ~[ast::ty_param]) -> ~str {
+              params: ~[ast::ty_param], intr: ident_interner) -> ~str {
     let buffer = io::mem_buffer();
-    let s = rust_printer(io::mem_buffer_writer(buffer));
+    let s = rust_printer(io::mem_buffer_writer(buffer), intr);
     print_fn(s, decl, name, params, none);
     end(s); // Close the head box
     end(s); // Close the outer box
@@ -162,9 +153,9 @@ fn test_fun_to_str() {
     assert fun_to_str(decl, "a", ~[]) == "fn a()";
 }
 
-fn block_to_str(blk: ast::blk) -> ~str {
+fn block_to_str(blk: ast::blk, intr: ident_interner) -> ~str {
     let buffer = io::mem_buffer();
-    let s = rust_printer(io::mem_buffer_writer(buffer));
+    let s = rust_printer(io::mem_buffer_writer(buffer), intr);
     // containing cbox, will be closed by print-block at }
     cbox(s, indent_unit);
     // head-ibox, will be closed by print-block after {
@@ -174,16 +165,16 @@ fn block_to_str(blk: ast::blk) -> ~str {
     io::mem_buffer_str(buffer)
 }
 
-fn meta_item_to_str(mi: ast::meta_item) -> ~str {
-    return to_str(@mi, print_meta_item);
+fn meta_item_to_str(mi: ast::meta_item, intr: ident_interner) -> ~str {
+    to_str(@mi, print_meta_item, intr)
 }
 
-fn attribute_to_str(attr: ast::attribute) -> ~str {
-    return to_str(attr, print_attribute);
+fn attribute_to_str(attr: ast::attribute, intr: ident_interner) -> ~str {
+    to_str(attr, print_attribute, intr)
 }
 
-fn variant_to_str(var: ast::variant) -> ~str {
-    return to_str(var, print_variant);
+fn variant_to_str(var: ast::variant, intr: ident_interner) -> ~str {
+    to_str(var, print_variant, intr)
 }
 
 #[test]
@@ -349,7 +340,7 @@ fn print_region(s: ps, region: @ast::region) {
       ast::re_anon => word_space(s, ~"&"),
       ast::re_named(name) => {
         word(s.s, ~"&");
-        word(s.s, *name);
+        print_ident(s, name);
       }
     }
 }
@@ -389,7 +380,7 @@ fn print_type_ex(s: ps, &&ty: @ast::ty, print_colons: bool) {
         fn print_field(s: ps, f: ast::ty_field) {
             cbox(s, indent_unit);
             print_mutability(s, f.node.mt.mutbl);
-            word(s.s, *f.node.ident);
+            print_ident(s, f.node.ident);
             word_space(s, ~":");
             print_type(s, f.node.mt.ty);
             end(s);
@@ -446,7 +437,8 @@ fn print_item(s: ps, &&item: @ast::item) {
     match item.node {
       ast::item_const(ty, expr) => {
         head(s, ~"const");
-        word_space(s, *item.ident + ~":");
+        print_ident(s, item.ident);
+        word_space(s, ~":");
         print_type(s, ty);
         space(s.s);
         end(s); // end the head-ibox
@@ -464,7 +456,8 @@ fn print_item(s: ps, &&item: @ast::item) {
       }
       ast::item_mod(_mod) => {
         head(s, ~"mod");
-        word_nbsp(s, *item.ident);
+        print_ident(s, item.ident);
+        nbsp(s);
         bopen(s);
         print_mod(s, _mod, item.attrs);
         bclose(s, item.span);
@@ -472,7 +465,8 @@ fn print_item(s: ps, &&item: @ast::item) {
       ast::item_foreign_mod(nmod) => {
         head(s, ~"extern");
         word_nbsp(s, ~"mod");
-        word_nbsp(s, *item.ident);
+        print_ident(s, item.ident);
+        nbsp(s);
         bopen(s);
         print_foreign_mod(s, nmod, item.attrs);
         bclose(s, item.span);
@@ -481,7 +475,7 @@ fn print_item(s: ps, &&item: @ast::item) {
         ibox(s, indent_unit);
         ibox(s, 0u);
         word_nbsp(s, ~"type");
-        word(s.s, *item.ident);
+        print_ident(s, item.ident);
         print_type_params(s, params);
         end(s); // end the inner ibox
 
@@ -498,6 +492,7 @@ fn print_item(s: ps, &&item: @ast::item) {
           head(s, ~"struct");
           print_struct(s, struct_def, tps, item.ident, item.span);
       }
+
       ast::item_impl(tps, traits, ty, methods) => {
         head(s, ~"impl");
         if tps.is_not_empty() {
@@ -522,7 +517,7 @@ fn print_item(s: ps, &&item: @ast::item) {
       }
       ast::item_trait(tps, traits, methods) => {
         head(s, ~"trait");
-        word(s.s, *item.ident);
+        print_ident(s, item.ident);
         print_type_params(s, tps);
         if vec::len(traits) != 0u {
             word_space(s, ~":");
@@ -535,7 +530,9 @@ fn print_item(s: ps, &&item: @ast::item) {
         bclose(s, item.span);
       }
       ast::item_mac({node: ast::mac_invoc_tt(pth, tts), _}) => {
-        head(s, path_to_str(pth) + ~"! " + *item.ident);
+        print_path(s, pth, false);
+        head(s, ~"! ");
+        print_ident(s, item.ident);
         bopen(s);
         for tts.each |tt| { print_tt(s, tt);  }
         bclose(s, item.span);
@@ -552,7 +549,7 @@ fn print_enum_def(s: ps, enum_definition: ast::enum_def,
                   span: ast::span) {
     let mut newtype =
         vec::len(enum_definition.variants) == 1u &&
-            str::eq(ident, enum_definition.variants[0].node.name);
+        ident == enum_definition.variants[0].node.name;
     if newtype {
         match enum_definition.variants[0].node.kind {
             ast::tuple_variant_kind(args) if args.len() == 1 => {}
@@ -566,7 +563,7 @@ fn print_enum_def(s: ps, enum_definition: ast::enum_def,
         head(s, ~"enum");
     }
 
-    word(s.s, *ident);
+    print_ident(s, ident);
     print_type_params(s, params);
     space(s.s);
     if newtype {
@@ -599,7 +596,8 @@ fn print_variants(s: ps, variants: ~[ast::variant], span: ast::span) {
 
 fn print_struct(s: ps, struct_def: @ast::struct_def, tps: ~[ast::ty_param],
                 ident: ast::ident, span: ast::span) {
-    word_nbsp(s, *ident);
+    print_ident(s, ident);
+    nbsp(s);
     print_type_params(s, tps);
     if vec::len(struct_def.traits) != 0u {
         word_space(s, ~":");
@@ -639,7 +637,7 @@ fn print_struct(s: ps, struct_def: @ast::struct_def, tps: ~[ast::ty_param],
                 if mutability == ast::class_mutable {
                     word_nbsp(s, ~"mut");
                 }
-                word(s.s, *ident);
+                print_ident(s, ident);
                 word_nbsp(s, ~":");
                 print_type(s, field.node.ty);
                 word(s.s, ~";");
@@ -684,7 +682,8 @@ fn print_tt(s: ps, tt: ast::token_tree) {
         s.s.token_tree_last_was_ident = false;
       }
       ast::tt_nonterminal(_, name) => {
-        word(s.s, ~"$" + *name);
+        word(s.s, ~"$");
+        print_ident(s, name);
         s.s.token_tree_last_was_ident = true;
       }
     }
@@ -693,7 +692,7 @@ fn print_tt(s: ps, tt: ast::token_tree) {
 fn print_variant(s: ps, v: ast::variant) {
     match v.node.kind {
         ast::tuple_variant_kind(args) => {
-            word(s.s, *v.node.name);
+            print_ident(s, v.node.name);
             if vec::len(args) > 0u {
                 popen(s);
                 fn print_variant_arg(s: ps, arg: ast::variant_arg) {
@@ -780,7 +779,7 @@ fn print_attribute(s: ps, attr: ast::attribute) {
     if attr.node.is_sugared_doc {
         let meta = attr::attr_meta(attr);
         let comment = attr::get_meta_item_value_str(meta).get();
-        word(s.s, *comment);
+        word(s.s, comment);
     } else {
         word(s.s, ~"#[");
         print_meta_item(s, @attr.node.value);
@@ -935,7 +934,8 @@ fn print_mac(s: ps, m: ast::mac) {
         // FIXME: extension 'body' (#2339)
       }
       ast::mac_invoc_tt(pth, tts) => {
-        head(s, path_to_str(pth) + ~"!");
+        print_path(s, pth, false);
+        head(s, ~"!");
         bopen(s);
         for tts.each() |tt| { print_tt(s, tt); }
         bclose(s, m.span);
@@ -956,7 +956,7 @@ fn print_vstore(s: ps, t: ast::vstore) {
         ast::re_anon => word(s.s, ~"&"),
         ast::re_named(name) => {
             word(s.s, ~"&");
-            word(s.s, *name);
+            print_ident(s, name);
             word(s.s, ~".");
         }
       }
@@ -967,7 +967,7 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
     fn print_field(s: ps, field: ast::field) {
         ibox(s, indent_unit);
         if field.node.mutbl == ast::m_mutbl { word_nbsp(s, ~"mut"); }
-        word(s.s, *field.node.ident);
+        print_ident(s, field.node.ident);
         word_space(s, ~":");
         print_expr(s, field.node.expr);
         end(s);
@@ -1125,7 +1125,7 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
       ast::expr_loop(blk, opt_ident) => {
         head(s, ~"loop");
         space(s.s);
-        option::iter(opt_ident, |ident| word_space(s, *ident));
+        option::iter(opt_ident, |ident| {print_ident(s, ident); space(s.s)});
         print_block(s, blk);
       }
       ast::expr_match(expr, arms, mode) => {
@@ -1270,7 +1270,7 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
             print_expr_parens_if_not_bot(s, expr);
         }
         word(s.s, ~".");
-        word(s.s, *id);
+        print_ident(s, id);
         if vec::len(tys) > 0u {
             word(s.s, ~"::<");
             commasep(s, inconsistent, tys, print_type);
@@ -1294,12 +1294,12 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
       ast::expr_break(opt_ident) => {
         word(s.s, ~"break");
         space(s.s);
-        option::iter(opt_ident, |ident| word_space(s, *ident));
+        option::iter(opt_ident, |ident| {print_ident(s, ident); space(s.s)});
       }
       ast::expr_again(opt_ident) => {
         word(s.s, ~"again");
         space(s.s);
-        option::iter(opt_ident, |ident| word_space(s, *ident));
+        option::iter(opt_ident, |ident| {print_ident(s, ident); space(s.s)});
       }
       ast::expr_ret(result) => {
         word(s.s, ~"return");
@@ -1395,7 +1395,7 @@ fn print_decl(s: ps, decl: @ast::decl) {
     }
 }
 
-fn print_ident(s: ps, ident: ast::ident) { word(s.s, *ident); }
+fn print_ident(s: ps, ident: ast::ident) { word(s.s, *s.intr.get(ident)); }
 
 fn print_for_decl(s: ps, loc: @ast::local, coll: @ast::expr) {
     print_local_decl(s, loc);
@@ -1410,7 +1410,7 @@ fn print_path(s: ps, &&path: @ast::path, colons_before_params: bool) {
     let mut first = true;
     for path.idents.each |id| {
         if first { first = false; } else { word(s.s, ~"::"); }
-        word(s.s, *id);
+        print_ident(s, id);
     }
     if path.rp.is_some() || !path.types.is_empty() {
         if colons_before_params { word(s.s, ~"::"); }
@@ -1471,7 +1471,7 @@ fn print_pat(s: ps, &&pat: @ast::pat) {
         word(s.s, ~"{");
         fn print_field(s: ps, f: ast::field_pat) {
             cbox(s, indent_unit);
-            word(s.s, *f.ident);
+            print_ident(s, f.ident);
             word_space(s, ~":");
             print_pat(s, f.pat);
             end(s);
@@ -1489,7 +1489,7 @@ fn print_pat(s: ps, &&pat: @ast::pat) {
         word(s.s, ~"{");
         fn print_field(s: ps, f: ast::field_pat) {
             cbox(s, indent_unit);
-            word(s.s, *f.ident);
+            print_ident(s, f.ident);
             word_space(s, ~":");
             print_pat(s, f.pat);
             end(s);
@@ -1542,7 +1542,7 @@ fn print_fn(s: ps, decl: ast::fn_decl, name: ast::ident,
             typarams: ~[ast::ty_param],
             opt_self_ty: option<ast::self_ty_>) {
     head(s, fn_header_info_to_str(opt_self_ty, decl.purity, none));
-    word(s.s, *name);
+    print_ident(s, name);
     print_type_params(s, typarams);
     print_fn_args_and_ret(s, decl, ~[], opt_self_ty);
 }
@@ -1568,7 +1568,7 @@ fn print_fn_args(s: ps, decl: ast::fn_decl,
         if first { first = false; } else { word_space(s, ~","); }
         if cap_item.is_move { word_nbsp(s, ~"move") }
         else { word_nbsp(s, ~"copy") }
-        word(s.s, *cap_item.name);
+        print_ident(s, cap_item.name);
     }
 
     end(s);
@@ -1638,7 +1638,7 @@ fn print_type_params(s: ps, &&params: ~[ast::ty_param]) {
     if vec::len(params) > 0u {
         word(s.s, ~"<");
         fn printParam(s: ps, param: ast::ty_param) {
-            word(s.s, *param.ident);
+            print_ident(s, param.ident);
             print_bounds(s, param.bounds);
         }
         commasep(s, inconsistent, params, printParam);
@@ -1649,14 +1649,14 @@ fn print_type_params(s: ps, &&params: ~[ast::ty_param]) {
 fn print_meta_item(s: ps, &&item: @ast::meta_item) {
     ibox(s, indent_unit);
     match item.node {
-      ast::meta_word(name) => word(s.s, *name),
+      ast::meta_word(name) => word(s.s, name),
       ast::meta_name_value(name, value) => {
-        word_space(s, *name);
+        word_space(s, name);
         word_space(s, ~"=");
         print_literal(s, @value);
       }
       ast::meta_list(name, items) => {
-        word(s.s, *name);
+        word(s.s, name);
         popen(s);
         commasep(s, consistent, items, print_meta_item);
         pclose(s);
@@ -1669,7 +1669,8 @@ fn print_view_path(s: ps, &&vp: @ast::view_path) {
     match vp.node {
       ast::view_path_simple(ident, path, _) => {
         if path.idents[vec::len(path.idents)-1u] != ident {
-            word_space(s, *ident);
+            print_ident(s, ident);
+            space(s.s);
             word_space(s, ~"=");
         }
         print_path(s, path, false);
@@ -1684,7 +1685,7 @@ fn print_view_path(s: ps, &&vp: @ast::view_path) {
         print_path(s, path, false);
         word(s.s, ~"::{");
         do commasep(s, inconsistent, idents) |s, w| {
-            word(s.s, *w.node.name)
+            print_ident(s, w.node.name);
         }
         word(s.s, ~"}");
       }
@@ -1702,7 +1703,7 @@ fn print_view_item(s: ps, item: @ast::view_item) {
     match item.node {
       ast::view_item_use(id, mta, _) => {
         head(s, ~"use");
-        word(s.s, *id);
+        print_ident(s, id);
         if vec::len(mta) > 0u {
             popen(s);
             commasep(s, consistent, mta, print_meta_item);
@@ -1749,10 +1750,12 @@ fn print_arg(s: ps, input: ast::arg) {
     ibox(s, indent_unit);
     print_arg_mode(s, input.mode);
     match input.ty.node {
-      ast::ty_infer => word(s.s, *input.ident),
+      ast::ty_infer => print_ident(s, input.ident),
       _ => {
-        if str::len(*input.ident) > 0u {
-            word_space(s, *input.ident + ~":");
+        if input.ident != parse::token::special_idents::invalid {
+            print_ident(s, input.ident);
+            word(s.s, ~":");
+            space(s.s);
         }
         print_type(s, input.ty);
       }
@@ -1768,7 +1771,7 @@ fn print_ty_fn(s: ps, opt_proto: option<ast::proto>,
     ibox(s, indent_unit);
     word(s.s, fn_header_info_to_str(opt_self_ty, decl.purity, opt_proto));
     print_bounds(s, bounds);
-    match id { some(id) => { word(s.s, ~" "); word(s.s, *id); } _ => () }
+    match id { some(id) => { word(s.s, ~" "); print_ident(s, id); } _ => () }
     match tps { some(tps) => print_type_params(s, tps), _ => () }
     zerobreak(s.s);
 
@@ -1880,7 +1883,9 @@ fn print_literal(s: ps, &&lit: @ast::lit) {
     }
 }
 
-fn lit_to_str(l: @ast::lit) -> ~str { return to_str(l, print_literal); }
+fn lit_to_str(l: @ast::lit) -> ~str {
+    return to_str(l, print_literal, parse::token::mk_fake_ident_interner());
+}
 
 fn next_lit(s: ps, pos: uint) -> option<comments::lit> {
     match s.literals {
@@ -1961,9 +1966,9 @@ fn print_string(s: ps, st: ~str) {
     word(s.s, ~"\"");
 }
 
-fn to_str<T>(t: T, f: fn@(ps, T)) -> ~str {
+fn to_str<T>(t: T, f: fn@(ps, T), intr: ident_interner) -> ~str {
     let buffer = io::mem_buffer();
-    let s = rust_printer(io::mem_buffer_writer(buffer));
+    let s = rust_printer(io::mem_buffer_writer(buffer), intr);
     f(s, t);
     eof(s.s);
     io::mem_buffer_str(buffer)
diff --git a/src/libsyntax/util/interner.rs b/src/libsyntax/util/interner.rs
index 19b27be83e2..5cecd315ac4 100644
--- a/src/libsyntax/util/interner.rs
+++ b/src/libsyntax/util/interner.rs
@@ -21,7 +21,7 @@ fn mk<T: const copy>(+hasher: hashfn<T>, +eqer: eqfn<T>) -> interner<T> {
 fn mk_prefill<T: const copy>(hasher: hashfn<T>, eqer: eqfn<T>,
                              init: ~[T]) -> interner<T> {
 
-    let rv = mk(hasher, eqer);
+    let rv = mk(copy hasher, copy eqer);
     for init.each() |v| { rv.intern(v); }
     return rv;
 }
@@ -30,6 +30,7 @@ fn mk_prefill<T: const copy>(hasher: hashfn<T>, eqer: eqfn<T>,
 /* when traits can extend traits, we should extend index<uint,T> to get [] */
 trait interner<T: const copy> {
     fn intern(T) -> uint;
+    fn gensym(T) -> uint;
     pure fn get(uint) -> T;
     fn len() -> uint;
 }
@@ -46,6 +47,12 @@ impl <T: const copy> hash_interner<T>: interner<T> {
           }
         }
     }
+    fn gensym(val: T) -> uint {
+        let new_idx = self.vect.len();
+        // leave out of .map to avoid colliding
+        self.vect.push(val);
+        return new_idx;
+    }
 
     // this isn't "pure" in the traditional sense, because it can go from
     // failing to returning a value as items are interned. But for typestate,
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index f9d861f15e1..51104e97119 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -27,9 +27,9 @@ enum fn_kind {
 fn name_of_fn(fk: fn_kind) -> ident {
     match fk {
       fk_item_fn(name, _) | fk_method(name, _, _)
-          | fk_ctor(name, _, _, _, _) => /* FIXME (#2543) */ copy name,
-      fk_anon(*) | fk_fn_block(*) => @~"anon",
-      fk_dtor(*)                  => @~"drop"
+          | fk_ctor(name, _, _, _, _) =>  /* FIXME (#2543) */ copy name,
+      fk_anon(*) | fk_fn_block(*) => parse::token::special_idents::anon,
+      fk_dtor(*)                  => parse::token::special_idents::dtor
     }
 }