@@ -141,6 +141,7 @@ impl ExprVisitor<'tcx> {
141141 template : & [ InlineAsmTemplatePiece ] ,
142142 is_input : bool ,
143143 tied_input : Option < ( & hir:: Expr < ' tcx > , Option < InlineAsmType > ) > ,
144+ target_features : & [ Symbol ] ,
144145 ) -> Option < InlineAsmType > {
145146 // Check the type against the allowed types for inline asm.
146147 let ty = self . typeck_results . expr_ty_adjusted ( expr) ;
@@ -283,17 +284,20 @@ impl ExprVisitor<'tcx> {
283284 } ;
284285
285286 // 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.
291292 //
292293 // 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.
295296 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+ {
297301 let msg = & format ! ( "`{}` target feature is not enabled" , feature) ;
298302 let mut err = self . tcx . sess . struct_span_err ( expr. span , msg) ;
299303 err. note ( & format ! (
@@ -349,23 +353,122 @@ impl ExprVisitor<'tcx> {
349353 Some ( asm_ty)
350354 }
351355
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+
354426 match * op {
355427 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+ ) ;
357437 }
358438 hir:: InlineAsmOperand :: Out { reg, late : _, ref expr } => {
359439 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+ ) ;
361449 }
362450 }
363451 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+ ) ;
365461 }
366462 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+ ) ;
369472 if let Some ( out_expr) = out_expr {
370473 self . check_asm_operand_type (
371474 idx,
@@ -374,6 +477,7 @@ impl ExprVisitor<'tcx> {
374477 asm. template ,
375478 false ,
376479 Some ( ( in_expr, in_ty) ) ,
480+ & attrs. target_features ,
377481 ) ;
378482 }
379483 }
@@ -422,7 +526,7 @@ impl Visitor<'tcx> for ExprVisitor<'tcx> {
422526 }
423527 }
424528
425- hir:: ExprKind :: InlineAsm ( asm) => self . check_asm ( asm) ,
529+ hir:: ExprKind :: InlineAsm ( asm) => self . check_asm ( asm, expr . hir_id ) ,
426530
427531 _ => { }
428532 }
0 commit comments