// types and then use hash_content. But, since all crate
// attributes should appear near beginning of the file, it is
// not such a big deal to be sensitive to their spans for now.
- krate.attrs.hash(&mut state);
+ //
+ // We hash only the MetaItems instead of the entire Attribute
+ // to avoid hashing the AttrId
+ for attr in krate.attrs.iter() {
+ attr.node.value.hash(&mut state);
+ }
let hash = state.result();
return Svh {
with_version("std"),
ast::DUMMY_NODE_ID),
attrs: vec!(
- attr::mk_attr_outer(attr::mk_list_item(
+ attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_list_item(
InternedString::new("phase"),
vec!(
attr::mk_word_item(InternedString::new("syntax")),
// Add it during the prelude injection instead.
// Add #![feature(phase)] here, because we use #[phase] on extern crate std.
- let feat_phase_attr = attr::mk_attr_inner(attr::mk_list_item(
+ let feat_phase_attr = attr::mk_attr_inner(attr::mk_attr_id(),
+ attr::mk_list_item(
InternedString::new("feature"),
vec![attr::mk_word_item(InternedString::new("phase"))],
));
// This must happen here and not in StandardLibraryInjector because this
// fold happens second.
- let no_std_attr = attr::mk_attr_inner(attr::mk_word_item(InternedString::new("no_std")));
+ let no_std_attr = attr::mk_attr_inner(attr::mk_attr_id(),
+ attr::mk_word_item(InternedString::new("no_std")));
krate.attrs.push(no_std_attr);
if !no_prelude(krate.attrs.as_slice()) {
// `#![no_implicit_prelude]` at the crate level.
// fold_mod() will insert glob path.
- let globs_attr = attr::mk_attr_inner(attr::mk_list_item(
+ let globs_attr = attr::mk_attr_inner(attr::mk_attr_id(),
+ attr::mk_list_item(
InternedString::new("feature"),
vec!(
attr::mk_word_item(InternedString::new("globs")),
// 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_inner(attr::mk_word_item(resolve_unexported_str));
+ attr::mk_attr_inner(attr::mk_attr_id(),
+ attr::mk_word_item(resolve_unexported_str));
let item = ast::Item {
ident: token::str_to_ident("__test"),
attrs.push(
codemap::Spanned {
node: ast::Attribute_ {
+ id: attr::mk_attr_id(),
style: ast::AttrOuter,
value: meta_item,
is_sugared_doc: false,
fn synthesize_crateid_attr(ecx: &EncodeContext) -> Attribute {
assert!(!ecx.link_meta.crateid.name.is_empty());
- attr::mk_attr_inner(
+ attr::mk_attr_inner(attr::mk_attr_id(),
attr::mk_name_value_item_str(
InternedString::new("crate_id"),
token::intern_and_get_ident(ecx.link_meta
let f = decl_rust_fn(ccx, fn_ty, name);
csearch::get_item_attrs(&ccx.sess().cstore, did, |meta_items| {
- set_llvm_fn_attrs(meta_items.iter().map(|&x| attr::mk_attr_outer(x))
- .collect::<Vec<_>>().as_slice(), f)
+ set_llvm_fn_attrs(meta_items.iter().map(|&x| {
+ attr::mk_attr_outer(attr::mk_attr_id(), x)
+ }).collect::<Vec<_>>().as_slice(), f)
});
ccx.externs.borrow_mut().insert(name.to_strbuf(), f);
AttrInner,
}
+#[deriving(Clone, Eq, TotalEq, Encodable, Decodable, Hash)]
+pub struct AttrId(pub uint);
+
// doc-comments are promoted to attributes that have is_sugared_doc = true
#[deriving(Clone, Eq, TotalEq, Encodable, Decodable, Hash)]
pub struct Attribute_ {
+ pub id: AttrId,
pub style: AttrStyle,
pub value: @MetaItem,
pub is_sugared_doc: bool,
// Functions dealing with attributes and meta items
use ast;
-use ast::{Attribute, Attribute_, MetaItem, MetaWord, MetaNameValue, MetaList};
+use ast::{AttrId, Attribute, Attribute_, MetaItem, MetaWord, MetaNameValue, MetaList};
use codemap::{Span, Spanned, spanned, dummy_spanned};
use codemap::BytePos;
use diagnostic::SpanHandler;
use collections::HashSet;
+local_data_key!(used_attrs: HashSet<AttrId>)
+
+pub fn mark_used(attr: &Attribute) {
+ let mut used = used_attrs.replace(None).unwrap_or_else(|| HashSet::new());
+ used.insert(attr.node.id);
+ used_attrs.replace(Some(used));
+}
+
+pub fn is_used(attr: &Attribute) -> bool {
+ used_attrs.get().map_or(false, |used| used.contains(&attr.node.id))
+}
+
pub trait AttrMetaMethods {
// This could be changed to `fn check_name(&self, name: InternedString) ->
// bool` which would facilitate a side table recording which
token::intern_and_get_ident(strip_doc_comment_decoration(
comment.get()).as_slice()));
if self.node.style == ast::AttrOuter {
- mk_attr_outer(meta)
+ mk_attr_outer(self.node.id, meta)
} else {
- mk_attr_inner(meta)
+ mk_attr_inner(self.node.id, meta)
}
} else {
*self
@dummy_spanned(MetaWord(name))
}
+local_data_key!(next_attr_id: uint)
+
+pub fn mk_attr_id() -> AttrId {
+ let id = next_attr_id.replace(None).unwrap_or(0);
+ next_attr_id.replace(Some(id + 1));
+ AttrId(id)
+}
+
/// Returns an inner attribute with the given value.
-pub fn mk_attr_inner(item: @MetaItem) -> Attribute {
+pub fn mk_attr_inner(id: AttrId, item: @MetaItem) -> Attribute {
dummy_spanned(Attribute_ {
+ id: id,
style: ast::AttrInner,
value: item,
is_sugared_doc: false,
}
/// Returns an outer attribute with the given value.
-pub fn mk_attr_outer(item: @MetaItem) -> Attribute {
+pub fn mk_attr_outer(id: AttrId, item: @MetaItem) -> Attribute {
dummy_spanned(Attribute_ {
+ id: id,
style: ast::AttrOuter,
value: item,
is_sugared_doc: false,
})
}
-pub fn mk_sugared_doc_attr(text: InternedString, lo: BytePos, hi: BytePos)
+pub fn mk_sugared_doc_attr(id: AttrId, text: InternedString, lo: BytePos,
+ hi: BytePos)
-> Attribute {
let style = doc_comment_style(text.get());
let lit = spanned(lo, hi, ast::LitStr(text, ast::CookedStr));
let attr = Attribute_ {
+ id: id,
style: style,
value: @spanned(lo, hi, MetaNameValue(InternedString::new("doc"),
lit)),
generics: Generics) -> @ast::Item;
fn item_ty(&self, span: Span, name: Ident, ty: P<ast::Ty>) -> @ast::Item;
- fn attribute(&self, sp: Span, mi: @ast::MetaItem) -> ast::Attribute;
+ fn attribute(&self, id: AttrId, sp: Span, mi: @ast::MetaItem) -> ast::Attribute;
fn meta_word(&self, sp: Span, w: InternedString) -> @ast::MetaItem;
fn meta_list(&self,
self.item_ty_poly(span, name, ty, ast_util::empty_generics())
}
- fn attribute(&self, sp: Span, mi: @ast::MetaItem) -> ast::Attribute {
+ fn attribute(&self, id: ast::AttrId, sp: Span, mi: @ast::MetaItem)
+ -> ast::Attribute {
respan(sp, ast::Attribute_ {
+ id: id,
style: ast::AttrOuter,
value: mi,
is_sugared_doc: false,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use attr;
use ast::{MetaItem, Item, Expr};
use codemap::Span;
use ext::base::ExtCtxt;
item: @Item,
push: |@Item|) {
let inline = cx.meta_word(span, InternedString::new("inline"));
- let attrs = vec!(cx.attribute(span, inline));
+ let attrs = vec!(cx.attribute(attr::mk_attr_id(), span, inline));
let trait_def = TraitDef {
span: span,
attributes: Vec::new(),
// except according to those terms.
use ast::{MetaItem, Item, Expr};
+use attr;
use codemap::Span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
macro_rules! md (
($name:expr, $f:ident) => { {
let inline = cx.meta_word(span, InternedString::new("inline"));
- let attrs = vec!(cx.attribute(span, inline));
+ let attrs = vec!(cx.attribute(attr::mk_attr_id(), span, inline));
MethodDef {
name: $name,
generics: LifetimeBounds::empty(),
use ast;
use ast::{MetaItem, Item, Expr};
+use attr;
use codemap::Span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
macro_rules! md (
($name:expr, $op:expr, $equal:expr) => { {
let inline = cx.meta_word(span, InternedString::new("inline"));
- let attrs = vec!(cx.attribute(span, inline));
+ let attrs = vec!(cx.attribute(attr::mk_attr_id(), span, inline));
MethodDef {
name: $name,
generics: LifetimeBounds::empty(),
// except according to those terms.
use ast::{MetaItem, Item, Expr};
+use attr;
use codemap::Span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
let inline = cx.meta_word(span, InternedString::new("inline"));
let hidden = cx.meta_word(span, InternedString::new("hidden"));
let doc = cx.meta_list(span, InternedString::new("doc"), vec!(hidden));
- let attrs = vec!(cx.attribute(span, inline),
- cx.attribute(span, doc));
+ let attrs = vec!(cx.attribute(attr::mk_attr_id(), span, inline),
+ cx.attribute(attr::mk_attr_id(), span, doc));
let trait_def = TraitDef {
span: span,
attributes: Vec::new(),
use ast;
use ast::{MetaItem, Item, Expr};
+use attr;
use codemap::Span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
item: @Item,
push: |@Item|) {
let inline = cx.meta_word(span, InternedString::new("inline"));
- let attrs = vec!(cx.attribute(span, inline));
+ let attrs = vec!(cx.attribute(attr::mk_attr_id(), span, inline));
let trait_def = TraitDef {
span: span,
attributes: Vec::new(),
// except according to those terms.
use ast::{MetaItem, Item, Expr};
+use attr;
use codemap::Span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
item: @Item,
push: |@Item|) {
let inline = cx.meta_word(span, InternedString::new("inline"));
- let attrs = vec!(cx.attribute(span, inline));
+ let attrs = vec!(cx.attribute(attr::mk_attr_id(), span, inline));
let trait_def = TraitDef {
span: span,
attributes: Vec::new(),
use ast;
use ast::{P, EnumDef, Expr, Ident, Generics, StructDef};
use ast_util;
+use attr;
use attr::AttrMetaMethods;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
self_ty_params.into_vec()), None);
let attr = cx.attribute(
+ attr::mk_attr_id(),
self.span,
cx.meta_word(self.span,
InternedString::new("automatically_derived")));
use ast;
use ast::{MetaItem, Item, Expr, MutMutable};
+use attr;
use codemap::Span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
Path::new(vec!("std", "hash", "sip", "SipState")))
};
let inline = cx.meta_word(span, InternedString::new("inline"));
- let attrs = vec!(cx.attribute(span, inline));
+ let attrs = vec!(cx.attribute(attr::mk_attr_id(), span, inline));
let hash_trait_def = TraitDef {
span: span,
attributes: Vec::new(),
use ast::{MetaItem, Item, Expr};
use ast;
+use attr;
use codemap::Span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
item: @Item,
push: |@Item|) {
let inline = cx.meta_word(span, InternedString::new("inline"));
- let attrs = vec!(cx.attribute(span, inline));
+ let attrs = vec!(cx.attribute(attr::mk_attr_id(), span, inline));
let trait_def = TraitDef {
span: span,
attributes: Vec::new(),
// except according to those terms.
use ast::{MetaItem, Item, Expr};
+use attr;
use codemap::Span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
item: @Item,
push: |@Item|) {
let inline = cx.meta_word(span, InternedString::new("inline"));
- let attrs = vec!(cx.attribute(span, inline));
+ let attrs = vec!(cx.attribute(attr::mk_attr_id(), span, inline));
let trait_def = TraitDef {
span: span,
attributes: Vec::new(),
use super::*;
use ast;
use ast::{Attribute_, AttrOuter, MetaWord};
+ use attr;
use codemap;
use codemap::Spanned;
use ext::base::{CrateLoader, MacroCrate};
Spanned {
span:codemap::DUMMY_SP,
node: Attribute_ {
+ id: attr::mk_attr_id(),
style: AttrOuter,
value: @Spanned {
node: MetaWord(token::intern_and_get_ident(s)),
use ast;
use ast::P;
+use attr;
use codemap::{Span, respan};
use ext::base::*;
use ext::base;
.meta_word(self.fmtsp,
InternedString::new(
"address_insignificant"));
- let unnamed = self.ecx.attribute(self.fmtsp, unnamed);
+ let unnamed = self.ecx.attribute(attr::mk_attr_id(), self.fmtsp,
+ unnamed);
// Do not warn format string as dead code
let dead_code = self.ecx.meta_word(self.fmtsp,
let allow_dead_code = self.ecx.meta_list(self.fmtsp,
InternedString::new("allow"),
vec!(dead_code));
- let allow_dead_code = self.ecx.attribute(self.fmtsp, allow_dead_code);
+ let allow_dead_code = self.ecx.attribute(attr::mk_attr_id(), self.fmtsp,
+ allow_dead_code);
return vec!(unnamed, allow_dead_code);
}
Spanned {
span: fld.new_span(at.span),
node: ast::Attribute_ {
+ id: at.node.id,
style: at.node.style,
value: fold_meta_item_(at.node.value, fld),
is_sugared_doc: at.node.is_sugared_doc
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use attr;
use ast;
use codemap::{spanned, Spanned, mk_sp, Span};
use parse::common::*; //resolve bug?
}
token::DOC_COMMENT(s) => {
let attr = ::attr::mk_sugared_doc_attr(
+ attr::mk_attr_id(),
self.id_to_interned_str(s),
self.span.lo,
self.span.hi
return Spanned {
span: span,
node: ast::Attribute_ {
+ id: attr::mk_attr_id(),
style: style,
value: value,
is_sugared_doc: false
// we need to get the position of this token before we bump.
let Span { lo, hi, .. } = self.span;
self.bump();
- ::attr::mk_sugared_doc_attr(self.id_to_interned_str(s), lo, hi)
+ ::attr::mk_sugared_doc_attr(attr::mk_attr_id(),
+ self.id_to_interned_str(s),
+ lo,
+ hi)
}
_ => {
break;