about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlexis Beingessner <a.beingessner@gmail.com>2017-11-20 12:26:54 -0500
committerAlexis Beingessner <a.beingessner@gmail.com>2017-11-20 15:18:48 -0500
commit3d7a6fee79a7a42ac69b185806733dbbd1fc664e (patch)
tree1b4093f176fb2410afb2d813e7a978acf6a6556a
parent8293fe9fdf2d3398176297b82a72cd32d13538d8 (diff)
downloadrust-3d7a6fee79a7a42ac69b185806733dbbd1fc664e.tar.gz
rust-3d7a6fee79a7a42ac69b185806733dbbd1fc664e.zip
Prevent repr(C, u8) from triggering a warning on non-clike enums
-rw-r--r--src/librustc/hir/check_attr.rs30
1 files changed, 25 insertions, 5 deletions
diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs
index 05c371113b4..003255f8796 100644
--- a/src/librustc/hir/check_attr.rs
+++ b/src/librustc/hir/check_attr.rs
@@ -75,7 +75,9 @@ impl<'a> CheckAttrVisitor<'a> {
             }
         };
 
-        let mut conflicting_reprs = 0;
+        let mut int_reprs = 0;
+        let mut is_c = false;
+        let mut is_simd = false;
 
         for word in words {
 
@@ -86,7 +88,7 @@ impl<'a> CheckAttrVisitor<'a> {
 
             let (message, label) = match &*name.as_str() {
                 "C" => {
-                    conflicting_reprs += 1;
+                    is_c = true;
                     if target != Target::Struct &&
                             target != Target::Union &&
                             target != Target::Enum {
@@ -108,7 +110,7 @@ impl<'a> CheckAttrVisitor<'a> {
                     }
                 }
                 "simd" => {
-                    conflicting_reprs += 1;
+                    is_simd = true;
                     if target != Target::Struct {
                         ("attribute should be applied to struct",
                          "a struct")
@@ -128,7 +130,7 @@ impl<'a> CheckAttrVisitor<'a> {
                 "i8" | "u8" | "i16" | "u16" |
                 "i32" | "u32" | "i64" | "u64" |
                 "isize" | "usize" => {
-                    conflicting_reprs += 1;
+                    int_reprs += 1;
                     if target != Target::Enum {
                         ("attribute should be applied to enum",
                          "an enum")
@@ -142,7 +144,11 @@ impl<'a> CheckAttrVisitor<'a> {
                 .span_label(item.span, format!("not {}", label))
                 .emit();
         }
-        if conflicting_reprs > 1 {
+
+        // Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
+        if (int_reprs > 1)
+           || (is_simd && is_c)
+           || (int_reprs == 1 && is_c && is_c_like_enum(item)) {
             span_warn!(self.sess, attr.span, E0566,
                        "conflicting representation hints");
         }
@@ -162,3 +168,17 @@ impl<'a> Visitor<'a> for CheckAttrVisitor<'a> {
 pub fn check_crate(sess: &Session, krate: &ast::Crate) {
     visit::walk_crate(&mut CheckAttrVisitor { sess: sess }, krate);
 }
+
+fn is_c_like_enum(item: &ast::Item) -> bool {
+    if let ast::ItemKind::Enum(ref def, _) = item.node {
+        for variant in &def.variants {
+            match variant.node.data {
+                ast::VariantData::Unit(_) => { /* continue */ }
+                _ => { return false; }
+            }
+        }
+        true
+    } else {
+        false
+    }
+}