]>
Commit | Line | Data |
---|---|---|
b039eaaf SL |
1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | use session::Session; | |
12 | ||
13 | use syntax::ast; | |
b039eaaf SL |
14 | use syntax::visit; |
15 | use syntax::visit::Visitor; | |
16 | ||
17 | #[derive(Copy, Clone, PartialEq)] | |
18 | enum Target { | |
19 | Fn, | |
20 | Struct, | |
9e0c209e | 21 | Union, |
b039eaaf SL |
22 | Enum, |
23 | Other, | |
24 | } | |
25 | ||
26 | impl Target { | |
27 | fn from_item(item: &ast::Item) -> Target { | |
28 | match item.node { | |
7453a54e SL |
29 | ast::ItemKind::Fn(..) => Target::Fn, |
30 | ast::ItemKind::Struct(..) => Target::Struct, | |
9e0c209e | 31 | ast::ItemKind::Union(..) => Target::Union, |
7453a54e | 32 | ast::ItemKind::Enum(..) => Target::Enum, |
b039eaaf SL |
33 | _ => Target::Other, |
34 | } | |
35 | } | |
36 | } | |
37 | ||
38 | struct CheckAttrVisitor<'a> { | |
39 | sess: &'a Session, | |
40 | } | |
41 | ||
42 | impl<'a> CheckAttrVisitor<'a> { | |
43 | fn check_inline(&self, attr: &ast::Attribute, target: Target) { | |
44 | if target != Target::Fn { | |
9e0c209e SL |
45 | struct_span_err!(self.sess, attr.span, E0518, "attribute should be applied to function") |
46 | .span_label(attr.span, &format!("requires a function")) | |
47 | .emit(); | |
b039eaaf SL |
48 | } |
49 | } | |
50 | ||
51 | fn check_repr(&self, attr: &ast::Attribute, target: Target) { | |
52 | let words = match attr.meta_item_list() { | |
53 | Some(words) => words, | |
54 | None => { | |
55 | return; | |
56 | } | |
57 | }; | |
9e0c209e SL |
58 | |
59 | let mut conflicting_reprs = 0; | |
b039eaaf | 60 | for word in words { |
9e0c209e SL |
61 | |
62 | let name = match word.name() { | |
63 | Some(word) => word, | |
64 | None => continue, | |
65 | }; | |
66 | ||
67 | let (message, label) = match &*name { | |
b039eaaf | 68 | "C" => { |
9e0c209e SL |
69 | conflicting_reprs += 1; |
70 | if target != Target::Struct && | |
71 | target != Target::Union && | |
72 | target != Target::Enum { | |
73 | ("attribute should be applied to struct, enum or union", | |
74 | "a struct, enum or union") | |
75 | } else { | |
76 | continue | |
77 | } | |
78 | } | |
79 | "packed" => { | |
80 | // Do not increment conflicting_reprs here, because "packed" | |
81 | // can be used to modify another repr hint | |
82 | if target != Target::Struct && | |
83 | target != Target::Union { | |
84 | ("attribute should be applied to struct or union", | |
85 | "a struct or union") | |
92a42be0 SL |
86 | } else { |
87 | continue | |
b039eaaf SL |
88 | } |
89 | } | |
b039eaaf | 90 | "simd" => { |
9e0c209e | 91 | conflicting_reprs += 1; |
b039eaaf | 92 | if target != Target::Struct { |
9e0c209e SL |
93 | ("attribute should be applied to struct", |
94 | "a struct") | |
92a42be0 SL |
95 | } else { |
96 | continue | |
b039eaaf SL |
97 | } |
98 | } | |
99 | "i8" | "u8" | "i16" | "u16" | | |
100 | "i32" | "u32" | "i64" | "u64" | | |
101 | "isize" | "usize" => { | |
9e0c209e | 102 | conflicting_reprs += 1; |
b039eaaf | 103 | if target != Target::Enum { |
9e0c209e SL |
104 | ("attribute should be applied to enum", |
105 | "an enum") | |
92a42be0 SL |
106 | } else { |
107 | continue | |
b039eaaf SL |
108 | } |
109 | } | |
92a42be0 SL |
110 | _ => continue, |
111 | }; | |
9e0c209e SL |
112 | struct_span_err!(self.sess, attr.span, E0517, "{}", message) |
113 | .span_label(attr.span, &format!("requires {}", label)) | |
114 | .emit(); | |
115 | } | |
116 | if conflicting_reprs > 1 { | |
117 | span_warn!(self.sess, attr.span, E0566, | |
118 | "conflicting representation hints"); | |
b039eaaf SL |
119 | } |
120 | } | |
121 | ||
122 | fn check_attribute(&self, attr: &ast::Attribute, target: Target) { | |
123 | let name: &str = &attr.name(); | |
124 | match name { | |
125 | "inline" => self.check_inline(attr, target), | |
126 | "repr" => self.check_repr(attr, target), | |
127 | _ => (), | |
128 | } | |
129 | } | |
130 | } | |
131 | ||
3157f602 | 132 | impl<'a> Visitor for CheckAttrVisitor<'a> { |
b039eaaf SL |
133 | fn visit_item(&mut self, item: &ast::Item) { |
134 | let target = Target::from_item(item); | |
135 | for attr in &item.attrs { | |
136 | self.check_attribute(attr, target); | |
137 | } | |
7453a54e | 138 | visit::walk_item(self, item); |
b039eaaf SL |
139 | } |
140 | } | |
141 | ||
142 | pub fn check_crate(sess: &Session, krate: &ast::Crate) { | |
143 | visit::walk_crate(&mut CheckAttrVisitor { sess: sess }, krate); | |
144 | } |