Add parser for #[repr(...)]
; nothing uses it yet.
Also export enum attrs into metadata, and add a convenient interface for obtaining the repr hint from either a local or remote definition.
This commit is contained in:
parent
e6650c87a3
commit
f1124a2f55
@ -989,6 +989,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
encode_family(ebml_w, 't');
|
||||
encode_bounds_and_type(ebml_w, ecx, &lookup_item_type(tcx, def_id));
|
||||
encode_name(ecx, ebml_w, item.ident);
|
||||
encode_attributes(ebml_w, item.attrs);
|
||||
for v in (*enum_definition).variants.iter() {
|
||||
encode_variant_id(ebml_w, local_def(v.node.id));
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ use syntax::ast::*;
|
||||
use syntax::ast_util::is_local;
|
||||
use syntax::ast_util;
|
||||
use syntax::attr;
|
||||
use syntax::attr::AttrMetaMethods;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::codemap;
|
||||
use syntax::parse::token;
|
||||
@ -4101,27 +4102,42 @@ pub fn lookup_trait_def(cx: ctxt, did: ast::DefId) -> @ty::TraitDef {
|
||||
}
|
||||
}
|
||||
|
||||
/// Determine whether an item is annotated with an attribute
|
||||
pub fn has_attr(tcx: ctxt, did: DefId, attr: &str) -> bool {
|
||||
/// Iterate over meta_items of a definition.
|
||||
// (This should really be an iterator, but that would require csearch and
|
||||
// decoder to use iterators instead of higher-order functions.)
|
||||
pub fn each_attr(tcx: ctxt, did: DefId, f: &fn(@MetaItem) -> bool) -> bool {
|
||||
if is_local(did) {
|
||||
match tcx.items.find(&did.node) {
|
||||
Some(
|
||||
&ast_map::node_item(@ast::item {
|
||||
attrs: ref attrs,
|
||||
_
|
||||
}, _)) => attr::contains_name(*attrs, attr),
|
||||
Some(&ast_map::node_item(@ast::item {attrs: ref attrs, _}, _)) =>
|
||||
attrs.iter().advance(|attr| f(attr.node.value)),
|
||||
_ => tcx.sess.bug(format!("has_attr: {:?} is not an item",
|
||||
did))
|
||||
did))
|
||||
}
|
||||
} else {
|
||||
let mut ret = false;
|
||||
let mut cont = true;
|
||||
do csearch::get_item_attrs(tcx.cstore, did) |meta_items| {
|
||||
ret = ret || attr::contains_name(meta_items, attr);
|
||||
if cont {
|
||||
cont = meta_items.iter().advance(|ptrptr| f(*ptrptr));
|
||||
}
|
||||
}
|
||||
ret
|
||||
return cont;
|
||||
}
|
||||
}
|
||||
|
||||
/// Determine whether an item is annotated with an attribute
|
||||
pub fn has_attr(tcx: ctxt, did: DefId, attr: &str) -> bool {
|
||||
let mut found = false;
|
||||
each_attr(tcx, did, |item| {
|
||||
if attr == item.name() {
|
||||
found = true;
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
return found;
|
||||
}
|
||||
|
||||
/// Determine whether an item is annotated with `#[packed]`
|
||||
pub fn lookup_packed(tcx: ctxt, did: DefId) -> bool {
|
||||
has_attr(tcx, did, "packed")
|
||||
@ -4132,6 +4148,16 @@ pub fn lookup_simd(tcx: ctxt, did: DefId) -> bool {
|
||||
has_attr(tcx, did, "simd")
|
||||
}
|
||||
|
||||
// Obtain the the representation annotation for a definition.
|
||||
pub fn lookup_repr_hint(tcx: ctxt, did: DefId) -> attr::ReprAttr {
|
||||
let mut acc = attr::ReprAny;
|
||||
ty::each_attr(tcx, did, |meta| {
|
||||
acc = attr::find_repr_attr(tcx.sess.diagnostic(), meta, acc);
|
||||
true
|
||||
});
|
||||
return acc;
|
||||
}
|
||||
|
||||
// Look up a field ID, whether or not it's local
|
||||
// Takes a list of type substs in case the struct is generic
|
||||
pub fn lookup_field_type(tcx: ctxt,
|
||||
|
@ -14,7 +14,7 @@ use extra;
|
||||
|
||||
use ast;
|
||||
use ast::{Attribute, Attribute_, MetaItem, MetaWord, MetaNameValue, MetaList};
|
||||
use codemap::{Spanned, spanned, dummy_spanned};
|
||||
use codemap::{Span, Spanned, spanned, dummy_spanned};
|
||||
use codemap::BytePos;
|
||||
use diagnostic::span_handler;
|
||||
use parse::comments::{doc_comment_style, strip_doc_comment_decoration};
|
||||
@ -363,3 +363,97 @@ pub fn require_unique_names(diagnostic: @mut span_handler,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fold this over attributes to parse #[repr(...)] forms.
|
||||
*
|
||||
* Valid repr contents: any of the primitive integral type names (see
|
||||
* `int_type_of_word`, below) to specify the discriminant type; and `C`, to use
|
||||
* the same discriminant size that the corresponding C enum would. These are
|
||||
* not allowed on univariant or zero-variant enums, which have no discriminant.
|
||||
*
|
||||
* If a discriminant type is so specified, then the discriminant will be
|
||||
* present (before fields, if any) with that type; reprensentation
|
||||
* optimizations which would remove it will not be done.
|
||||
*/
|
||||
pub fn find_repr_attr(diagnostic: @mut span_handler, attr: @ast::MetaItem, acc: ReprAttr)
|
||||
-> ReprAttr {
|
||||
let mut acc = acc;
|
||||
match attr.node {
|
||||
ast::MetaList(s, ref items) if "repr" == s => {
|
||||
for item in items.iter() {
|
||||
match item.node {
|
||||
ast::MetaWord(word) => {
|
||||
let word: &str = word;
|
||||
let hint = match word {
|
||||
// Can't use "extern" because it's not a lexical identifier.
|
||||
"C" => ReprExtern,
|
||||
_ => match int_type_of_word(word) {
|
||||
Some(ity) => ReprInt(item.span, ity),
|
||||
None => {
|
||||
// Not a word we recognize
|
||||
diagnostic.span_err(item.span,
|
||||
"unrecognized representation hint");
|
||||
ReprAny
|
||||
}
|
||||
}
|
||||
};
|
||||
if hint != ReprAny {
|
||||
if acc == ReprAny {
|
||||
acc = hint;
|
||||
} else if acc != hint {
|
||||
diagnostic.span_warn(item.span,
|
||||
"conflicting representation hint ignored")
|
||||
}
|
||||
}
|
||||
}
|
||||
// Not a word:
|
||||
_ => diagnostic.span_err(item.span, "unrecognized representation hint")
|
||||
}
|
||||
}
|
||||
}
|
||||
// Not a "repr" hint: ignore.
|
||||
_ => { }
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
fn int_type_of_word(s: &str) -> Option<IntType> {
|
||||
match s {
|
||||
"i8" => Some(SignedInt(ast::ty_i8)),
|
||||
"u8" => Some(UnsignedInt(ast::ty_u8)),
|
||||
"i16" => Some(SignedInt(ast::ty_i16)),
|
||||
"u16" => Some(UnsignedInt(ast::ty_u16)),
|
||||
"i32" => Some(SignedInt(ast::ty_i32)),
|
||||
"u32" => Some(UnsignedInt(ast::ty_u32)),
|
||||
"i64" => Some(SignedInt(ast::ty_i64)),
|
||||
"u64" => Some(UnsignedInt(ast::ty_u64)),
|
||||
"int" => Some(SignedInt(ast::ty_i)),
|
||||
"uint" => Some(UnsignedInt(ast::ty_u)),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(Eq)]
|
||||
pub enum ReprAttr {
|
||||
ReprAny,
|
||||
ReprInt(Span, IntType),
|
||||
ReprExtern
|
||||
}
|
||||
|
||||
#[deriving(Eq)]
|
||||
pub enum IntType {
|
||||
SignedInt(ast::int_ty),
|
||||
UnsignedInt(ast::uint_ty)
|
||||
}
|
||||
|
||||
impl IntType {
|
||||
#[inline]
|
||||
pub fn is_signed(self) -> bool {
|
||||
match self {
|
||||
SignedInt(*) => true,
|
||||
UnsignedInt(*) => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user