14
14
//! conflicts between multiple such attributes attached to the same
15
15
//! item.
16
16
17
+ use syntax_pos:: Span ;
17
18
use ty:: TyCtxt ;
18
19
19
20
use hir;
@@ -27,6 +28,8 @@ enum Target {
27
28
Enum ,
28
29
Const ,
29
30
ForeignMod ,
31
+ Expression ,
32
+ Statement ,
30
33
Other ,
31
34
}
32
35
@@ -62,7 +65,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
62
65
let mut has_wasm_import_module = false ;
63
66
for attr in & item. attrs {
64
67
if attr. check_name ( "inline" ) {
65
- self . check_inline ( attr, item, target)
68
+ self . check_inline ( attr, & item. span , target)
66
69
} else if attr. check_name ( "wasm_import_module" ) {
67
70
has_wasm_import_module = true ;
68
71
if attr. value_str ( ) . is_none ( ) {
@@ -99,13 +102,13 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
99
102
}
100
103
101
104
/// Check if an `#[inline]` is applied to a function.
102
- fn check_inline ( & self , attr : & hir:: Attribute , item : & hir :: Item , target : Target ) {
105
+ fn check_inline ( & self , attr : & hir:: Attribute , span : & Span , target : Target ) {
103
106
if target != Target :: Fn {
104
107
struct_span_err ! ( self . tcx. sess,
105
108
attr. span,
106
109
E0518 ,
107
110
"attribute should be applied to function" )
108
- . span_label ( item . span , "not a function" )
111
+ . span_label ( * span, "not a function" )
109
112
. emit ( ) ;
110
113
}
111
114
}
@@ -196,10 +199,12 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
196
199
}
197
200
_ => continue ,
198
201
} ;
199
- struct_span_err ! ( self . tcx. sess, hint. span, E0517 ,
200
- "attribute should be applied to {}" , allowed_targets)
201
- . span_label ( item. span , format ! ( "not {} {}" , article, allowed_targets) )
202
- . emit ( ) ;
202
+ self . emit_repr_error (
203
+ hint. span ,
204
+ item. span ,
205
+ & format ! ( "attribute should be applied to {}" , allowed_targets) ,
206
+ & format ! ( "not {} {}" , article, allowed_targets) ,
207
+ )
203
208
}
204
209
205
210
// Just point at all repr hints if there are any incompatibilities.
@@ -221,17 +226,85 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
221
226
"conflicting representation hints" ) ;
222
227
}
223
228
}
229
+
230
+ fn emit_repr_error (
231
+ & self ,
232
+ hint_span : Span ,
233
+ label_span : Span ,
234
+ hint_message : & str ,
235
+ label_message : & str ,
236
+ ) {
237
+ struct_span_err ! ( self . tcx. sess, hint_span, E0517 , "{}" , hint_message)
238
+ . span_label ( label_span, label_message)
239
+ . emit ( ) ;
240
+ }
241
+
242
+ fn check_stmt_attributes ( & self , stmt : & hir:: Stmt ) {
243
+ // When checking statements ignore expressions, they will be checked later
244
+ if let hir:: Stmt_ :: StmtDecl ( _, _) = stmt. node {
245
+ for attr in stmt. node . attrs ( ) {
246
+ if attr. check_name ( "inline" ) {
247
+ self . check_inline ( attr, & stmt. span , Target :: Statement ) ;
248
+ }
249
+ if attr. check_name ( "repr" ) {
250
+ self . emit_repr_error (
251
+ attr. span ,
252
+ stmt. span ,
253
+ & format ! ( "attribute should not be applied to statements" ) ,
254
+ & format ! ( "not a struct, enum or union" ) ,
255
+ ) ;
256
+ }
257
+ }
258
+ }
259
+ }
260
+
261
+ fn check_expr_attributes ( & self , expr : & hir:: Expr ) {
262
+ use hir:: Expr_ :: * ;
263
+ match expr. node {
264
+ // Assignments, Calls and Structs were handled by Items and Statements
265
+ ExprCall ( ..) |
266
+ ExprAssign ( ..) |
267
+ ExprMethodCall ( ..) |
268
+ ExprStruct ( ..) => return ,
269
+ _ => ( ) ,
270
+ }
271
+
272
+ for attr in expr. attrs . iter ( ) {
273
+ if attr. check_name ( "inline" ) {
274
+ self . check_inline ( attr, & expr. span , Target :: Expression ) ;
275
+ }
276
+ if attr. check_name ( "repr" ) {
277
+ self . emit_repr_error (
278
+ attr. span ,
279
+ expr. span ,
280
+ & format ! ( "attribute should not be applied to an expression" ) ,
281
+ & format ! ( "not a struct, enum or union" ) ,
282
+ ) ;
283
+ }
284
+ }
285
+ }
224
286
}
225
287
226
288
impl < ' a , ' tcx > Visitor < ' tcx > for CheckAttrVisitor < ' a , ' tcx > {
227
289
fn nested_visit_map < ' this > ( & ' this mut self ) -> NestedVisitorMap < ' this , ' tcx > {
228
- NestedVisitorMap :: None
290
+ NestedVisitorMap :: OnlyBodies ( & self . tcx . hir )
229
291
}
230
292
231
293
fn visit_item ( & mut self , item : & ' tcx hir:: Item ) {
232
294
let target = Target :: from_item ( item) ;
233
295
self . check_attributes ( item, target) ;
234
- intravisit:: walk_item ( self , item) ;
296
+ intravisit:: walk_item ( self , item)
297
+ }
298
+
299
+
300
+ fn visit_stmt ( & mut self , stmt : & ' tcx hir:: Stmt ) {
301
+ self . check_stmt_attributes ( stmt) ;
302
+ intravisit:: walk_stmt ( self , stmt)
303
+ }
304
+
305
+ fn visit_expr ( & mut self , expr : & ' tcx hir:: Expr ) {
306
+ self . check_expr_attributes ( expr) ;
307
+ intravisit:: walk_expr ( self , expr)
235
308
}
236
309
}
237
310
0 commit comments