@@ -141,6 +141,7 @@ impl ExprVisitor<'tcx> {
141
141
template : & [ InlineAsmTemplatePiece ] ,
142
142
is_input : bool ,
143
143
tied_input : Option < ( & hir:: Expr < ' tcx > , Option < InlineAsmType > ) > ,
144
+ target_features : & [ Symbol ] ,
144
145
) -> Option < InlineAsmType > {
145
146
// Check the type against the allowed types for inline asm.
146
147
let ty = self . typeck_results . expr_ty_adjusted ( expr) ;
@@ -283,17 +284,20 @@ impl ExprVisitor<'tcx> {
283
284
} ;
284
285
285
286
// Check whether the selected type requires a target feature. Note that
286
- // this is different from the feature check we did earlier in AST
287
- // lowering. While AST lowering checked that this register class is
288
- // usable at all with the currently enabled features, some types may
289
- // only be usable with a register class when a certain feature is
290
- // enabled. We check this here since it depends on the results of typeck.
287
+ // this is different from the feature check we did earlier. While the
288
+ // previous check checked that this register class is usable at all
289
+ // with the currently enabled features, some types may only be usable
290
+ // with a register class when a certain feature is enabled. We check
291
+ // this here since it depends on the results of typeck.
291
292
//
292
293
// Also note that this check isn't run when the operand type is never
293
- // (!). In that case we still need the earlier check in AST lowering to
294
- // verify that the register class is usable at all.
294
+ // (!). In that case we still need the earlier check to verify that the
295
+ // register class is usable at all.
295
296
if let Some ( feature) = feature {
296
- if !self . tcx . sess . target_features . contains ( & Symbol :: intern ( feature) ) {
297
+ let feat_sym = Symbol :: intern ( feature) ;
298
+ if !self . tcx . sess . target_features . contains ( & feat_sym)
299
+ && !target_features. contains ( & feat_sym)
300
+ {
297
301
let msg = & format ! ( "`{}` target feature is not enabled" , feature) ;
298
302
let mut err = self . tcx . sess . struct_span_err ( expr. span , msg) ;
299
303
err. note ( & format ! (
@@ -349,23 +353,122 @@ impl ExprVisitor<'tcx> {
349
353
Some ( asm_ty)
350
354
}
351
355
352
- fn check_asm ( & self , asm : & hir:: InlineAsm < ' tcx > ) {
353
- for ( idx, ( op, _) ) in asm. operands . iter ( ) . enumerate ( ) {
356
+ fn check_asm ( & self , asm : & hir:: InlineAsm < ' tcx > , hir_id : hir:: HirId ) {
357
+ let hir = self . tcx . hir ( ) ;
358
+ let enclosing_id = hir. enclosing_body_owner ( hir_id) ;
359
+ let enclosing_def_id = hir. local_def_id ( enclosing_id) . to_def_id ( ) ;
360
+ let attrs = self . tcx . codegen_fn_attrs ( enclosing_def_id) ;
361
+ for ( idx, ( op, op_sp) ) in asm. operands . iter ( ) . enumerate ( ) {
362
+ // Validate register classes against currently enabled target
363
+ // features. We check that at least one type is available for
364
+ // the enabled features.
365
+ //
366
+ // We ignore target feature requirements for clobbers: if the
367
+ // feature is disabled then the compiler doesn't care what we
368
+ // do with the registers.
369
+ //
370
+ // Note that this is only possible for explicit register
371
+ // operands, which cannot be used in the asm string.
372
+ if let Some ( reg) = op. reg ( ) {
373
+ if !op. is_clobber ( ) {
374
+ let mut missing_required_features = vec ! [ ] ;
375
+ let reg_class = reg. reg_class ( ) ;
376
+ for & ( _, feature) in reg_class. supported_types ( self . tcx . sess . asm_arch . unwrap ( ) )
377
+ {
378
+ match feature {
379
+ Some ( feature) => {
380
+ let feat_sym = Symbol :: intern ( feature) ;
381
+ if self . tcx . sess . target_features . contains ( & feat_sym)
382
+ || attrs. target_features . contains ( & feat_sym)
383
+ {
384
+ missing_required_features. clear ( ) ;
385
+ break ;
386
+ } else {
387
+ missing_required_features. push ( feature) ;
388
+ }
389
+ }
390
+ None => {
391
+ missing_required_features. clear ( ) ;
392
+ break ;
393
+ }
394
+ }
395
+ }
396
+
397
+ // We are sorting primitive strs here and can use unstable sort here
398
+ missing_required_features. sort_unstable ( ) ;
399
+ missing_required_features. dedup ( ) ;
400
+ match & missing_required_features[ ..] {
401
+ [ ] => { }
402
+ [ feature] => {
403
+ let msg = format ! (
404
+ "register class `{}` requires the `{}` target feature" ,
405
+ reg_class. name( ) ,
406
+ feature
407
+ ) ;
408
+ self . tcx . sess . struct_span_err ( * op_sp, & msg) . emit ( ) ;
409
+ // register isn't enabled, don't do more checks
410
+ continue ;
411
+ }
412
+ features => {
413
+ let msg = format ! (
414
+ "register class `{}` requires at least one of the following target features: {}" ,
415
+ reg_class. name( ) ,
416
+ features. join( ", " )
417
+ ) ;
418
+ self . tcx . sess . struct_span_err ( * op_sp, & msg) . emit ( ) ;
419
+ // register isn't enabled, don't do more checks
420
+ continue ;
421
+ }
422
+ }
423
+ }
424
+ }
425
+
354
426
match * op {
355
427
hir:: InlineAsmOperand :: In { reg, ref expr } => {
356
- self . check_asm_operand_type ( idx, reg, expr, asm. template , true , None ) ;
428
+ self . check_asm_operand_type (
429
+ idx,
430
+ reg,
431
+ expr,
432
+ asm. template ,
433
+ true ,
434
+ None ,
435
+ & attrs. target_features ,
436
+ ) ;
357
437
}
358
438
hir:: InlineAsmOperand :: Out { reg, late : _, ref expr } => {
359
439
if let Some ( expr) = expr {
360
- self . check_asm_operand_type ( idx, reg, expr, asm. template , false , None ) ;
440
+ self . check_asm_operand_type (
441
+ idx,
442
+ reg,
443
+ expr,
444
+ asm. template ,
445
+ false ,
446
+ None ,
447
+ & attrs. target_features ,
448
+ ) ;
361
449
}
362
450
}
363
451
hir:: InlineAsmOperand :: InOut { reg, late : _, ref expr } => {
364
- self . check_asm_operand_type ( idx, reg, expr, asm. template , false , None ) ;
452
+ self . check_asm_operand_type (
453
+ idx,
454
+ reg,
455
+ expr,
456
+ asm. template ,
457
+ false ,
458
+ None ,
459
+ & attrs. target_features ,
460
+ ) ;
365
461
}
366
462
hir:: InlineAsmOperand :: SplitInOut { reg, late : _, ref in_expr, ref out_expr } => {
367
- let in_ty =
368
- self . check_asm_operand_type ( idx, reg, in_expr, asm. template , true , None ) ;
463
+ let in_ty = self . check_asm_operand_type (
464
+ idx,
465
+ reg,
466
+ in_expr,
467
+ asm. template ,
468
+ true ,
469
+ None ,
470
+ & attrs. target_features ,
471
+ ) ;
369
472
if let Some ( out_expr) = out_expr {
370
473
self . check_asm_operand_type (
371
474
idx,
@@ -374,6 +477,7 @@ impl ExprVisitor<'tcx> {
374
477
asm. template ,
375
478
false ,
376
479
Some ( ( in_expr, in_ty) ) ,
480
+ & attrs. target_features ,
377
481
) ;
378
482
}
379
483
}
@@ -422,7 +526,7 @@ impl Visitor<'tcx> for ExprVisitor<'tcx> {
422
526
}
423
527
}
424
528
425
- hir:: ExprKind :: InlineAsm ( asm) => self . check_asm ( asm) ,
529
+ hir:: ExprKind :: InlineAsm ( asm) => self . check_asm ( asm, expr . hir_id ) ,
426
530
427
531
_ => { }
428
532
}
0 commit comments