about summary refs log tree commit diff
path: root/src/libsyntax/attr.rs
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 /src/libsyntax/attr.rs
parente6650c87a3800264a043b7f129e6a4841c4cc3f7 (diff)
downloadrust-f1124a2f55406be8e758488352c59ae9deef17b3.tar.gz
rust-f1124a2f55406be8e758488352c59ae9deef17b3.zip
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.
Diffstat (limited to 'src/libsyntax/attr.rs')
-rw-r--r--src/libsyntax/attr.rs96
1 files changed, 95 insertions, 1 deletions
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
+        }
+    }
+}