about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorCameron Hart <cameron.hart@gmail.com>2018-02-04 22:10:28 +1100
committerCameron Hart <cameron.hart@gmail.com>2018-04-11 22:13:13 +1000
commit15d1c4d2139611fcb87a2c802bd015b5f4f0aed8 (patch)
tree5822428a8e6a8ef94f13ea80f22d8ec01545f33b /src/libsyntax
parentca26ef321c44358404ef788d315c4557eb015fb2 (diff)
downloadrust-15d1c4d2139611fcb87a2c802bd015b5f4f0aed8.tar.gz
rust-15d1c4d2139611fcb87a2c802bd015b5f4f0aed8.zip
Implementation of `#[repr(packed(n))]` RFC 1399.
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/attr.rs46
-rw-r--r--src/libsyntax/feature_gate.rs19
2 files changed, 45 insertions, 20 deletions
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 2812e1238e9..c68a743303a 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -993,7 +993,7 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr>
                     let word = &*mi.ident.name.as_str();
                     let hint = match word {
                         "C" => Some(ReprC),
-                        "packed" => Some(ReprPacked),
+                        "packed" => Some(ReprPacked(1)),
                         "simd" => Some(ReprSimd),
                         "transparent" => Some(ReprTransparent),
                         _ => match int_type_of_word(word) {
@@ -1009,27 +1009,41 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr>
                         acc.push(h);
                     }
                 } else if let Some((name, value)) = item.name_value_literal() {
-                    if name == "align" {
-                        recognised = true;
-                        let mut align_error = None;
-                        if let ast::LitKind::Int(align, ast::LitIntType::Unsuffixed) = value.node {
-                            if align.is_power_of_two() {
+                    let parse_alignment = |node: &ast::LitKind| -> Result<u32, &'static str> {
+                        if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node {
+                            if literal.is_power_of_two() {
                                 // rustc::ty::layout::Align restricts align to <= 2147483647
-                                if align <= 2147483647 {
-                                    acc.push(ReprAlign(align as u32));
+                                if *literal <= 2147483647 {
+                                    Ok(*literal as u32)
                                 } else {
-                                    align_error = Some("larger than 2147483647");
+                                    Err("larger than 2147483647")
                                 }
                             } else {
-                                align_error = Some("not a power of two");
+                                Err("not a power of two")
                             }
                         } else {
-                            align_error = Some("not an unsuffixed integer");
-                        }
-                        if let Some(align_error) = align_error {
-                            span_err!(diagnostic, item.span, E0589,
-                                      "invalid `repr(align)` attribute: {}", align_error);
+                            Err("not an unsuffixed integer")
                         }
+                    };
+
+                    let mut literal_error = None;
+                    if name == "align" {
+                        recognised = true;
+                        match parse_alignment(&value.node) {
+                            Ok(literal) => acc.push(ReprAlign(literal)),
+                            Err(message) => literal_error = Some(message)
+                        };
+                    }
+                    else if name == "packed" {
+                        recognised = true;
+                        match parse_alignment(&value.node) {
+                            Ok(literal) => acc.push(ReprPacked(literal)),
+                            Err(message) => literal_error = Some(message)
+                        };
+                    }
+                    if let Some(literal_error) = literal_error {
+                        span_err!(diagnostic, item.span, E0589,
+                                  "invalid `repr(align)` attribute: {}", literal_error);
                     }
                 }
                 if !recognised {
@@ -1065,7 +1079,7 @@ fn int_type_of_word(s: &str) -> Option<IntType> {
 pub enum ReprAttr {
     ReprInt(IntType),
     ReprC,
-    ReprPacked,
+    ReprPacked(u32),
     ReprSimd,
     ReprTransparent,
     ReprAlign(u32),
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 0a3cd66d897..df39757d1eb 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -432,6 +432,9 @@ declare_features! (
     // Parentheses in patterns
     (active, pattern_parentheses, "1.26.0", None, None),
 
+    // Allows `#[repr(packed)]` attribute on structs
+    (active, repr_packed, "1.26.0", Some(33158), None),
+
     // `use path as _;` and `extern crate c as _;`
     (active, underscore_imports, "1.26.0", Some(48216), None),
 
@@ -1439,11 +1442,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             }
         }
 
-        // allow attr_literals in #[repr(align(x))]
-        let mut is_repr_align = false;
+        // allow attr_literals in #[repr(align(x))] and #[repr(packed(n))]
+        let mut allow_attr_literal = false;
         if attr.path == "repr" {
             if let Some(content) = attr.meta_item_list() {
-                is_repr_align = content.iter().any(|c| c.check_name("align"));
+                allow_attr_literal = content.iter().any(
+                    |c| c.check_name("align") || c.check_name("packed"));
             }
         }
 
@@ -1451,7 +1455,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             return
         }
 
-        if !is_repr_align {
+        if !allow_attr_literal {
             let meta = panictry!(attr.parse_meta(self.context.parse_sess));
             if contains_novel_literal(&meta) {
                 gate_feature_post!(&self, attr_literals, attr.span,
@@ -1535,6 +1539,13 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                                                "the `#[repr(transparent)]` attribute \
                                                is experimental");
                         }
+                        if let Some((name, _)) = item.name_value_literal() {
+                            if name == "packed" {
+                                gate_feature_post!(&self, repr_packed, attr.span,
+                                                   "the `#[repr(packed(n))]` attribute \
+                                                   is experimental");
+                            }
+                        }
                     }
                 }
             }