Skip to content

Commit 7a75fe8

Browse files
committed
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.
1 parent d84a7b5 commit 7a75fe8

File tree

3 files changed

+133
-11
lines changed

3 files changed

+133
-11
lines changed

src/librustc/metadata/encoder.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -941,6 +941,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
941941
encode_family(ebml_w, 't');
942942
encode_bounds_and_type(ebml_w, ecx, &lookup_item_type(tcx, def_id));
943943
encode_name(ecx, ebml_w, item.ident);
944+
encode_attributes(ebml_w, item.attrs);
944945
for v in (*enum_definition).variants.iter() {
945946
encode_variant_id(ebml_w, local_def(v.node.id));
946947
}

src/librustc/middle/ty.rs

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ use syntax::ast::*;
3838
use syntax::ast_util::is_local;
3939
use syntax::ast_util;
4040
use syntax::attr;
41+
use syntax::attr::AttrMetaMethods;
4142
use syntax::codemap::Span;
4243
use syntax::codemap;
4344
use syntax::parse::token;
@@ -4120,27 +4121,42 @@ pub fn lookup_trait_def(cx: ctxt, did: ast::DefId) -> @ty::TraitDef {
41204121
}
41214122
}
41224123

4123-
/// Determine whether an item is annotated with an attribute
4124-
pub fn has_attr(tcx: ctxt, did: DefId, attr: &str) -> bool {
4124+
/// Iterate over meta_items of a definition.
4125+
// (This should really be an iterator, but that would require csearch and
4126+
// decoder to use iterators instead of higher-order functions.)
4127+
pub fn each_attr(tcx: ctxt, did: DefId, f: &fn(@MetaItem) -> bool) -> bool {
41254128
if is_local(did) {
41264129
match tcx.items.find(&did.node) {
4127-
Some(
4128-
&ast_map::node_item(@ast::item {
4129-
attrs: ref attrs,
4130-
_
4131-
}, _)) => attr::contains_name(*attrs, attr),
4130+
Some(&ast_map::node_item(@ast::item {attrs: ref attrs, _}, _)) =>
4131+
attrs.iter().advance(|attr| f(attr.node.value)),
41324132
_ => tcx.sess.bug(fmt!("has_attr: %? is not an item",
41334133
did))
41344134
}
41354135
} else {
4136-
let mut ret = false;
4136+
let mut cont = true;
41374137
do csearch::get_item_attrs(tcx.cstore, did) |meta_items| {
4138-
ret = ret || attr::contains_name(meta_items, attr);
4138+
if cont {
4139+
cont = meta_items.iter().advance(|ptrptr| f(*ptrptr));
4140+
}
41394141
}
4140-
ret
4142+
return cont;
41414143
}
41424144
}
41434145

4146+
/// Determine whether an item is annotated with an attribute
4147+
pub fn has_attr(tcx: ctxt, did: DefId, attr: &str) -> bool {
4148+
let mut found = false;
4149+
each_attr(tcx, did, |item| {
4150+
if attr == item.name() {
4151+
found = true;
4152+
false
4153+
} else {
4154+
true
4155+
}
4156+
});
4157+
return found;
4158+
}
4159+
41444160
/// Determine whether an item is annotated with `#[packed]`
41454161
pub fn lookup_packed(tcx: ctxt, did: DefId) -> bool {
41464162
has_attr(tcx, did, "packed")
@@ -4151,6 +4167,16 @@ pub fn lookup_simd(tcx: ctxt, did: DefId) -> bool {
41514167
has_attr(tcx, did, "simd")
41524168
}
41534169

4170+
// Obtain the the representation annotation for a definition.
4171+
pub fn lookup_repr_hint(tcx: ctxt, did: DefId) -> attr::ReprAttr {
4172+
let mut acc = attr::ReprAny;
4173+
ty::each_attr(tcx, did, |meta| {
4174+
acc = attr::find_repr_attr(tcx.sess.diagnostic(), meta, acc);
4175+
true
4176+
});
4177+
return acc;
4178+
}
4179+
41544180
// Look up a field ID, whether or not it's local
41554181
// Takes a list of type substs in case the struct is generic
41564182
pub fn lookup_field_type(tcx: ctxt,

src/libsyntax/attr.rs

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use extra;
1414

1515
use ast;
1616
use ast::{Attribute, Attribute_, MetaItem, MetaWord, MetaNameValue, MetaList};
17-
use codemap::{Spanned, spanned, dummy_spanned};
17+
use codemap::{Span, Spanned, spanned, dummy_spanned};
1818
use codemap::BytePos;
1919
use diagnostic::span_handler;
2020
use parse::comments::{doc_comment_style, strip_doc_comment_decoration};
@@ -363,3 +363,98 @@ pub fn require_unique_names(diagnostic: @mut span_handler,
363363
}
364364
}
365365
}
366+
367+
368+
/**
369+
* Fold this over attributes to parse #[repr(...)] forms.
370+
*
371+
* Valid repr contents: any of the primitive integral type names (see
372+
* `int_type_of_word`, below) to specify the discriminant type; and `C`, to use
373+
* the same discriminant size that the corresponding C enum would. These are
374+
* not allowed on univariant or zero-variant enums, which have no discriminant.
375+
*
376+
* If a discriminant type is so specified, then the discriminant will be
377+
* present (before fields, if any) with that type; reprensentation
378+
* optimizations which would remove it will not be done.
379+
*/
380+
pub fn find_repr_attr(diagnostic: @mut span_handler, attr: @ast::MetaItem, acc: ReprAttr)
381+
-> ReprAttr {
382+
let mut acc = acc;
383+
match attr.node {
384+
ast::MetaList(s, ref items) if "repr" == s => {
385+
for item in items.iter() {
386+
match item.node {
387+
ast::MetaWord(word) => {
388+
let word: &str = word;
389+
let hint = match word {
390+
// Can't use "extern" because it's not a lexical identifier.
391+
"C" => ReprExtern,
392+
_ => match int_type_of_word(word) {
393+
Some(ity) => ReprInt(item.span, ity),
394+
None => {
395+
// Not a word we recognize
396+
diagnostic.span_warn(item.span,
397+
"unrecognized representation hint");
398+
ReprAny
399+
}
400+
}
401+
};
402+
if hint != ReprAny {
403+
if acc == ReprAny {
404+
acc = hint;
405+
} else if acc != hint {
406+
diagnostic.span_warn(item.span,
407+
"conflicting representation hint \
408+
ignored")
409+
}
410+
}
411+
}
412+
// Not a word:
413+
_ => diagnostic.span_warn(item.span, "unrecognized representation hint")
414+
}
415+
}
416+
}
417+
// Not a "repr" hint: ignore.
418+
_ => { }
419+
}
420+
return acc;
421+
}
422+
423+
fn int_type_of_word(s: &str) -> Option<IntType> {
424+
match s {
425+
"i8" => Some(SignedInt(ast::ty_i8)),
426+
"u8" => Some(UnsignedInt(ast::ty_u8)),
427+
"i16" => Some(SignedInt(ast::ty_i16)),
428+
"u16" => Some(UnsignedInt(ast::ty_u16)),
429+
"i32" => Some(SignedInt(ast::ty_i32)),
430+
"u32" => Some(UnsignedInt(ast::ty_u32)),
431+
"i64" => Some(SignedInt(ast::ty_i64)),
432+
"u64" => Some(UnsignedInt(ast::ty_u64)),
433+
"int" => Some(SignedInt(ast::ty_i)),
434+
"uint" => Some(UnsignedInt(ast::ty_u)),
435+
_ => None
436+
}
437+
}
438+
439+
#[deriving(Eq)]
440+
pub enum ReprAttr {
441+
ReprAny,
442+
ReprInt(Span, IntType),
443+
ReprExtern
444+
}
445+
446+
#[deriving(Eq)]
447+
pub enum IntType {
448+
SignedInt(ast::int_ty),
449+
UnsignedInt(ast::uint_ty)
450+
}
451+
452+
impl IntType {
453+
#[inline]
454+
pub fn is_signed(self) -> bool {
455+
match self {
456+
SignedInt(*) => true,
457+
UnsignedInt(*) => false
458+
}
459+
}
460+
}

0 commit comments

Comments
 (0)