1- use hir:: intravisit:: walk_inline_asm;
21use rustc_ast:: InlineAsmTemplatePiece ;
32use rustc_data_structures:: stable_set:: FxHashSet ;
43use rustc_errors:: struct_span_err;
54use rustc_hir as hir;
6- use rustc_hir:: def:: { DefKind , Res } ;
7- use rustc_hir:: def_id:: DefId ;
8- use rustc_hir:: intravisit:: { self , Visitor } ;
95use rustc_index:: vec:: Idx ;
106use rustc_middle:: ty:: layout:: { LayoutError , SizeSkeleton } ;
11- use rustc_middle:: ty:: { self , FloatTy , IntTy , Ty , TyCtxt , UintTy } ;
7+ use rustc_middle:: ty:: { self , FloatTy , InferTy , IntTy , Ty , TyCtxt , TypeFoldable , UintTy } ;
128use rustc_session:: lint;
13- use rustc_span:: { sym , Span , Symbol , DUMMY_SP } ;
9+ use rustc_span:: { Span , Symbol , DUMMY_SP } ;
1410use rustc_target:: abi:: { Pointer , VariantIdx } ;
15- use rustc_target:: asm:: { InlineAsmRegOrRegClass , InlineAsmType } ;
11+ use rustc_target:: asm:: { InlineAsmReg , InlineAsmRegClass , InlineAsmRegOrRegClass , InlineAsmType } ;
1612
17- struct ItemVisitor < ' tcx > {
18- tcx : TyCtxt < ' tcx > ,
19- }
20-
21- struct ExprVisitor < ' tcx > {
22- tcx : TyCtxt < ' tcx > ,
23- typeck_results : & ' tcx ty:: TypeckResults < ' tcx > ,
24- param_env : ty:: ParamEnv < ' tcx > ,
25- }
13+ use super :: FnCtxt ;
2614
2715/// If the type is `Option<T>`, it will return `T`, otherwise
2816/// the type itself. Works on most `Option`-like types.
@@ -51,14 +39,15 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
5139 ty
5240}
5341
54- impl < ' tcx > ExprVisitor < ' tcx > {
55- fn def_id_is_transmute ( & self , def_id : DefId ) -> bool {
56- self . tcx . is_intrinsic ( def_id) && self . tcx . item_name ( def_id) == sym:: transmute
57- }
58-
59- fn check_transmute ( & self , span : Span , from : Ty < ' tcx > , to : Ty < ' tcx > ) {
60- let sk_from = SizeSkeleton :: compute ( from, self . tcx , self . param_env ) ;
61- let sk_to = SizeSkeleton :: compute ( to, self . tcx , self . param_env ) ;
42+ impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
43+ pub fn check_transmute ( & self , span : Span , from : Ty < ' tcx > , to : Ty < ' tcx > ) {
44+ let convert = |ty : Ty < ' tcx > | {
45+ let ty = self . resolve_vars_if_possible ( ty) ;
46+ let ty = self . tcx . normalize_erasing_regions ( self . param_env , ty) ;
47+ ( SizeSkeleton :: compute ( ty, self . tcx , self . param_env ) , ty)
48+ } ;
49+ let ( sk_from, from) = convert ( from) ;
50+ let ( sk_to, to) = convert ( to) ;
6251
6352 // Check for same size using the skeletons.
6453 if let ( Ok ( sk_from) , Ok ( sk_to) ) = ( sk_from, sk_to) {
@@ -130,7 +119,8 @@ impl<'tcx> ExprVisitor<'tcx> {
130119 target_features : & FxHashSet < Symbol > ,
131120 ) -> Option < InlineAsmType > {
132121 // Check the type against the allowed types for inline asm.
133- let ty = self . typeck_results . expr_ty_adjusted ( expr) ;
122+ let ty = self . typeck_results . borrow ( ) . expr_ty_adjusted ( expr) ;
123+ let ty = self . resolve_vars_if_possible ( ty) ;
134124 let asm_ty_isize = match self . tcx . sess . target . pointer_width {
135125 16 => InlineAsmType :: I16 ,
136126 32 => InlineAsmType :: I32 ,
@@ -143,10 +133,24 @@ impl<'tcx> ExprVisitor<'tcx> {
143133 ty:: Error ( _) => return None ,
144134 ty:: Int ( IntTy :: I8 ) | ty:: Uint ( UintTy :: U8 ) => Some ( InlineAsmType :: I8 ) ,
145135 ty:: Int ( IntTy :: I16 ) | ty:: Uint ( UintTy :: U16 ) => Some ( InlineAsmType :: I16 ) ,
136+ // Somewhat of a hack: fallback in the presence of errors does not actually
137+ // fall back to i32, but to ty::Error. For integer inference variables this
138+ // means that they don't get any fallback and stay as `{integer}`.
139+ // Since compilation can't succeed anyway, it's fine to use this to avoid printing
140+ // "cannot use value of type `{integer}`", even though that would absolutely
141+ // work due due i32 fallback if the current function had no other errors.
142+ ty:: Infer ( InferTy :: IntVar ( _) ) => {
143+ assert ! ( self . is_tainted_by_errors( ) ) ;
144+ Some ( InlineAsmType :: I32 )
145+ }
146146 ty:: Int ( IntTy :: I32 ) | ty:: Uint ( UintTy :: U32 ) => Some ( InlineAsmType :: I32 ) ,
147147 ty:: Int ( IntTy :: I64 ) | ty:: Uint ( UintTy :: U64 ) => Some ( InlineAsmType :: I64 ) ,
148148 ty:: Int ( IntTy :: I128 ) | ty:: Uint ( UintTy :: U128 ) => Some ( InlineAsmType :: I128 ) ,
149149 ty:: Int ( IntTy :: Isize ) | ty:: Uint ( UintTy :: Usize ) => Some ( asm_ty_isize) ,
150+ ty:: Infer ( InferTy :: FloatVar ( _) ) => {
151+ assert ! ( self . is_tainted_by_errors( ) ) ;
152+ Some ( InlineAsmType :: F32 )
153+ }
150154 ty:: Float ( FloatTy :: F32 ) => Some ( InlineAsmType :: F32 ) ,
151155 ty:: Float ( FloatTy :: F64 ) => Some ( InlineAsmType :: F64 ) ,
152156 ty:: FnPtr ( _) => Some ( asm_ty_isize) ,
@@ -199,6 +203,11 @@ impl<'tcx> ExprVisitor<'tcx> {
199203 return None ;
200204 } ;
201205
206+ if ty. has_infer_types_or_consts ( ) {
207+ assert ! ( self . is_tainted_by_errors( ) ) ;
208+ return None ;
209+ }
210+
202211 // Check that the type implements Copy. The only case where this can
203212 // possibly fail is for SIMD types which don't #[derive(Copy)].
204213 if !ty. is_copy_modulo_regions ( self . tcx . at ( DUMMY_SP ) , self . param_env ) {
@@ -221,10 +230,10 @@ impl<'tcx> ExprVisitor<'tcx> {
221230 if in_asm_ty != asm_ty {
222231 let msg = "incompatible types for asm inout argument" ;
223232 let mut err = self . tcx . sess . struct_span_err ( vec ! [ in_expr. span, expr. span] , msg) ;
224- err . span_label (
225- in_expr . span ,
226- & format ! ( "type `{}`" , self . typeck_results . expr_ty_adjusted ( in_expr ) ) ,
227- ) ;
233+
234+ let in_expr_ty = self . typeck_results . borrow ( ) . expr_ty_adjusted ( in_expr ) ;
235+ let in_expr_ty = self . resolve_vars_if_possible ( in_expr_ty ) ;
236+ err . span_label ( in_expr . span , & format ! ( "type `{in_expr_ty}`" ) ) ;
228237 err. span_label ( expr. span , & format ! ( "type `{ty}`" ) ) ;
229238 err. note (
230239 "asm inout arguments must have the same type, \
@@ -328,12 +337,14 @@ impl<'tcx> ExprVisitor<'tcx> {
328337 Some ( asm_ty)
329338 }
330339
331- fn check_asm ( & self , asm : & hir:: InlineAsm < ' tcx > , hir_id : hir:: HirId ) {
340+ pub fn check_asm ( & self , asm : & hir:: InlineAsm < ' tcx > , enclosing_id : hir:: HirId ) {
332341 let hir = self . tcx . hir ( ) ;
333- let enclosing_id = hir. enclosing_body_owner ( hir_id) ;
334342 let enclosing_def_id = hir. local_def_id ( enclosing_id) . to_def_id ( ) ;
335343 let target_features = self . tcx . asm_target_features ( enclosing_def_id) ;
336- let asm_arch = self . tcx . sess . asm_arch . unwrap ( ) ;
344+ let Some ( asm_arch) = self . tcx . sess . asm_arch else {
345+ self . tcx . sess . delay_span_bug ( DUMMY_SP , "target architecture does not support asm" ) ;
346+ return ;
347+ } ;
337348 for ( idx, ( op, op_sp) ) in asm. operands . iter ( ) . enumerate ( ) {
338349 // Validate register classes against currently enabled target
339350 // features. We check that at least one type is available for
@@ -349,6 +360,9 @@ impl<'tcx> ExprVisitor<'tcx> {
349360 // Some explicit registers cannot be used depending on the
350361 // target. Reject those here.
351362 if let InlineAsmRegOrRegClass :: Reg ( reg) = reg {
363+ if let InlineAsmReg :: Err = reg {
364+ return ;
365+ }
352366 if let Err ( msg) = reg. validate (
353367 asm_arch,
354368 self . tcx . sess . relocation_model ( ) ,
@@ -365,6 +379,9 @@ impl<'tcx> ExprVisitor<'tcx> {
365379 if !op. is_clobber ( ) {
366380 let mut missing_required_features = vec ! [ ] ;
367381 let reg_class = reg. reg_class ( ) ;
382+ if let InlineAsmRegClass :: Err = reg_class {
383+ return ;
384+ }
368385 for & ( _, feature) in reg_class. supported_types ( asm_arch) {
369386 match feature {
370387 Some ( feature) => {
@@ -473,33 +490,6 @@ impl<'tcx> ExprVisitor<'tcx> {
473490 ) ;
474491 }
475492 }
476- // These are checked in ItemVisitor.
477- hir:: InlineAsmOperand :: Const { .. }
478- | hir:: InlineAsmOperand :: SymFn { .. }
479- | hir:: InlineAsmOperand :: SymStatic { .. } => { }
480- }
481- }
482- }
483- }
484-
485- impl < ' tcx > Visitor < ' tcx > for ItemVisitor < ' tcx > {
486- fn visit_nested_body ( & mut self , body_id : hir:: BodyId ) {
487- let owner_def_id = self . tcx . hir ( ) . body_owner_def_id ( body_id) ;
488- let body = self . tcx . hir ( ) . body ( body_id) ;
489- let param_env = self . tcx . param_env ( owner_def_id. to_def_id ( ) ) ;
490- let typeck_results = self . tcx . typeck ( owner_def_id) ;
491- ExprVisitor { tcx : self . tcx , param_env, typeck_results } . visit_body ( body) ;
492- self . visit_body ( body) ;
493- }
494-
495- fn visit_inline_asm ( & mut self , asm : & ' tcx hir:: InlineAsm < ' tcx > , id : hir:: HirId ) {
496- for ( op, op_sp) in asm. operands . iter ( ) {
497- match * op {
498- // These are checked in ExprVisitor.
499- hir:: InlineAsmOperand :: In { .. }
500- | hir:: InlineAsmOperand :: Out { .. }
501- | hir:: InlineAsmOperand :: InOut { .. }
502- | hir:: InlineAsmOperand :: SplitInOut { .. } => { }
503493 // No special checking is needed for these:
504494 // - Typeck has checked that Const operands are integers.
505495 // - AST lowering guarantees that SymStatic points to a static.
@@ -525,31 +515,5 @@ impl<'tcx> Visitor<'tcx> for ItemVisitor<'tcx> {
525515 }
526516 }
527517 }
528- walk_inline_asm ( self , asm, id) ;
529- }
530- }
531-
532- impl < ' tcx > Visitor < ' tcx > for ExprVisitor < ' tcx > {
533- fn visit_expr ( & mut self , expr : & ' tcx hir:: Expr < ' tcx > ) {
534- match expr. kind {
535- hir:: ExprKind :: Path ( ref qpath) => {
536- let res = self . typeck_results . qpath_res ( qpath, expr. hir_id ) ;
537- if let Res :: Def ( DefKind :: Fn , did) = res
538- && self . def_id_is_transmute ( did)
539- {
540- let typ = self . typeck_results . node_type ( expr. hir_id ) ;
541- let sig = typ. fn_sig ( self . tcx ) ;
542- let from = sig. inputs ( ) . skip_binder ( ) [ 0 ] ;
543- let to = sig. output ( ) . skip_binder ( ) ;
544- self . check_transmute ( expr. span , from, to) ;
545- }
546- }
547-
548- hir:: ExprKind :: InlineAsm ( asm) => self . check_asm ( asm, expr. hir_id ) ,
549-
550- _ => { }
551- }
552-
553- intravisit:: walk_expr ( self , expr) ;
554518 }
555519}
0 commit comments