Skip to content

Commit f1124a2

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 e6650c8 commit f1124a2

File tree

3 files changed

+133
-12
lines changed

3 files changed

+133
-12
lines changed

src/librustc/metadata/encoder.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
989989
encode_family(ebml_w, 't');
990990
encode_bounds_and_type(ebml_w, ecx, &lookup_item_type(tcx, def_id));
991991
encode_name(ecx, ebml_w, item.ident);
992+
encode_attributes(ebml_w, item.attrs);
992993
for v in (*enum_definition).variants.iter() {
993994
encode_variant_id(ebml_w, local_def(v.node.id));
994995
}

src/librustc/middle/ty.rs

Lines changed: 37 additions & 11 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;
@@ -4101,27 +4102,42 @@ pub fn lookup_trait_def(cx: ctxt, did: ast::DefId) -> @ty::TraitDef {
41014102
}
41024103
}
41034104

4104-
/// Determine whether an item is annotated with an attribute
4105-
pub fn has_attr(tcx: ctxt, did: DefId, attr: &str) -> bool {
4105+
/// Iterate over meta_items of a definition.
4106+
// (This should really be an iterator, but that would require csearch and
4107+
// decoder to use iterators instead of higher-order functions.)
4108+
pub fn each_attr(tcx: ctxt, did: DefId, f: &fn(@MetaItem) -> bool) -> bool {
41064109
if is_local(did) {
41074110
match tcx.items.find(&did.node) {
4108-
Some(
4109-
&ast_map::node_item(@ast::item {
4110-
attrs: ref attrs,
4111-
_
4112-
}, _)) => attr::contains_name(*attrs, attr),
4111+
Some(&ast_map::node_item(@ast::item {attrs: ref attrs, _}, _)) =>
4112+
attrs.iter().advance(|attr| f(attr.node.value)),
41134113
_ => tcx.sess.bug(format!("has_attr: {:?} is not an item",
4114-
did))
4114+
did))
41154115
}
41164116
} else {
4117-
let mut ret = false;
4117+
let mut cont = true;
41184118
do csearch::get_item_attrs(tcx.cstore, did) |meta_items| {
4119-
ret = ret || attr::contains_name(meta_items, attr);
4119+
if cont {
4120+
cont = meta_items.iter().advance(|ptrptr| f(*ptrptr));
4121+
}
41204122
}
4121-
ret
4123+
return cont;
41224124
}
41234125
}
41244126

4127+
/// Determine whether an item is annotated with an attribute
4128+
pub fn has_attr(tcx: ctxt, did: DefId, attr: &str) -> bool {
4129+
let mut found = false;
4130+
each_attr(tcx, did, |item| {
4131+
if attr == item.name() {
4132+
found = true;
4133+
false
4134+
} else {
4135+
true
4136+
}
4137+
});
4138+
return found;
4139+
}
4140+
41254141
/// Determine whether an item is annotated with `#[packed]`
41264142
pub fn lookup_packed(tcx: ctxt, did: DefId) -> bool {
41274143
has_attr(tcx, did, "packed")
@@ -4132,6 +4148,16 @@ pub fn lookup_simd(tcx: ctxt, did: DefId) -> bool {
41324148
has_attr(tcx, did, "simd")
41334149
}
41344150

4151+
// Obtain the the representation annotation for a definition.
4152+
pub fn lookup_repr_hint(tcx: ctxt, did: DefId) -> attr::ReprAttr {
4153+
let mut acc = attr::ReprAny;
4154+
ty::each_attr(tcx, did, |meta| {
4155+
acc = attr::find_repr_attr(tcx.sess.diagnostic(), meta, acc);
4156+
true
4157+
});
4158+
return acc;
4159+
}
4160+
41354161
// Look up a field ID, whether or not it's local
41364162
// Takes a list of type substs in case the struct is generic
41374163
pub fn lookup_field_type(tcx: ctxt,

src/libsyntax/attr.rs

Lines changed: 95 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,97 @@ 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_err(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 ignored")
408+
}
409+
}
410+
}
411+
// Not a word:
412+
_ => diagnostic.span_err(item.span, "unrecognized representation hint")
413+
}
414+
}
415+
}
416+
// Not a "repr" hint: ignore.
417+
_ => { }
418+
}
419+
return acc;
420+
}
421+
422+
fn int_type_of_word(s: &str) -> Option<IntType> {
423+
match s {
424+
"i8" => Some(SignedInt(ast::ty_i8)),
425+
"u8" => Some(UnsignedInt(ast::ty_u8)),
426+
"i16" => Some(SignedInt(ast::ty_i16)),
427+
"u16" => Some(UnsignedInt(ast::ty_u16)),
428+
"i32" => Some(SignedInt(ast::ty_i32)),
429+
"u32" => Some(UnsignedInt(ast::ty_u32)),
430+
"i64" => Some(SignedInt(ast::ty_i64)),
431+
"u64" => Some(UnsignedInt(ast::ty_u64)),
432+
"int" => Some(SignedInt(ast::ty_i)),
433+
"uint" => Some(UnsignedInt(ast::ty_u)),
434+
_ => None
435+
}
436+
}
437+
438+
#[deriving(Eq)]
439+
pub enum ReprAttr {
440+
ReprAny,
441+
ReprInt(Span, IntType),
442+
ReprExtern
443+
}
444+
445+
#[deriving(Eq)]
446+
pub enum IntType {
447+
SignedInt(ast::int_ty),
448+
UnsignedInt(ast::uint_ty)
449+
}
450+
451+
impl IntType {
452+
#[inline]
453+
pub fn is_signed(self) -> bool {
454+
match self {
455+
SignedInt(*) => true,
456+
UnsignedInt(*) => false
457+
}
458+
}
459+
}

0 commit comments

Comments
 (0)