diff options
| author | Patrick Walton <pcwalton@mimiga.net> | 2014-01-08 10:35:15 -0800 |
|---|---|---|
| committer | Huon Wilson <dbau.pp+github@gmail.com> | 2014-02-02 01:44:47 +1100 |
| commit | 70c5a0fbf784d6a89b1c2c50f9fe83093bd21abc (patch) | |
| tree | c0d73d05918545051a9e1d10f5496ee588df3693 | |
| parent | 1d494198bbb9701b6336febcf9d0ceb39e4b7975 (diff) | |
| download | rust-70c5a0fbf784d6a89b1c2c50f9fe83093bd21abc.tar.gz rust-70c5a0fbf784d6a89b1c2c50f9fe83093bd21abc.zip | |
libsyntax: Introduce an `InternedString` type to reduce `@str` in the
compiler and use it for attributes
27 files changed, 336 insertions, 154 deletions
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 211d60f7e2d..2b552aff717 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -44,6 +44,7 @@ use syntax::codemap; use syntax::diagnostic; use syntax::ext::base::CrateLoader; use syntax::parse; +use syntax::parse::token::InternedString; use syntax::parse::token; use syntax::print::{pp, pprust}; use syntax; @@ -90,22 +91,23 @@ pub fn default_configuration(sess: Session) -> }; let fam = match sess.targ_cfg.os { - abi::OsWin32 => @"windows", - _ => @"unix" + abi::OsWin32 => InternedString::new("windows"), + _ => InternedString::new("unix") }; let mk = attr::mk_name_value_item_str; return ~[ // Target bindings. - attr::mk_word_item(fam), - mk(@"target_os", tos), - mk(@"target_family", fam), - mk(@"target_arch", arch), - mk(@"target_endian", end), - mk(@"target_word_size", wordsz), + attr::mk_word_item(fam.clone()), + mk(InternedString::new("target_os"), tos), + mk(InternedString::new("target_family"), fam.get().to_managed()), + mk(InternedString::new("target_arch"), arch), + mk(InternedString::new("target_endian"), end), + mk(InternedString::new("target_word_size"), wordsz), ]; } -pub fn append_configuration(cfg: &mut ast::CrateConfig, name: @str) { +pub fn append_configuration(cfg: &mut ast::CrateConfig, + name: InternedString) { if !cfg.iter().any(|mi| mi.name() == name) { cfg.push(attr::mk_word_item(name)) } @@ -118,9 +120,15 @@ pub fn build_configuration(sess: Session) -> let default_cfg = default_configuration(sess); let mut user_cfg = sess.opts.cfg.clone(); // If the user wants a test runner, then add the test cfg - if sess.opts.test { append_configuration(&mut user_cfg, @"test") } + if sess.opts.test { + append_configuration(&mut user_cfg, InternedString::new("test")) + } // If the user requested GC, then add the GC cfg - append_configuration(&mut user_cfg, if sess.opts.gc { @"gc" } else { @"nogc" }); + append_configuration(&mut user_cfg, if sess.opts.gc { + InternedString::new("gc") + } else { + InternedString::new("nogc") + }); return vec::append(user_cfg, default_cfg); } diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index 5cda81836a4..57bc9c32cbd 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -435,7 +435,7 @@ pub fn collect_outputs(session: &Session, } let mut base = session.opts.outputs.clone(); let mut iter = attrs.iter().filter_map(|a| { - if "crate_type" == a.name() { + if a.name().equiv(&("crate_type")) { match a.value_str() { Some(n) if "rlib" == n => Some(OutputRlib), Some(n) if "dylib" == n => Some(OutputDylib), diff --git a/src/librustc/front/feature_gate.rs b/src/librustc/front/feature_gate.rs index bfb27594108..7903ce00dc3 100644 --- a/src/librustc/front/feature_gate.rs +++ b/src/librustc/front/feature_gate.rs @@ -135,7 +135,7 @@ impl Visitor<()> for Context { fn visit_item(&mut self, i: &ast::Item, _:()) { for attr in i.attrs.iter() { - if "thread_local" == attr.name() { + if attr.name().equiv(&("thread_local")) { self.gate_feature("thread_local", i.span, "`#[thread_local]` is an experimental feature, and does not \ currently handle destructors. There is no corresponding \ @@ -258,7 +258,9 @@ pub fn check_crate(sess: Session, crate: &ast::Crate) { }; for attr in crate.attrs.iter() { - if "feature" != attr.name() { continue } + if !attr.name().equiv(&("feature")) { + continue + } match attr.meta_item_list() { None => { @@ -268,14 +270,16 @@ pub fn check_crate(sess: Session, crate: &ast::Crate) { Some(list) => { for &mi in list.iter() { let name = match mi.node { - ast::MetaWord(word) => word, + ast::MetaWord(ref word) => (*word).clone(), _ => { - sess.span_err(mi.span, "malformed feature, expected \ - just one word"); + sess.span_err(mi.span, + "malformed feature, expected just \ + one word"); continue } }; - match KNOWN_FEATURES.iter().find(|& &(n, _)| n == name) { + match KNOWN_FEATURES.iter() + .find(|& &(n, _)| name.equiv(&n)) { Some(&(name, Active)) => { cx.features.push(name); } Some(&(_, Removed)) => { sess.span_err(mi.span, "feature has been removed"); diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index 0714c1c620b..b32568abeb1 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -27,6 +27,7 @@ use syntax::ext::base::ExtCtxt; use syntax::fold::Folder; use syntax::fold; use syntax::opt_vec; +use syntax::parse::token::InternedString; use syntax::print::pprust; use syntax::{ast, ast_util}; use syntax::util::small_vector::SmallVector; @@ -132,7 +133,7 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { if !cx.sess.building_library.get() { @ast::Item { attrs: item.attrs.iter().filter_map(|attr| { - if "main" != attr.name() { + if attr.name().equiv(&("main")) { Some(*attr) } else { None @@ -248,7 +249,7 @@ fn is_bench_fn(i: @ast::Item) -> bool { fn is_ignored(cx: &TestCtxt, i: @ast::Item) -> bool { i.attrs.iter().any(|attr| { // check ignore(cfg(foo, bar)) - "ignore" == attr.name() && match attr.meta_item_list() { + attr.name().equiv(&("ignore")) && match attr.meta_item_list() { Some(ref cfgs) => attr::test_cfg(cx.config, cfgs.iter().map(|x| *x)), None => true } @@ -330,8 +331,9 @@ fn mk_test_module(cx: &TestCtxt) -> @ast::Item { let item_ = ast::ItemMod(testmod); // This attribute tells resolve to let us call unexported functions + let resolve_unexported_str = InternedString::new("!resolve_unexported"); let resolve_unexported_attr = - attr::mk_attr(attr::mk_word_item(@"!resolve_unexported")); + attr::mk_attr(attr::mk_word_item(resolve_unexported_str)); let item = ast::Item { ident: cx.sess.ident_of("__test"), diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index fa2e94b6f8f..4670757b5c3 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -124,7 +124,7 @@ struct Env { fn visit_crate(e: &Env, c: &ast::Crate) { let cstore = e.sess.cstore; - for a in c.attrs.iter().filter(|m| "link_args" == m.name()) { + for a in c.attrs.iter().filter(|m| m.name().equiv(&("link_args"))) { match a.value_str() { Some(ref linkarg) => { cstore.add_used_link_args(*linkarg); @@ -206,7 +206,11 @@ fn visit_item(e: &Env, i: &ast::Item) { // First, add all of the custom link_args attributes let cstore = e.sess.cstore; let link_args = i.attrs.iter() - .filter_map(|at| if "link_args" == at.name() {Some(at)} else {None}) + .filter_map(|at| if at.name().equiv(&("link_args")) { + Some(at) + } else { + None + }) .to_owned_vec(); for m in link_args.iter() { match m.value_str() { @@ -220,13 +224,17 @@ fn visit_item(e: &Env, i: &ast::Item) { // Next, process all of the #[link(..)]-style arguments let cstore = e.sess.cstore; let link_args = i.attrs.iter() - .filter_map(|at| if "link" == at.name() {Some(at)} else {None}) + .filter_map(|at| if at.name().equiv(&("link")) { + Some(at) + } else { + None + }) .to_owned_vec(); for m in link_args.iter() { match m.meta_item_list() { Some(items) => { let kind = items.iter().find(|k| { - "kind" == k.name() + k.name().equiv(&("kind")) }).and_then(|a| a.value_str()); let kind = match kind { Some(k) => { @@ -249,7 +257,7 @@ fn visit_item(e: &Env, i: &ast::Item) { None => cstore::NativeUnknown }; let n = items.iter().find(|n| { - "name" == n.name() + n.name().equiv(&("name")) }).and_then(|a| a.value_str()); let n = match n { Some(n) => n, diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 11fab9cced7..ef6bb30cb51 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -1042,14 +1042,14 @@ fn get_meta_items(md: ebml::Doc) -> ~[@ast::MetaItem] { let mut items: ~[@ast::MetaItem] = ~[]; reader::tagged_docs(md, tag_meta_item_word, |meta_item_doc| { let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); - let n = nd.as_str_slice().to_managed(); + let n = token::intern_and_get_ident(nd.as_str_slice()); items.push(attr::mk_word_item(n)); true }); reader::tagged_docs(md, tag_meta_item_name_value, |meta_item_doc| { let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); let vd = reader::get_doc(meta_item_doc, tag_meta_item_value); - let n = nd.as_str_slice().to_managed(); + let n = token::intern_and_get_ident(nd.as_str_slice()); let v = vd.as_str_slice().to_managed(); // FIXME (#623): Should be able to decode MetaNameValue variants, // but currently the encoder just drops them @@ -1058,7 +1058,7 @@ fn get_meta_items(md: ebml::Doc) -> ~[@ast::MetaItem] { }); reader::tagged_docs(md, tag_meta_item_list, |meta_item_doc| { let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); - let n = nd.as_str_slice().to_managed(); + let n = token::intern_and_get_ident(nd.as_str_slice()); let subitems = get_meta_items(meta_item_doc); items.push(attr::mk_list_item(n, subitems)); true diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index ac3ee78fb86..94a4639975c 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -21,29 +21,28 @@ use middle::ty; use middle::typeck; use middle; +use extra::serialize::Encodable; use std::cast; use std::cell::{Cell, RefCell}; use std::hashmap::{HashMap, HashSet}; use std::io::MemWriter; use std::str; use std::vec; - -use extra::serialize::Encodable; - use syntax::abi::AbiSet; use syntax::ast::*; use syntax::ast; use syntax::ast_map; use syntax::ast_util::*; -use syntax::attr; +use syntax::ast_util; use syntax::attr::AttrMetaMethods; +use syntax::attr; use syntax::codemap; use syntax::diagnostic::SpanHandler; +use syntax::parse::token::InternedString; use syntax::parse::token::special_idents; -use syntax::ast_util; +use syntax::parse::token; use syntax::visit::Visitor; use syntax::visit; -use syntax::parse::token; use syntax; use writer = extra::ebml::writer; @@ -1507,19 +1506,19 @@ fn write_i64(writer: &mut MemWriter, &n: &i64) { fn encode_meta_item(ebml_w: &mut writer::Encoder, mi: @MetaItem) { match mi.node { - MetaWord(name) => { + MetaWord(ref name) => { ebml_w.start_tag(tag_meta_item_word); ebml_w.start_tag(tag_meta_item_name); - ebml_w.writer.write(name.as_bytes()); + ebml_w.writer.write(name.get().as_bytes()); ebml_w.end_tag(); ebml_w.end_tag(); } - MetaNameValue(name, value) => { + MetaNameValue(ref name, value) => { match value.node { LitStr(value, _) => { ebml_w.start_tag(tag_meta_item_name_value); ebml_w.start_tag(tag_meta_item_name); - ebml_w.writer.write(name.as_bytes()); + ebml_w.writer.write(name.get().as_bytes()); ebml_w.end_tag(); ebml_w.start_tag(tag_meta_item_value); ebml_w.writer.write(value.as_bytes()); @@ -1529,10 +1528,10 @@ fn encode_meta_item(ebml_w: &mut writer::Encoder, mi: @MetaItem) { _ => {/* FIXME (#623): encode other variants */ } } } - MetaList(name, ref items) => { + MetaList(ref name, ref items) => { ebml_w.start_tag(tag_meta_item_list); ebml_w.start_tag(tag_meta_item_name); - ebml_w.writer.write(name.as_bytes()); + ebml_w.writer.write(name.get().as_bytes()); ebml_w.end_tag(); for inner_item in items.iter() { encode_meta_item(ebml_w, *inner_item); @@ -1563,13 +1562,13 @@ fn synthesize_crate_attrs(ecx: &EncodeContext, attr::mk_attr( attr::mk_name_value_item_str( - @"crate_id", + InternedString::new("crate_id"), ecx.link_meta.crateid.to_str().to_managed())) } let mut attrs = ~[]; for attr in crate.attrs.iter() { - if "crate_id" != attr.name() { + if !attr.name().equiv(&("crate_id")) { attrs.push(*attr); } } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 82c927a1c2d..34f8bad9666 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -185,7 +185,7 @@ impl LanguageItemCollector { pub fn extract(attrs: &[ast::Attribute]) -> Option<@str> { for attribute in attrs.iter() { match attribute.name_str_pair() { - Some((key, value)) if "lang" == key => { + Some((ref key, value)) if key.equiv(&("lang")) => { return Some(value); } Some(..) | None => {} diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index 7cb549d91a8..3dfa186e4a9 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -34,18 +34,17 @@ //! Context itself, span_lint should be used instead of add_lint. use driver::session; +use metadata::csearch; use middle::dead::DEAD_CODE_LINT_STR; +use middle::pat_util; use middle::privacy; use middle::trans::adt; // for `adt::is_ffi_safe` use middle::ty; +use middle::typeck::astconv::{ast_ty_to_ty, AstConv}; +use middle::typeck::infer; use middle::typeck; -use middle::pat_util; -use metadata::csearch; -use util::ppaux::{ty_to_str}; use std::to_str::ToStr; - -use middle::typeck::infer; -use middle::typeck::astconv::{ast_ty_to_ty, AstConv}; +use util::ppaux::{ty_to_str}; use std::cmp; use std::hashmap::HashMap; @@ -59,13 +58,14 @@ use std::u64; use std::u8; use extra::smallintmap::SmallIntMap; use syntax::ast_map; -use syntax::attr; +use syntax::ast_util::IdVisitingOperation; use syntax::attr::{AttrMetaMethods, AttributeMethods}; +use syntax::attr; use syntax::codemap::Span; +use syntax::parse::token::InternedString; use syntax::parse::token; -use syntax::{ast, ast_util, visit}; -use syntax::ast_util::IdVisitingOperation; use syntax::visit::Visitor; +use syntax::{ast, ast_util, visit}; #[deriving(Clone, Eq, Ord, TotalEq, TotalOrd)] pub enum Lint { @@ -540,10 +540,16 @@ impl<'a> Context<'a> { }); let old_is_doc_hidden = self.is_doc_hidden; - self.is_doc_hidden = self.is_doc_hidden || - attrs.iter().any(|attr| ("doc" == attr.name() && match attr.meta_item_list() - { None => false, - Some(l) => attr::contains_name(l, "hidden") })); + self.is_doc_hidden = + self.is_doc_hidden || + attrs.iter() + .any(|attr| { + attr.name().equiv(&("doc")) && + match attr.meta_item_list() { + None => false, + Some(l) => attr::contains_name(l, "hidden") + } + }); f(self); @@ -569,12 +575,12 @@ impl<'a> Context<'a> { // Return true if that's the case. Otherwise return false. pub fn each_lint(sess: session::Session, attrs: &[ast::Attribute], - f: |@ast::MetaItem, level, @str| -> bool) + f: |@ast::MetaItem, level, InternedString| -> bool) -> bool { let xs = [allow, warn, deny, forbid]; for &level in xs.iter() { let level_name = level_to_str(level); - for attr in attrs.iter().filter(|m| level_name == m.name()) { + for attr in attrs.iter().filter(|m| m.name().equiv(&level_name)) { let meta = attr.node.value; let metas = match meta.node { ast::MetaList(_, ref metas) => metas, @@ -585,8 +591,8 @@ pub fn each_lint(sess: session::Session, }; for meta in metas.iter() { match meta.node { - ast::MetaWord(lintname) => { - if !f(*meta, level, lintname) { + ast::MetaWord(ref lintname) => { + if !f(*meta, level, (*lintname).clone()) { return false; } } @@ -1314,7 +1320,7 @@ fn check_missing_doc_attrs(cx: &Context, let has_doc = attrs.iter().any(|a| { match a.node.value.node { - ast::MetaNameValue(ref name, _) if "doc" == *name => true, + ast::MetaNameValue(ref name, _) if name.equiv(&("doc")) => true, _ => false } }); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 9062949b000..ba9dea28cbc 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4165,7 +4165,7 @@ pub fn each_attr(tcx: ctxt, did: DefId, f: |@MetaItem| -> bool) -> bool { pub fn has_attr(tcx: ctxt, did: DefId, attr: &str) -> bool { let mut found = false; each_attr(tcx, did, |item| { - if attr == item.name() { + if item.name().equiv(&attr) { found = true; false } else { diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index e86122fb7d1..564fb465c02 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -20,6 +20,8 @@ use syntax::ast_util; use syntax::attr; use syntax::attr::AttributeMethods; use syntax::codemap::Pos; +use syntax::parse::token::InternedString; +use syntax::parse::token; use rustc::metadata::cstore; use rustc::metadata::csearch; @@ -223,9 +225,13 @@ pub enum Attribute { impl Clean<Attribute> for ast::MetaItem { fn clean(&self) -> Attribute { match self.node { - ast::MetaWord(s) => Word(s.to_owned()), - ast::MetaList(ref s, ref l) => List(s.to_owned(), l.clean()), - ast::MetaNameValue(s, ref v) => NameValue(s.to_owned(), lit_to_str(v)) + ast::MetaWord(ref s) => Word(s.get().to_owned()), + ast::MetaList(ref s, ref l) => { + List(s.get().to_owned(), l.clean()) + } + ast::MetaNameValue(ref s, ref v) => { + NameValue(s.get().to_owned(), lit_to_str(v)) + } } } } @@ -238,10 +244,11 @@ impl Clean<Attribute> for ast::Attribute { // This is a rough approximation that gets us what we want. impl<'a> attr::AttrMetaMethods for &'a Attribute { - fn name(&self) -> @str { + fn name(&self) -> InternedString { match **self { - Word(ref n) | List(ref n, _) | NameValue(ref n, _) => - n.to_managed() + Word(ref n) | List(ref n, _) | NameValue(ref n, _) => { + token::intern_and_get_ident(*n) + } } } @@ -252,7 +259,7 @@ impl<'a> attr::AttrMetaMethods for &'a Attribute { } } fn meta_item_list<'a>(&'a self) -> Option<&'a [@ast::MetaItem]> { None } - fn name_str_pair(&self) -> Option<(@str, @str)> { None } + fn name_str_pair(&self) -> Option<(InternedString, @str)> { None } } #[deriving(Clone, Encodable, Decodable)] diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index e4260e367a8..0e2d6c972ae 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -15,6 +15,7 @@ use rustc::middle::privacy; use syntax::ast; use syntax::diagnostic; +use syntax::parse::token; use syntax::parse; use syntax; @@ -71,7 +72,8 @@ fn get_ast_and_resolve(cpath: &Path, let mut cfg = build_configuration(sess); for cfg_ in cfgs.move_iter() { - cfg.push(@dummy_spanned(ast::MetaWord(cfg_.to_managed()))); + let cfg_ = token::intern_and_get_ident(cfg_); + cfg.push(@dummy_spanned(ast::MetaWord(cfg_))); } let crate = phase_1_parse_input(sess, cfg.clone(), &input); diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index 1f8962fbd3a..3f1762009bc 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -30,6 +30,7 @@ use syntax::ext::base::{ExtCtxt, MacroCrate}; use syntax::{ast, attr, codemap, diagnostic, fold, visit}; use syntax::attr::AttrMetaMethods; use syntax::fold::Folder; +use syntax::parse::token::InternedString; use syntax::visit::Visitor; use syntax::util::small_vector::SmallVector; use syntax::crateid::CrateId; @@ -77,7 +78,7 @@ fn fold_mod(m: &ast::Mod, fold: &mut CrateSetup) -> ast::Mod { fn strip_main(item: @ast::Item) -> @ast::Item { @ast::Item { attrs: item.attrs.iter().filter_map(|attr| { - if "main" != attr.name() { + if !attr.name().equiv(&("main")) { Some(*attr) } else { None @@ -101,13 +102,15 @@ fn fold_item(item: @ast::Item, fold: &mut CrateSetup) let mut had_pkg_do = false; for attr in item.attrs.iter() { - if "pkg_do" == attr.name() { + if attr.name().equiv(&("pkg_do")) { had_pkg_do = true; match attr.node.value.node { ast::MetaList(_, ref mis) => { for mi in mis.iter() { match mi.node { - ast::MetaWord(cmd) => cmds.push(cmd.to_owned()), + ast::MetaWord(ref cmd) => { + cmds.push(cmd.get().to_owned()) + } _ => {} }; } @@ -314,7 +317,8 @@ pub fn compile_input(context: &BuildContext, if !attr::contains_name(crate.attrs, "crate_id") { // FIXME (#9639): This needs to handle non-utf8 paths let crateid_attr = - attr::mk_name_value_item_str(@"crate_id", crate_id.to_str().to_managed()); + attr::mk_name_value_item_str(InternedString::new("crate_id"), + crate_id.to_str().to_managed()); debug!("crateid attr: {:?}", crateid_attr); crate.attrs.push(attr::mk_attr(crateid_attr)); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 1513946e401..f7e474f666c 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -14,7 +14,8 @@ use codemap::{Span, Spanned, DUMMY_SP}; use abi::AbiSet; use ast_util; use opt_vec::OptVec; -use parse::token::{interner_get, str_to_ident, special_idents}; +use parse::token::{InternedString, interner_get, special_idents}; +use parse::token::{str_to_ident}; use std::cell::RefCell; use std::hashmap::HashMap; @@ -295,9 +296,9 @@ pub type MetaItem = Spanned<MetaItem_>; #[deriving(Clone, Encodable, Decodable, IterBytes)] pub enum MetaItem_ { - MetaWord(@str), - MetaList(@str, ~[@MetaItem]), - MetaNameValue(@str, Lit), + MetaWord(InternedString), + MetaList(InternedString, ~[@MetaItem]), + MetaNameValue(InternedString, Lit), } // can't be derived because the MetaList requires an unordered comparison diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index c44861bd7d7..6c6f47bae8a 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -16,18 +16,19 @@ use codemap::{Span, Spanned, spanned, dummy_spanned}; use codemap::BytePos; use diagnostic::SpanHandler; use parse::comments::{doc_comment_style, strip_doc_comment_decoration}; +use parse::token::InternedString; use crateid::CrateId; use std::hashmap::HashSet; pub trait AttrMetaMethods { - // This could be changed to `fn check_name(&self, name: @str) -> + // This could be changed to `fn check_name(&self, name: InternedString) -> // bool` which would facilitate a side table recording which // attributes/meta items are used/unused. /// Retrieve the name of the meta item, e.g. foo in #[foo], /// #[foo="bar"] and #[foo(bar)] - fn name(&self) -> @str; + fn name(&self) -> InternedString; /** * Gets the string value if self is a MetaNameValue variant @@ -41,24 +42,26 @@ pub trait AttrMetaMethods { * If the meta item is a name-value type with a string value then returns * a tuple containing the name and string value, otherwise `None` */ - fn name_str_pair(&self) -> Option<(@str, @str)>; + fn name_str_pair(&self) -> Option<(InternedString, @str)>; } impl AttrMetaMethods for Attribute { - fn name(&self) -> @str { self.meta().name() } + fn name(&self) -> InternedString { self.meta().name() } fn value_str(&self) -> Option<@str> { self.meta().value_str() } fn meta_item_list<'a>(&'a self) -> Option<&'a [@MetaItem]> { self.node.value.meta_item_list() } - fn name_str_pair(&self) -> Option<(@str, @str)> { self.meta().name_str_pair() } + fn name_str_pair(&self) -> Option<(InternedString, @str)> { + self.meta().name_str_pair() + } } impl AttrMetaMethods for MetaItem { - fn name(&self) -> @str { + fn name(&self) -> InternedString { match self.node { - MetaWord(n) => n, - MetaNameValue(n, _) => n, - MetaList(n, _) => n + MetaWord(ref n) => (*n).clone(), + MetaNameValue(ref n, _) => (*n).clone(), + MetaList(ref n, _) => (*n).clone(), } } @@ -81,19 +84,21 @@ impl AttrMetaMethods for MetaItem { } } - fn name_str_pair(&self) -> Option<(@str, @str)> { + fn name_str_pair(&self) -> Option<(InternedString, @str)> { self.value_str().map(|s| (self.name(), s)) } } // Annoying, but required to get test_cfg to work impl AttrMetaMethods for @MetaItem { - fn name(&self) -> @str { (**self).name() } + fn name(&self) -> InternedString { (**self).name() } fn value_str(&self) -> Option<@str> { (**self).value_str() } fn meta_item_list<'a>(&'a self) -> Option<&'a [@MetaItem]> { (**self).meta_item_list() } - fn name_str_pair(&self) -> Option<(@str, @str)> { (**self).name_str_pair() } + fn name_str_pair(&self) -> Option<(InternedString, @str)> { + (**self).name_str_pair() + } } @@ -114,7 +119,7 @@ impl AttributeMethods for Attribute { fn desugar_doc(&self) -> Attribute { if self.node.is_sugared_doc { let comment = self.value_str().unwrap(); - let meta = mk_name_value_item_str(@"doc", + let meta = mk_name_value_item_str(InternedString::new("doc"), strip_doc_comment_decoration(comment).to_managed()); mk_attr(meta) } else { @@ -125,20 +130,22 @@ impl AttributeMethods for Attribute { /* Constructors */ -pub fn mk_name_value_item_str(name: @str, value: @str) -> @MetaItem { +pub fn mk_name_value_item_str(name: InternedString, value: @str) + -> @MetaItem { let value_lit = dummy_spanned(ast::LitStr(value, ast::CookedStr)); mk_name_value_item(name, value_lit) } -pub fn mk_name_value_item(name: @str, value: ast::Lit) -> @MetaItem { +pub fn mk_name_value_item(name: InternedString, value: ast::Lit) + -> @MetaItem { @dummy_spanned(MetaNameValue(name, value)) } -pub fn mk_list_item(name: @str, items: ~[@MetaItem]) -> @MetaItem { +pub fn mk_list_item(name: InternedString, items: ~[@MetaItem]) -> @MetaItem { @dummy_spanned(MetaList(name, items)) } -pub fn mk_word_item(name: @str) -> @MetaItem { +pub fn mk_word_item(name: InternedString) -> @MetaItem { @dummy_spanned(MetaWord(name)) } @@ -155,7 +162,8 @@ pub fn mk_sugared_doc_attr(text: @str, lo: BytePos, hi: BytePos) -> Attribute { let lit = spanned(lo, hi, ast::LitStr(text, ast::CookedStr)); let attr = Attribute_ { style: style, - value: @spanned(lo, hi, MetaNameValue(@"doc", lit)), + value: @spanned(lo, hi, MetaNameValue(InternedString::new("doc"), + lit)), is_sugared_doc: true }; spanned(lo, hi, attr) @@ -178,20 +186,22 @@ pub fn contains_name<AM: AttrMetaMethods>(metas: &[AM], name: &str) -> bool { debug!("attr::contains_name (name={})", name); metas.iter().any(|item| { debug!(" testing: {}", item.name()); - name == item.name() + item.name().equiv(&name) }) } pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: &str) -> Option<@str> { attrs.iter() - .find(|at| name == at.name()) + .find(|at| at.name().equiv(&name)) .and_then(|at| at.value_str()) } pub fn last_meta_item_value_str_by_name(items: &[@MetaItem], name: &str) -> Option<@str> { - items.rev_iter().find(|mi| name == mi.name()).and_then(|i| i.value_str()) + items.rev_iter() + .find(|mi| mi.name().equiv(&name)) + .and_then(|i| i.value_str()) } /* Higher-level applications */ @@ -201,16 +211,16 @@ pub fn sort_meta_items(items: &[@MetaItem]) -> ~[@MetaItem] { // human-readable strings. let mut v = items.iter() .map(|&mi| (mi.name(), mi)) - .collect::<~[(@str, @MetaItem)]>(); + .collect::<~[(InternedString, @MetaItem)]>(); - v.sort_by(|&(a, _), &(b, _)| a.cmp(&b)); + v.sort_by(|&(ref a, _), &(ref b, _)| a.cmp(b)); // There doesn't seem to be a more optimal way to do this v.move_iter().map(|(_, m)| { match m.node { - MetaList(n, ref mis) => { + MetaList(ref n, ref mis) => { @Spanned { - node: MetaList(n, sort_meta_items(*mis)), + node: MetaList((*n).clone(), sort_meta_items(*mis)), .. /*bad*/ (*m).clone() } } @@ -225,7 +235,7 @@ pub fn sort_meta_items(items: &[@MetaItem]) -> ~[@MetaItem] { */ pub fn find_linkage_metas(attrs: &[Attribute]) -> ~[@MetaItem] { let mut result = ~[]; - for attr in attrs.iter().filter(|at| "link" == at.name()) { + for attr in attrs.iter().filter(|at| at.name().equiv(&("link"))) { match attr.meta().node { MetaList(_, ref items) => result.push_all(*items), _ => () @@ -254,8 +264,8 @@ pub fn find_inline_attr(attrs: &[Attribute]) -> InlineAttr { // FIXME (#2809)---validate the usage of #[inline] and #[inline] attrs.iter().fold(InlineNone, |ia,attr| { match attr.node.value.node { - MetaWord(n) if "inline" == n => InlineHint, - MetaList(n, ref items) if "inline" == n => { + MetaWord(ref n) if n.equiv(&("inline")) => InlineHint, + MetaList(ref n, ref items) if n.equiv(&("inline")) => { if contains_name(*items, "always") { InlineAlways } else if contains_name(*items, "never") { @@ -284,7 +294,7 @@ pub fn test_cfg<AM: AttrMetaMethods, It: Iterator<AM>> // this doesn't work. let some_cfg_matches = metas.any(|mi| { debug!("testing name: {}", mi.name()); - if "cfg" == mi.name() { // it is a #[cfg()] attribute + if mi.name().equiv(&("cfg")) { // it is a #[cfg()] attribute debug!("is cfg"); no_cfgs = false; // only #[cfg(...)] ones are understood. @@ -294,7 +304,8 @@ pub fn test_cfg<AM: AttrMetaMethods, It: Iterator<AM>> cfg_meta.iter().all(|cfg_mi| { debug!("cfg({}[...])", cfg_mi.name()); match cfg_mi.node { - ast::MetaList(s, ref not_cfgs) if "not" == s => { + ast::MetaList(ref s, ref not_cfgs) + if s.equiv(&("not")) => { debug!("not!"); // inside #[cfg(not(...))], so these need to all // not match. @@ -337,7 +348,7 @@ pub enum StabilityLevel { /// Find the first stability attribute. `None` if none exists. pub fn find_stability<AM: AttrMetaMethods, It: Iterator<AM>>(mut metas: It) -> Option<Stability> { for m in metas { - let level = match m.name().as_slice() { + let level = match m.name().get() { "deprecated" => Deprecated, "experimental" => Experimental, "unstable" => Unstable, @@ -360,7 +371,7 @@ pub fn require_unique_names(diagnostic: @SpanHandler, metas: &[@MetaItem]) { for meta in metas.iter() { let name = meta.name(); - if !set.insert(name) { + if !set.insert(name.clone()) { diagnostic.span_fatal(meta.span, format!("duplicate meta item `{}`", name)); } @@ -384,14 +395,14 @@ pub fn find_repr_attr(diagnostic: @SpanHandler, attr: @ast::MetaItem, acc: ReprA -> ReprAttr { let mut acc = acc; match attr.node { - ast::MetaList(s, ref items) if "repr" == s => { + ast::MetaList(ref s, ref items) if s.equiv(&("repr")) => { for item in items.iter() { match item.node { - ast::MetaWord(word) => { - let hint = match word.as_slice() { + ast::MetaWord(ref word) => { + let hint = match word.get() { // Can't use "extern" because it's not a lexical identifier. "C" => ReprExtern, - _ => match int_type_of_word(word) { + _ => match int_type_of_word(word.get()) { Some(ity) => ReprInt(item.span, ity), None => { // Not a word we recognize diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 9ad4f4f7fac..884bd831ce8 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -228,9 +228,17 @@ pub trait AstBuilder { fn attribute(&self, sp: Span, mi: @ast::MetaItem) -> ast::Attribute; - fn meta_word(&self, sp: Span, w: @str) -> @ast::MetaItem; - fn meta_list(&self, sp: Span, name: @str, mis: ~[@ast::MetaItem]) -> @ast::MetaItem; - fn meta_name_value(&self, sp: Span, name: @str, value: ast::Lit_) -> @ast::MetaItem; + fn meta_word(&self, sp: Span, w: InternedString) -> @ast::MetaItem; + fn meta_list(&self, + sp: Span, + name: InternedString, + mis: ~[@ast::MetaItem]) + -> @ast::MetaItem; + fn meta_name_value(&self, + sp: Span, + name: InternedString, + value: ast::Lit_) + -> @ast::MetaItem; fn view_use(&self, sp: Span, vis: ast::Visibility, vp: ~[@ast::ViewPath]) -> ast::ViewItem; @@ -866,13 +874,21 @@ impl<'a> AstBuilder for ExtCtxt<'a> { }) } - fn meta_word(&self, sp: Span, w: @str) -> @ast::MetaItem { + fn meta_word(&self, sp: Span, w: InternedString) -> @ast::MetaItem { @respan(sp, ast::MetaWord(w)) } - fn meta_list(&self, sp: Span, name: @str, mis: ~[@ast::MetaItem]) -> @ast::MetaItem { + fn meta_list(&self, + sp: Span, + name: InternedString, + mis: ~[@ast::MetaItem]) + -> @ast::MetaItem { @respan(sp, ast::MetaList(name, mis)) } - fn meta_name_value(&self, sp: Span, name: @str, value: ast::Lit_) -> @ast::MetaItem { + fn meta_name_value(&self, + sp: Span, + name: InternedString, + value: ast::Lit_) + -> @ast::MetaItem { @respan(sp, ast::MetaNameValue(name, respan(sp, value))) } diff --git a/src/libsyntax/ext/cfg.rs b/src/libsyntax/ext/cfg.rs index 9af295c0b11..295c456c9d0 100644 --- a/src/libsyntax/ext/cfg.rs +++ b/src/libsyntax/ext/cfg.rs @@ -21,9 +21,10 @@ use ext::base; use ext::build::AstBuilder; use attr; use attr::*; -use parse; -use parse::token; use parse::attr::ParserAttr; +use parse::token::InternedString; +use parse::token; +use parse; pub fn expand_cfg(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::MacResult { let mut p = parse::new_parser_from_tts(cx.parse_sess(), @@ -39,7 +40,7 @@ pub fn expand_cfg(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::M } // test_cfg searches for meta items looking like `cfg(foo, ...)` - let in_cfg = &[cx.meta_list(sp, @"cfg", cfgs)]; + let in_cfg = &[cx.meta_list(sp, InternedString::new("cfg"), cfgs)]; let matches_cfg = attr::test_cfg(cx.cfg(), in_cfg.iter().map(|&x| x)); let e = cx.expr_bool(sp, matches_cfg); diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs index 6449d0aab5e..20a515692e1 100644 --- a/src/libsyntax/ext/deriving/generic.rs +++ b/src/libsyntax/ext/deriving/generic.rs @@ -184,6 +184,7 @@ use ext::build::AstBuilder; use codemap; use codemap::Span; use opt_vec; +use parse::token::InternedString; use std::vec; @@ -396,7 +397,7 @@ impl<'a> TraitDef<'a> { let doc_attr = cx.attribute( self.span, cx.meta_name_value(self.span, - @"doc", + InternedString::new("doc"), ast::LitStr(@"Automatically derived.", ast::CookedStr))); cx.item( self.span, @@ -567,7 +568,14 @@ impl<'a> MethodDef<'a> { let body_block = trait_.cx.block_expr(body); let attrs = if self.inline { - ~[trait_.cx.attribute(trait_.span, trait_.cx.meta_word(trait_.span, @"inline"))] + ~[ + trait_.cx + .attribute(trait_.span, + trait_.cx + .meta_word(trait_.span, + InternedString::new( + "inline"))) + ] } else { ~[] }; diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index 652f5ebe6c7..9c487146639 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -75,12 +75,12 @@ pub fn expand_meta_deriving(cx: &ExtCtxt, MetaList(_, ref titems) => { titems.rev_iter().fold(in_items, |in_items, &titem| { match titem.node { - MetaNameValue(tname, _) | - MetaList(tname, _) | - MetaWord(tname) => { + MetaNameValue(ref tname, _) | + MetaList(ref tname, _) | + MetaWord(ref tname) => { macro_rules! expand(($func:path) => ($func(cx, titem.span, titem, in_items))); - match tname.as_slice() { + match tname.get() { "Clone" => expand!(clone::expand_deriving_clone), "DeepClone" => expand!(clone::expand_deriving_deep_clone), diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 1ffff03a80f..d98a549725c 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -221,12 +221,12 @@ pub fn expand_mod_items(module_: &ast::Mod, fld: &mut MacroExpander) -> ast::Mod item.attrs.rev_iter().fold(~[*item], |items, attr| { let mname = attr.name(); - match fld.extsbox.find(&intern(mname)) { + match fld.extsbox.find(&intern(mname.get())) { Some(&ItemDecorator(dec_fn)) => { fld.cx.bt_push(ExpnInfo { call_site: attr.span, callee: NameAndSpan { - name: mname, + name: mname.get().to_managed(), format: MacroAttribute, span: None } diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs index bbf6f7fff7f..5730d435c15 100644 --- a/src/libsyntax/ext/format.rs +++ b/src/libsyntax/ext/format.rs @@ -14,9 +14,10 @@ use codemap::{Span, respan}; use ext::base::*; use ext::base; use ext::build::AstBuilder; -use rsparse = parse; -use parse::token; use opt_vec; +use parse::token::InternedString; +use parse::token; +use rsparse = parse; use std::fmt::parse; use std::hashmap::{HashMap, HashSet}; use std::vec; @@ -333,13 +334,18 @@ impl<'a> Context<'a> { fn static_attrs(&self) -> ~[ast::Attribute] { // Flag statics as `address_insignificant` so LLVM can merge duplicate // globals as much as possible (which we're generating a whole lot of). - let unnamed = self.ecx.meta_word(self.fmtsp, @"address_insignificant"); + let unnamed = self.ecx + .meta_word(self.fmtsp, + InternedString::new( + "address_insignificant")); let unnamed = self.ecx.attribute(self.fmtsp, unnamed); // Do not warn format string as dead code - let dead_code = self.ecx.meta_word(self.fmtsp, @"dead_code"); + let dead_code = self.ecx.meta_word(self.fmtsp, + InternedString::new("dead_code")); let allow_dead_code = self.ecx.meta_list(self.fmtsp, - @"allow", ~[dead_code]); + InternedString::new("allow"), + ~[dead_code]); let allow_dead_code = self.ecx.attribute(self.fmtsp, allow_dead_code); return ~[unnamed, allow_dead_code]; } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 8dac13f1e31..c2d54a4f368 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -321,15 +321,12 @@ fn fold_meta_item_<T: Folder>(mi: @MetaItem, fld: &mut T) -> @MetaItem { @Spanned { node: match mi.node { - MetaWord(id) => MetaWord(id), - MetaList(id, ref mis) => { + MetaWord(ref id) => MetaWord((*id).clone()), + MetaList(ref id, ref mis) => { let fold_meta_item = |x| fold_meta_item_(x, fld); - MetaList( - id, - mis.map(|e| fold_meta_item(*e)) - ) + MetaList((*id).clone(), mis.map(|e| fold_meta_item(*e))) } - MetaNameValue(id, s) => MetaNameValue(id, s) + MetaNameValue(ref id, s) => MetaNameValue((*id).clone(), s) }, span: fld.new_span(mi.span) } } diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index e7630a66855..bc9f7e4b195 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -157,7 +157,7 @@ impl ParserAttr for Parser { fn parse_meta_item(&mut self) -> @ast::MetaItem { let lo = self.span.lo; let ident = self.parse_ident(); - let name = self.id_to_str(ident); + let name = self.id_to_interned_str(ident); match self.token { token::EQ => { self.bump(); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 642624adfb2..93264f5a6c6 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -71,10 +71,10 @@ use parse::common::{seq_sep_trailing_disallowed, seq_sep_trailing_allowed}; use parse::lexer::Reader; use parse::lexer::TokenAndSpan; use parse::obsolete::*; -use parse::token::{can_begin_expr, get_ident_interner, ident_to_str, is_ident}; -use parse::token::{is_ident_or_path}; -use parse::token::{is_plain_ident, INTERPOLATED, keywords, special_idents}; -use parse::token::{token_to_binop}; +use parse::token::{INTERPOLATED, InternedString, can_begin_expr, get_ident}; +use parse::token::{get_ident_interner, ident_to_str, is_ident}; +use parse::token::{is_ident_or_path, is_plain_ident, keywords}; +use parse::token::{special_idents, token_to_binop}; use parse::token; use parse::{new_sub_parser_from_file, ParseSess}; use opt_vec; @@ -806,6 +806,10 @@ impl Parser { get_ident_interner().get(id.name) } + pub fn id_to_interned_str(&mut self, id: Ident) -> InternedString { + get_ident(id.name) + } + // Is the current token one of the keywords that signals a bare function // type? pub fn token_is_bare_fn_keyword(&mut self) -> bool { diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 68e2f44ebb1..97b9b4d53a4 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -15,8 +15,10 @@ use parse::token; use util::interner::StrInterner; use util::interner; +use extra::serialize::{Decodable, Decoder, Encodable, Encoder}; use std::cast; use std::char; +use std::fmt; use std::local_data; #[allow(non_camel_case_types)] @@ -525,6 +527,90 @@ pub fn get_ident_interner() -> @IdentInterner { } } +/// Represents a string stored in the task-local interner. Because the +/// interner lives for the life of the task, this can be safely treated as an +/// immortal string, as long as it never crosses between tasks. +/// +/// XXX(pcwalton): You must be careful about what you do in the destructors of +/// objects stored in TLS, because they may run after the interner is +/// destroyed. In particular, they must not access string contents. This can +/// be fixed in the future by just leaking all strings until task death +/// somehow. +#[no_send] +#[deriving(Clone, Eq, IterBytes, TotalEq, TotalOrd)] +pub struct InternedString { + priv string: @str, +} + +#[unsafe_destructor] +impl Drop for InternedString { + fn drop(&mut self) { + // No-op just to make this not implicitly copyable. + } +} + +impl InternedString { + #[inline] + pub fn new(string: &'static str) -> InternedString { + InternedString { + string: string.to_managed(), + } + } + + // NB: Do not make this public. We are trying to remove `@str`. + #[inline] + fn new_from_at_str(string: @str) -> InternedString { + InternedString { + string: string, + } + } + + #[inline] + pub fn get<'a>(&'a self) -> &'a str { + self.string.as_slice() + } +} + +impl fmt::Default for InternedString { + fn fmt(obj: &InternedString, f: &mut fmt::Formatter) { + write!(f.buf, "{}", obj.string); + } +} + +impl<'a> Equiv<&'a str> for InternedString { + fn equiv(&self, other: & &'a str) -> bool { + (*other) == self.string.as_slice() + } +} + +impl<D:Decoder> Decodable<D> for InternedString { + fn decode(d: &mut D) -> InternedString { + let interner = get_ident_interner(); + get_ident(interner.intern(d.read_str())) + } +} + +impl<E:Encoder> Encodable<E> for InternedString { + fn encode(&self, e: &mut E) { + e.emit_str(self.string) + } +} + +/// Returns the string contents of an identifier, using the task-local +/// interner. +#[inline] +pub fn get_ident(idx: Name) -> InternedString { + let interner = get_ident_interner(); + InternedString::new_from_at_str(interner.get(idx)) +} + +/// Interns and returns the string contents of an identifier, using the +/// task-local interner. +#[inline] +pub fn intern_and_get_ident(s: &str) -> InternedString { + get_ident(intern(s)) +} + /* for when we don't care about the contents; doesn't interact with TLD or serialization */ pub fn mk_fake_ident_interner() -> @IdentInterner { @@ -532,6 +618,7 @@ pub fn mk_fake_ident_interner() -> @IdentInterner { } // maps a string to its interned representation +#[inline] pub fn intern(str : &str) -> Name { let interner = get_ident_interner(); interner.intern(str) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 2783284ea8b..89d8173f7e7 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1930,14 +1930,14 @@ pub fn print_generics(s: &mut State, generics: &ast::Generics) { pub fn print_meta_item(s: &mut State, item: &ast::MetaItem) { ibox(s, indent_unit); match item.node { - ast::MetaWord(name) => word(&mut s.s, name), - ast::MetaNameValue(name, value) => { - word_space(s, name); + ast::MetaWord(ref name) => word(&mut s.s, name.get()), + ast::MetaNameValue(ref name, value) => { + word_space(s, name.get()); word_space(s, "="); print_literal(s, &value); } - ast::MetaList(name, ref items) => { - word(&mut s.s, name); + ast::MetaList(ref name, ref items) => { + word(&mut s.s, name.get()); popen(s); commasep(s, Consistent, diff --git a/src/libsyntax/util/interner.rs b/src/libsyntax/util/interner.rs index fdc54f1f140..c0fe19ede01 100644 --- a/src/libsyntax/util/interner.rs +++ b/src/libsyntax/util/interner.rs @@ -14,6 +14,7 @@ use ast::Name; +use std::cast; use std::cell::RefCell; use std::cmp::Equiv; use std::hashmap::HashMap; @@ -151,6 +152,16 @@ impl StrInterner { vect.get()[idx] } + /// Returns this string with lifetime tied to the interner. Since + /// strings may never be removed from the interner, this is safe. + pub fn get_ref<'a>(&'a self, idx: Name) -> &'a str { + let vect = self.vect.borrow(); + let s: &str = vect.get()[idx]; + unsafe { + cast::transmute(s) + } + } + pub fn len(&self) -> uint { let vect = self.vect.borrow(); vect.get().len() |
