]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/attr/builtin.rs
Improve some compiletest documentation
[rust.git] / src / libsyntax / attr / builtin.rs
1 //! Parsing and validation of builtin attributes
2
3 use crate::ast::{self, Attribute, MetaItem, NestedMetaItem};
4 use crate::feature_gate::{Features, GatedCfg};
5 use crate::parse::ParseSess;
6
7 use errors::{Applicability, Handler};
8 use syntax_pos::{symbol::Symbol, Span};
9
10 use super::{mark_used, MetaItemKind};
11
12 enum AttrError {
13     MultipleItem(String),
14     UnknownMetaItem(String, &'static [&'static str]),
15     MissingSince,
16     MissingFeature,
17     MultipleStabilityLevels,
18     UnsupportedLiteral(&'static str, /* is_bytestr */ bool),
19 }
20
21 fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) {
22     let diag = &sess.span_diagnostic;
23     match error {
24         AttrError::MultipleItem(item) => span_err!(diag, span, E0538,
25                                                    "multiple '{}' items", item),
26         AttrError::UnknownMetaItem(item, expected) => {
27             let expected = expected
28                 .iter()
29                 .map(|name| format!("`{}`", name))
30                 .collect::<Vec<_>>();
31             struct_span_err!(diag, span, E0541, "unknown meta item '{}'", item)
32                 .span_label(span, format!("expected one of {}", expected.join(", ")))
33                 .emit();
34         }
35         AttrError::MissingSince => span_err!(diag, span, E0542, "missing 'since'"),
36         AttrError::MissingFeature => span_err!(diag, span, E0546, "missing 'feature'"),
37         AttrError::MultipleStabilityLevels => span_err!(diag, span, E0544,
38                                                         "multiple stability levels"),
39         AttrError::UnsupportedLiteral(
40             msg,
41             is_bytestr,
42         ) => {
43             let mut err = struct_span_err!(diag, span, E0565, "{}", msg);
44             if is_bytestr {
45                 if let Ok(lint_str) = sess.source_map().span_to_snippet(span) {
46                     err.span_suggestion(
47                         span,
48                         "consider removing the prefix",
49                         format!("{}", &lint_str[1..]),
50                         Applicability::MaybeIncorrect,
51                     );
52                 }
53             }
54             err.emit();
55         }
56     }
57 }
58
59 #[derive(Copy, Clone, Hash, PartialEq, RustcEncodable, RustcDecodable)]
60 pub enum InlineAttr {
61     None,
62     Hint,
63     Always,
64     Never,
65 }
66
67 #[derive(Copy, Clone, Hash, PartialEq, RustcEncodable, RustcDecodable)]
68 pub enum OptimizeAttr {
69     None,
70     Speed,
71     Size,
72 }
73
74 #[derive(Copy, Clone, PartialEq)]
75 pub enum UnwindAttr {
76     Allowed,
77     Aborts,
78 }
79
80 /// Determine what `#[unwind]` attribute is present in `attrs`, if any.
81 pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Option<UnwindAttr> {
82     attrs.iter().fold(None, |ia, attr| {
83         if attr.check_name("unwind") {
84             if let Some(meta) = attr.meta() {
85                 if let MetaItemKind::List(items) = meta.node {
86                     if items.len() == 1 {
87                         if items[0].check_name("allowed") {
88                             return Some(UnwindAttr::Allowed);
89                         } else if items[0].check_name("aborts") {
90                             return Some(UnwindAttr::Aborts);
91                         }
92                     }
93
94                     diagnostic.map(|d| {
95                         span_err!(d, attr.span, E0633, "malformed `#[unwind]` attribute");
96                     });
97                 }
98             }
99         }
100
101         ia
102     })
103 }
104
105 /// Represents the #[stable], #[unstable], #[rustc_{deprecated,const_unstable}] attributes.
106 #[derive(RustcEncodable, RustcDecodable, Clone, Debug, PartialEq, Eq, Hash)]
107 pub struct Stability {
108     pub level: StabilityLevel,
109     pub feature: Symbol,
110     pub rustc_depr: Option<RustcDeprecation>,
111     /// `None` means the function is stable but needs to be a stable const fn, too
112     /// `Some` contains the feature gate required to be able to use the function
113     /// as const fn
114     pub const_stability: Option<Symbol>,
115     /// whether the function has a `#[rustc_promotable]` attribute
116     pub promotable: bool,
117 }
118
119 /// The available stability levels.
120 #[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
121 pub enum StabilityLevel {
122     // Reason for the current stability level and the relevant rust-lang issue
123     Unstable { reason: Option<Symbol>, issue: u32 },
124     Stable { since: Symbol },
125 }
126
127 impl StabilityLevel {
128     pub fn is_unstable(&self) -> bool {
129         if let StabilityLevel::Unstable {..} = *self {
130             true
131         } else {
132             false
133         }
134     }
135     pub fn is_stable(&self) -> bool {
136         if let StabilityLevel::Stable {..} = *self {
137             true
138         } else {
139             false
140         }
141     }
142 }
143
144 #[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
145 pub struct RustcDeprecation {
146     pub since: Symbol,
147     pub reason: Symbol,
148     /// A text snippet used to completely replace any use of the deprecated item in an expression.
149     pub suggestion: Option<Symbol>,
150 }
151
152 /// Checks if `attrs` contains an attribute like `#![feature(feature_name)]`.
153 /// This will not perform any "sanity checks" on the form of the attributes.
154 pub fn contains_feature_attr(attrs: &[Attribute], feature_name: &str) -> bool {
155     attrs.iter().any(|item| {
156         item.check_name("feature") &&
157         item.meta_item_list().map(|list| {
158             list.iter().any(|mi| mi.is_word() && mi.check_name(feature_name))
159         }).unwrap_or(false)
160     })
161 }
162
163 /// Finds the first stability attribute. `None` if none exists.
164 pub fn find_stability(sess: &ParseSess, attrs: &[Attribute],
165                       item_sp: Span) -> Option<Stability> {
166     find_stability_generic(sess, attrs.iter(), item_sp)
167 }
168
169 fn find_stability_generic<'a, I>(sess: &ParseSess,
170                                  attrs_iter: I,
171                                  item_sp: Span)
172                                  -> Option<Stability>
173     where I: Iterator<Item = &'a Attribute>
174 {
175     use StabilityLevel::*;
176
177     let mut stab: Option<Stability> = None;
178     let mut rustc_depr: Option<RustcDeprecation> = None;
179     let mut rustc_const_unstable: Option<Symbol> = None;
180     let mut promotable = false;
181     let diagnostic = &sess.span_diagnostic;
182
183     'outer: for attr in attrs_iter {
184         if ![
185             "rustc_deprecated",
186             "rustc_const_unstable",
187             "unstable",
188             "stable",
189             "rustc_promotable",
190         ].iter().any(|&s| attr.path == s) {
191             continue // not a stability level
192         }
193
194         mark_used(attr);
195
196         let meta = attr.meta();
197
198         if attr.path == "rustc_promotable" {
199             promotable = true;
200         }
201         // attributes with data
202         else if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }) = meta {
203             let meta = meta.as_ref().unwrap();
204             let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
205                 if item.is_some() {
206                     handle_errors(sess, meta.span, AttrError::MultipleItem(meta.path.to_string()));
207                     return false
208                 }
209                 if let Some(v) = meta.value_str() {
210                     *item = Some(v);
211                     true
212                 } else {
213                     span_err!(diagnostic, meta.span, E0539, "incorrect meta item");
214                     false
215                 }
216             };
217
218             macro_rules! get_meta {
219                 ($($name:ident),+) => {
220                     $(
221                         let mut $name = None;
222                     )+
223                     for meta in metas {
224                         if let Some(mi) = meta.meta_item() {
225                             match mi.ident_str() {
226                                 $(
227                                     Some(stringify!($name))
228                                         => if !get(mi, &mut $name) { continue 'outer },
229                                 )+
230                                 _ => {
231                                     let expected = &[ $( stringify!($name) ),+ ];
232                                     handle_errors(
233                                         sess,
234                                         mi.span,
235                                         AttrError::UnknownMetaItem(mi.path.to_string(), expected),
236                                     );
237                                     continue 'outer
238                                 }
239                             }
240                         } else {
241                             handle_errors(
242                                 sess,
243                                 meta.span(),
244                                 AttrError::UnsupportedLiteral(
245                                     "unsupported literal",
246                                     false,
247                                 ),
248                             );
249                             continue 'outer
250                         }
251                     }
252                 }
253             }
254
255             match meta.ident_str().expect("not a stability level") {
256                 "rustc_deprecated" => {
257                     if rustc_depr.is_some() {
258                         span_err!(diagnostic, item_sp, E0540,
259                                   "multiple rustc_deprecated attributes");
260                         continue 'outer
261                     }
262
263                     get_meta!(since, reason, suggestion);
264
265                     match (since, reason) {
266                         (Some(since), Some(reason)) => {
267                             rustc_depr = Some(RustcDeprecation {
268                                 since,
269                                 reason,
270                                 suggestion,
271                             })
272                         }
273                         (None, _) => {
274                             handle_errors(sess, attr.span, AttrError::MissingSince);
275                             continue
276                         }
277                         _ => {
278                             span_err!(diagnostic, attr.span, E0543, "missing 'reason'");
279                             continue
280                         }
281                     }
282                 }
283                 "rustc_const_unstable" => {
284                     if rustc_const_unstable.is_some() {
285                         span_err!(diagnostic, item_sp, E0553,
286                                   "multiple rustc_const_unstable attributes");
287                         continue 'outer
288                     }
289
290                     get_meta!(feature);
291                     if let Some(feature) = feature {
292                         rustc_const_unstable = Some(feature);
293                     } else {
294                         span_err!(diagnostic, attr.span, E0629, "missing 'feature'");
295                         continue
296                     }
297                 }
298                 "unstable" => {
299                     if stab.is_some() {
300                         handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
301                         break
302                     }
303
304                     let mut feature = None;
305                     let mut reason = None;
306                     let mut issue = None;
307                     for meta in metas {
308                         if let Some(mi) = meta.meta_item() {
309                             match mi.ident_str() {
310                                 Some("feature") => if !get(mi, &mut feature) { continue 'outer },
311                                 Some("reason") => if !get(mi, &mut reason) { continue 'outer },
312                                 Some("issue") => if !get(mi, &mut issue) { continue 'outer },
313                                 _ => {
314                                     handle_errors(
315                                         sess,
316                                         meta.span(),
317                                         AttrError::UnknownMetaItem(
318                                             mi.path.to_string(),
319                                             &["feature", "reason", "issue"]
320                                         ),
321                                     );
322                                     continue 'outer
323                                 }
324                             }
325                         } else {
326                             handle_errors(
327                                 sess,
328                                 meta.span(),
329                                 AttrError::UnsupportedLiteral(
330                                     "unsupported literal",
331                                     false,
332                                 ),
333                             );
334                             continue 'outer
335                         }
336                     }
337
338                     match (feature, reason, issue) {
339                         (Some(feature), reason, Some(issue)) => {
340                             stab = Some(Stability {
341                                 level: Unstable {
342                                     reason,
343                                     issue: {
344                                         if let Ok(issue) = issue.as_str().parse() {
345                                             issue
346                                         } else {
347                                             span_err!(diagnostic, attr.span, E0545,
348                                                       "incorrect 'issue'");
349                                             continue
350                                         }
351                                     }
352                                 },
353                                 feature,
354                                 rustc_depr: None,
355                                 const_stability: None,
356                                 promotable: false,
357                             })
358                         }
359                         (None, _, _) => {
360                             handle_errors(sess, attr.span, AttrError::MissingFeature);
361                             continue
362                         }
363                         _ => {
364                             span_err!(diagnostic, attr.span, E0547, "missing 'issue'");
365                             continue
366                         }
367                     }
368                 }
369                 "stable" => {
370                     if stab.is_some() {
371                         handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
372                         break
373                     }
374
375                     let mut feature = None;
376                     let mut since = None;
377                     for meta in metas {
378                         match meta {
379                             NestedMetaItem::MetaItem(mi) => {
380                                 match mi.ident_str() {
381                                     Some("feature") =>
382                                         if !get(mi, &mut feature) { continue 'outer },
383                                     Some("since") =>
384                                         if !get(mi, &mut since) { continue 'outer },
385                                     _ => {
386                                         handle_errors(
387                                             sess,
388                                             meta.span(),
389                                             AttrError::UnknownMetaItem(
390                                                 mi.path.to_string(), &["since", "note"],
391                                             ),
392                                         );
393                                         continue 'outer
394                                     }
395                                 }
396                             },
397                             NestedMetaItem::Literal(lit) => {
398                                 handle_errors(
399                                     sess,
400                                     lit.span,
401                                     AttrError::UnsupportedLiteral(
402                                         "unsupported literal",
403                                         false,
404                                     ),
405                                 );
406                                 continue 'outer
407                             }
408                         }
409                     }
410
411                     match (feature, since) {
412                         (Some(feature), Some(since)) => {
413                             stab = Some(Stability {
414                                 level: Stable {
415                                     since,
416                                 },
417                                 feature,
418                                 rustc_depr: None,
419                                 const_stability: None,
420                                 promotable: false,
421                             })
422                         }
423                         (None, _) => {
424                             handle_errors(sess, attr.span, AttrError::MissingFeature);
425                             continue
426                         }
427                         _ => {
428                             handle_errors(sess, attr.span, AttrError::MissingSince);
429                             continue
430                         }
431                     }
432                 }
433                 _ => unreachable!()
434             }
435         }
436     }
437
438     // Merge the deprecation info into the stability info
439     if let Some(rustc_depr) = rustc_depr {
440         if let Some(ref mut stab) = stab {
441             stab.rustc_depr = Some(rustc_depr);
442         } else {
443             span_err!(diagnostic, item_sp, E0549,
444                       "rustc_deprecated attribute must be paired with \
445                        either stable or unstable attribute");
446         }
447     }
448
449     // Merge the const-unstable info into the stability info
450     if let Some(feature) = rustc_const_unstable {
451         if let Some(ref mut stab) = stab {
452             stab.const_stability = Some(feature);
453         } else {
454             span_err!(diagnostic, item_sp, E0630,
455                       "rustc_const_unstable attribute must be paired with \
456                        either stable or unstable attribute");
457         }
458     }
459
460     // Merge the const-unstable info into the stability info
461     if promotable {
462         if let Some(ref mut stab) = stab {
463             stab.promotable = true;
464         } else {
465             span_err!(diagnostic, item_sp, E0717,
466                       "rustc_promotable attribute must be paired with \
467                        either stable or unstable attribute");
468         }
469     }
470
471     stab
472 }
473
474 pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> {
475     super::first_attr_value_str_by_name(attrs, "crate_name")
476 }
477
478 /// Tests if a cfg-pattern matches the cfg set
479 pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) -> bool {
480     eval_condition(cfg, sess, &mut |cfg| {
481         if let (Some(feats), Some(gated_cfg)) = (features, GatedCfg::gate(cfg)) {
482             gated_cfg.check_and_emit(sess, feats);
483         }
484         let error = |span, msg| { sess.span_diagnostic.span_err(span, msg); true };
485         if cfg.path.segments.len() != 1 {
486             return error(cfg.path.span, "`cfg` predicate key must be an identifier");
487         }
488         match &cfg.node {
489             MetaItemKind::List(..) => {
490                 error(cfg.span, "unexpected parentheses after `cfg` predicate key")
491             }
492             MetaItemKind::NameValue(lit) if !lit.node.is_str() => {
493                 handle_errors(
494                     sess,
495                     lit.span,
496                     AttrError::UnsupportedLiteral(
497                         "literal in `cfg` predicate value must be a string",
498                         lit.node.is_bytestr()
499                     ),
500                 );
501                 true
502             }
503             MetaItemKind::NameValue(..) | MetaItemKind::Word => {
504                 let ident = cfg.ident().expect("multi-segment cfg predicate");
505                 sess.config.contains(&(ident.name, cfg.value_str()))
506             }
507         }
508     })
509 }
510
511 /// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
512 /// evaluate individual items.
513 pub fn eval_condition<F>(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F)
514                          -> bool
515     where F: FnMut(&ast::MetaItem) -> bool
516 {
517     match cfg.node {
518         ast::MetaItemKind::List(ref mis) => {
519             for mi in mis.iter() {
520                 if !mi.is_meta_item() {
521                     handle_errors(
522                         sess,
523                         mi.span(),
524                         AttrError::UnsupportedLiteral(
525                             "unsupported literal",
526                             false
527                         ),
528                     );
529                     return false;
530                 }
531             }
532
533             // The unwraps below may look dangerous, but we've already asserted
534             // that they won't fail with the loop above.
535             match cfg.ident_str() {
536                 Some("any") => mis.iter().any(|mi| {
537                     eval_condition(mi.meta_item().unwrap(), sess, eval)
538                 }),
539                 Some("all") => mis.iter().all(|mi| {
540                     eval_condition(mi.meta_item().unwrap(), sess, eval)
541                 }),
542                 Some("not") => {
543                     if mis.len() != 1 {
544                         span_err!(sess.span_diagnostic, cfg.span, E0536, "expected 1 cfg-pattern");
545                         return false;
546                     }
547
548                     !eval_condition(mis[0].meta_item().unwrap(), sess, eval)
549                 },
550                 _ => {
551                     span_err!(sess.span_diagnostic, cfg.span, E0537,
552                               "invalid predicate `{}`", cfg.path);
553                     false
554                 }
555             }
556         },
557         ast::MetaItemKind::Word | ast::MetaItemKind::NameValue(..) => {
558             eval(cfg)
559         }
560     }
561 }
562
563
564 #[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
565 pub struct Deprecation {
566     pub since: Option<Symbol>,
567     pub note: Option<Symbol>,
568 }
569
570 /// Finds the deprecation attribute. `None` if none exists.
571 pub fn find_deprecation(sess: &ParseSess, attrs: &[Attribute],
572                         item_sp: Span) -> Option<Deprecation> {
573     find_deprecation_generic(sess, attrs.iter(), item_sp)
574 }
575
576 fn find_deprecation_generic<'a, I>(sess: &ParseSess,
577                                    attrs_iter: I,
578                                    item_sp: Span)
579                                    -> Option<Deprecation>
580     where I: Iterator<Item = &'a Attribute>
581 {
582     let mut depr: Option<Deprecation> = None;
583     let diagnostic = &sess.span_diagnostic;
584
585     'outer: for attr in attrs_iter {
586         if !attr.check_name("deprecated") {
587             continue;
588         }
589
590         if depr.is_some() {
591             span_err!(diagnostic, item_sp, E0550, "multiple deprecated attributes");
592             break
593         }
594
595         let meta = attr.meta().unwrap();
596         depr = match &meta.node {
597             MetaItemKind::Word => Some(Deprecation { since: None, note: None }),
598             MetaItemKind::NameValue(..) => {
599                 meta.value_str().map(|note| {
600                     Deprecation { since: None, note: Some(note) }
601                 })
602             }
603             MetaItemKind::List(list) => {
604                 let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
605                     if item.is_some() {
606                         handle_errors(
607                             sess, meta.span, AttrError::MultipleItem(meta.path.to_string())
608                         );
609                         return false
610                     }
611                     if let Some(v) = meta.value_str() {
612                         *item = Some(v);
613                         true
614                     } else {
615                         if let Some(lit) = meta.name_value_literal() {
616                             handle_errors(
617                                 sess,
618                                 lit.span,
619                                 AttrError::UnsupportedLiteral(
620                                     "literal in `deprecated` \
621                                     value must be a string",
622                                     lit.node.is_bytestr()
623                                 ),
624                             );
625                         } else {
626                             span_err!(diagnostic, meta.span, E0551, "incorrect meta item");
627                         }
628
629                         false
630                     }
631                 };
632
633                 let mut since = None;
634                 let mut note = None;
635                 for meta in list {
636                     match meta {
637                         NestedMetaItem::MetaItem(mi) => {
638                             match mi.ident_str() {
639                                 Some("since") => if !get(mi, &mut since) { continue 'outer },
640                                 Some("note") => if !get(mi, &mut note) { continue 'outer },
641                                 _ => {
642                                     handle_errors(
643                                         sess,
644                                         meta.span(),
645                                         AttrError::UnknownMetaItem(mi.path.to_string(),
646                                                                    &["since", "note"]),
647                                     );
648                                     continue 'outer
649                                 }
650                             }
651                         }
652                         NestedMetaItem::Literal(lit) => {
653                             handle_errors(
654                                 sess,
655                                 lit.span,
656                                 AttrError::UnsupportedLiteral(
657                                     "item in `deprecated` must be a key/value pair",
658                                     false,
659                                 ),
660                             );
661                             continue 'outer
662                         }
663                     }
664                 }
665
666                 Some(Deprecation { since, note })
667             }
668         };
669     }
670
671     depr
672 }
673
674 #[derive(PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
675 pub enum ReprAttr {
676     ReprInt(IntType),
677     ReprC,
678     ReprPacked(u32),
679     ReprSimd,
680     ReprTransparent,
681     ReprAlign(u32),
682 }
683
684 #[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
685 pub enum IntType {
686     SignedInt(ast::IntTy),
687     UnsignedInt(ast::UintTy)
688 }
689
690 impl IntType {
691     #[inline]
692     pub fn is_signed(self) -> bool {
693         use IntType::*;
694
695         match self {
696             SignedInt(..) => true,
697             UnsignedInt(..) => false
698         }
699     }
700 }
701
702 /// Parse #[repr(...)] forms.
703 ///
704 /// Valid repr contents: any of the primitive integral type names (see
705 /// `int_type_of_word`, below) to specify enum discriminant type; `C`, to use
706 /// the same discriminant size that the corresponding C enum would or C
707 /// structure layout, `packed` to remove padding, and `transparent` to elegate representation
708 /// concerns to the only non-ZST field.
709 pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> {
710     use ReprAttr::*;
711
712     let mut acc = Vec::new();
713     let diagnostic = &sess.span_diagnostic;
714     if attr.path == "repr" {
715         if let Some(items) = attr.meta_item_list() {
716             mark_used(attr);
717             for item in items {
718                 if !item.is_meta_item() {
719                     handle_errors(
720                         sess,
721                         item.span(),
722                         AttrError::UnsupportedLiteral(
723                             "meta item in `repr` must be an identifier",
724                             false,
725                         ),
726                     );
727                     continue
728                 }
729
730                 let mut recognised = false;
731                 if item.is_word() {
732                     let hint = match item.ident_str() {
733                         Some("C") => Some(ReprC),
734                         Some("packed") => Some(ReprPacked(1)),
735                         Some("simd") => Some(ReprSimd),
736                         Some("transparent") => Some(ReprTransparent),
737                         name => name.and_then(|name| int_type_of_word(name)).map(ReprInt),
738                     };
739
740                     if let Some(h) = hint {
741                         recognised = true;
742                         acc.push(h);
743                     }
744                 } else if let Some((name, value)) = item.name_value_literal() {
745                     let parse_alignment = |node: &ast::LitKind| -> Result<u32, &'static str> {
746                         if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node {
747                             if literal.is_power_of_two() {
748                                 // rustc::ty::layout::Align restricts align to <= 2^29
749                                 if *literal <= 1 << 29 {
750                                     Ok(*literal as u32)
751                                 } else {
752                                     Err("larger than 2^29")
753                                 }
754                             } else {
755                                 Err("not a power of two")
756                             }
757                         } else {
758                             Err("not an unsuffixed integer")
759                         }
760                     };
761
762                     let mut literal_error = None;
763                     if name == "align" {
764                         recognised = true;
765                         match parse_alignment(&value.node) {
766                             Ok(literal) => acc.push(ReprAlign(literal)),
767                             Err(message) => literal_error = Some(message)
768                         };
769                     }
770                     else if name == "packed" {
771                         recognised = true;
772                         match parse_alignment(&value.node) {
773                             Ok(literal) => acc.push(ReprPacked(literal)),
774                             Err(message) => literal_error = Some(message)
775                         };
776                     }
777                     if let Some(literal_error) = literal_error {
778                         span_err!(diagnostic, item.span(), E0589,
779                                   "invalid `repr(align)` attribute: {}", literal_error);
780                     }
781                 } else {
782                     if let Some(meta_item) = item.meta_item() {
783                         if meta_item.check_name("align") {
784                             if let MetaItemKind::NameValue(ref value) = meta_item.node {
785                                 recognised = true;
786                                 let mut err = struct_span_err!(diagnostic, item.span(), E0693,
787                                     "incorrect `repr(align)` attribute format");
788                                 match value.node {
789                                     ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => {
790                                         err.span_suggestion(
791                                             item.span(),
792                                             "use parentheses instead",
793                                             format!("align({})", int),
794                                             Applicability::MachineApplicable
795                                         );
796                                     }
797                                     ast::LitKind::Str(s, _) => {
798                                         err.span_suggestion(
799                                             item.span(),
800                                             "use parentheses instead",
801                                             format!("align({})", s),
802                                             Applicability::MachineApplicable
803                                         );
804                                     }
805                                     _ => {}
806                                 }
807                                 err.emit();
808                             }
809                         }
810                     }
811                 }
812                 if !recognised {
813                     // Not a word we recognize
814                     span_err!(diagnostic, item.span(), E0552,
815                               "unrecognized representation hint");
816                 }
817             }
818         }
819     }
820     acc
821 }
822
823 fn int_type_of_word(s: &str) -> Option<IntType> {
824     use IntType::*;
825
826     match s {
827         "i8" => Some(SignedInt(ast::IntTy::I8)),
828         "u8" => Some(UnsignedInt(ast::UintTy::U8)),
829         "i16" => Some(SignedInt(ast::IntTy::I16)),
830         "u16" => Some(UnsignedInt(ast::UintTy::U16)),
831         "i32" => Some(SignedInt(ast::IntTy::I32)),
832         "u32" => Some(UnsignedInt(ast::UintTy::U32)),
833         "i64" => Some(SignedInt(ast::IntTy::I64)),
834         "u64" => Some(UnsignedInt(ast::UintTy::U64)),
835         "i128" => Some(SignedInt(ast::IntTy::I128)),
836         "u128" => Some(UnsignedInt(ast::UintTy::U128)),
837         "isize" => Some(SignedInt(ast::IntTy::Isize)),
838         "usize" => Some(UnsignedInt(ast::UintTy::Usize)),
839         _ => None
840     }
841 }