@@ -47,14 +47,15 @@ struct CheckAttrVisitor<'a> {
47
47
48
48
impl < ' a > CheckAttrVisitor < ' a > {
49
49
/// Check any attribute.
50
- fn check_attribute ( & self , attr : & ast :: Attribute , item : & ast:: Item , target : Target ) {
51
- if let Some ( name ) = attr . name ( ) {
52
- match & * name. as_str ( ) {
53
- "inline" => self . check_inline ( attr , item , target ) ,
54
- "repr" => self . check_repr ( attr, item, target) ,
55
- _ => ( ) ,
50
+ fn check_attributes ( & self , item : & ast:: Item , target : Target ) {
51
+ for attr in & item . attrs {
52
+ if let Some ( name) = attr . name ( ) {
53
+ if name == "inline" {
54
+ self . check_inline ( attr, item, target)
55
+ }
56
56
}
57
57
}
58
+ self . check_repr ( item, target) ;
58
59
}
59
60
60
61
/// Check if an `#[inline]` is applied to a function.
@@ -66,63 +67,67 @@ impl<'a> CheckAttrVisitor<'a> {
66
67
}
67
68
}
68
69
69
- /// Check if an `#[repr]` attr is valid.
70
- fn check_repr ( & self , attr : & ast:: Attribute , item : & ast:: Item , target : Target ) {
71
- let words = match attr. meta_item_list ( ) {
72
- Some ( words) => words,
73
- None => {
74
- return ;
75
- }
76
- } ;
70
+ /// Check if the `#[repr]` attributes on `item` are valid.
71
+ fn check_repr ( & self , item : & ast:: Item , target : Target ) {
72
+ // Extract the names of all repr hints, e.g., [foo, bar, align] for:
73
+ // ```
74
+ // #[repr(foo)]
75
+ // #[repr(bar, align(8))]
76
+ // ```
77
+ let hints: Vec < _ > = item. attrs
78
+ . iter ( )
79
+ . filter ( |attr| match attr. name ( ) {
80
+ Some ( name) => name == "repr" ,
81
+ None => false ,
82
+ } )
83
+ . filter_map ( |attr| attr. meta_item_list ( ) )
84
+ . flat_map ( |hints| hints)
85
+ . collect ( ) ;
77
86
78
87
let mut int_reprs = 0 ;
79
88
let mut is_c = false ;
80
89
let mut is_simd = false ;
81
90
82
- for word in words {
83
-
84
- let name = match word. name ( ) {
85
- Some ( word) => word,
86
- None => continue ,
91
+ for hint in & hints {
92
+ let name = if let Some ( name) = hint. name ( ) {
93
+ name
94
+ } else {
95
+ // Invalid repr hint like repr(42). We don't check for unrecognized hints here
96
+ // (libsyntax does that), so just ignore it.
97
+ continue ;
87
98
} ;
88
99
89
- let ( message , label ) = match & * name. as_str ( ) {
100
+ let ( article , allowed_targets ) = match & * name. as_str ( ) {
90
101
"C" => {
91
102
is_c = true ;
92
103
if target != Target :: Struct &&
93
104
target != Target :: Union &&
94
105
target != Target :: Enum {
95
- ( "attribute should be applied to struct, enum or union" ,
96
- "a struct, enum or union" )
106
+ ( "a" , "struct, enum or union" )
97
107
} else {
98
108
continue
99
109
}
100
110
}
101
111
"packed" => {
102
- // Do not increment conflicting_reprs here, because "packed"
103
- // can be used to modify another repr hint
104
112
if target != Target :: Struct &&
105
113
target != Target :: Union {
106
- ( "attribute should be applied to struct or union" ,
107
- "a struct or union" )
114
+ ( "a" , "struct or union" )
108
115
} else {
109
116
continue
110
117
}
111
118
}
112
119
"simd" => {
113
120
is_simd = true ;
114
121
if target != Target :: Struct {
115
- ( "attribute should be applied to struct" ,
116
- "a struct" )
122
+ ( "a" , "struct" )
117
123
} else {
118
124
continue
119
125
}
120
126
}
121
127
"align" => {
122
128
if target != Target :: Struct &&
123
129
target != Target :: Union {
124
- ( "attribute should be applied to struct or union" ,
125
- "a struct or union" )
130
+ ( "a" , "struct or union" )
126
131
} else {
127
132
continue
128
133
}
@@ -132,24 +137,27 @@ impl<'a> CheckAttrVisitor<'a> {
132
137
"isize" | "usize" => {
133
138
int_reprs += 1 ;
134
139
if target != Target :: Enum {
135
- ( "attribute should be applied to enum" ,
136
- "an enum" )
140
+ ( "an" , "enum" )
137
141
} else {
138
142
continue
139
143
}
140
144
}
141
145
_ => continue ,
142
146
} ;
143
- struct_span_err ! ( self . sess, attr. span, E0517 , "{}" , message)
144
- . span_label ( item. span , format ! ( "not {}" , label) )
147
+ struct_span_err ! ( self . sess, hint. span, E0517 ,
148
+ "attribute should be applied to {}" , allowed_targets)
149
+ . span_label ( item. span , format ! ( "not {} {}" , article, allowed_targets) )
145
150
. emit ( ) ;
146
151
}
147
152
148
153
// Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
149
154
if ( int_reprs > 1 )
150
155
|| ( is_simd && is_c)
151
156
|| ( int_reprs == 1 && is_c && is_c_like_enum ( item) ) {
152
- span_warn ! ( self . sess, attr. span, E0566 ,
157
+ // Just point at all repr hints. This is not ideal, but tracking precisely which ones
158
+ // are at fault is a huge hassle.
159
+ let spans: Vec < _ > = hints. iter ( ) . map ( |hint| hint. span ) . collect ( ) ;
160
+ span_warn ! ( self . sess, spans, E0566 ,
153
161
"conflicting representation hints" ) ;
154
162
}
155
163
}
@@ -158,9 +166,7 @@ impl<'a> CheckAttrVisitor<'a> {
158
166
impl < ' a > Visitor < ' a > for CheckAttrVisitor < ' a > {
159
167
fn visit_item ( & mut self , item : & ' a ast:: Item ) {
160
168
let target = Target :: from_item ( item) ;
161
- for attr in & item. attrs {
162
- self . check_attribute ( attr, item, target) ;
163
- }
169
+ self . check_attributes ( item, target) ;
164
170
visit:: walk_item ( self , item) ;
165
171
}
166
172
}
0 commit comments