@@ -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