Skip to content

Commit

Permalink
Add parser for #[repr(...)]; nothing uses it yet.
Browse files Browse the repository at this point in the history
Also export enum attrs into metadata, and add a convenient interface for
obtaining the repr hint from either a local or remote definition.
  • Loading branch information
jld committed Oct 29, 2013
1 parent e6650c8 commit f1124a2
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 12 deletions.
1 change: 1 addition & 0 deletions src/librustc/metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
48 changes: 37 additions & 11 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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")
Expand All @@ -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,
Expand Down
96 changes: 95 additions & 1 deletion src/libsyntax/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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
}
}
}

0 comments on commit f1124a2

Please sign in to comment.