about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJed Davis <jld@panix.com>2013-05-24 18:08:45 -0400
committerJed Davis <jld@panix.com>2013-10-29 09:09:19 -0700
commitf1124a2f55406be8e758488352c59ae9deef17b3 (patch)
tree06cd816c346551e82db912d0edc7b4872a36de57
parente6650c87a3800264a043b7f129e6a4841c4cc3f7 (diff)
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.
-rw-r--r--src/librustc/metadata/encoder.rs1
-rw-r--r--src/librustc/middle/ty.rs48
-rw-r--r--src/libsyntax/attr.rs96
3 files changed, 133 insertions, 12 deletions
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index ade5bfe85e4..86c4ca0158f 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 39aa6c5e396..3945fcd80ae 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 40b7ff29e24..e538e09c056 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<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
+        }
+    }
+}