From f1124a2f55406be8e758488352c59ae9deef17b3 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Fri, 24 May 2013 18:08:45 -0400 Subject: [PATCH] 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. --- src/librustc/metadata/encoder.rs | 1 + src/librustc/middle/ty.rs | 48 ++++++++++++---- src/libsyntax/attr.rs | 96 +++++++++++++++++++++++++++++++- 3 files changed, 133 insertions(+), 12 deletions(-) diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index ade5bfe85e4bc..86c4ca0158f19 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -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)); } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 39aa6c5e39637..3945fcd80ae8a 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -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, diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 40b7ff29e241a..e538e09c05692 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -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 { + 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 + } + } +}