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