@@ -3,6 +3,7 @@ use std::assert_matches::debug_assert_matches;
33use rustc_abi:: FieldIdx ;
44use rustc_ast:: InlineAsmTemplatePiece ;
55use rustc_data_structures:: fx:: FxIndexSet ;
6+ use rustc_hir:: def_id:: DefId ;
67use rustc_hir:: { self as hir, LangItem } ;
78use rustc_middle:: bug;
89use rustc_middle:: ty:: { self , FloatTy , IntTy , Ty , TyCtxt , TypeVisitableExt , UintTy } ;
@@ -21,6 +22,12 @@ pub struct InlineAsmCtxt<'a, 'tcx> {
2122 get_operand_ty : Box < dyn Fn ( & ' tcx hir:: Expr < ' tcx > ) -> Ty < ' tcx > + ' a > ,
2223}
2324
25+ enum NonAsmTypeReason < ' tcx > {
26+ UnevaluatedSIMDArrayLength ( DefId , ty:: Const < ' tcx > ) ,
27+ Invalid ( Ty < ' tcx > ) ,
28+ InvalidElement ( DefId , Ty < ' tcx > ) ,
29+ }
30+
2431impl < ' a , ' tcx > InlineAsmCtxt < ' a , ' tcx > {
2532 pub fn new_global_asm ( tcx : TyCtxt < ' tcx > ) -> Self {
2633 InlineAsmCtxt {
@@ -56,7 +63,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
5663 false
5764 }
5865
59- fn get_asm_ty ( & self , ty : Ty < ' tcx > ) -> Option < InlineAsmType > {
66+ fn get_asm_ty ( & self , ty : Ty < ' tcx > ) -> Result < InlineAsmType , NonAsmTypeReason < ' tcx > > {
6067 let asm_ty_isize = match self . tcx . sess . target . pointer_width {
6168 16 => InlineAsmType :: I16 ,
6269 32 => InlineAsmType :: I32 ,
@@ -65,64 +72,62 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
6572 } ;
6673
6774 match * ty. kind ( ) {
68- ty:: Int ( IntTy :: I8 ) | ty:: Uint ( UintTy :: U8 ) => Some ( InlineAsmType :: I8 ) ,
69- ty:: Int ( IntTy :: I16 ) | ty:: Uint ( UintTy :: U16 ) => Some ( InlineAsmType :: I16 ) ,
70- ty:: Int ( IntTy :: I32 ) | ty:: Uint ( UintTy :: U32 ) => Some ( InlineAsmType :: I32 ) ,
71- ty:: Int ( IntTy :: I64 ) | ty:: Uint ( UintTy :: U64 ) => Some ( InlineAsmType :: I64 ) ,
72- ty:: Int ( IntTy :: I128 ) | ty:: Uint ( UintTy :: U128 ) => Some ( InlineAsmType :: I128 ) ,
73- ty:: Int ( IntTy :: Isize ) | ty:: Uint ( UintTy :: Usize ) => Some ( asm_ty_isize) ,
74- ty:: Float ( FloatTy :: F16 ) => Some ( InlineAsmType :: F16 ) ,
75- ty:: Float ( FloatTy :: F32 ) => Some ( InlineAsmType :: F32 ) ,
76- ty:: Float ( FloatTy :: F64 ) => Some ( InlineAsmType :: F64 ) ,
77- ty:: Float ( FloatTy :: F128 ) => Some ( InlineAsmType :: F128 ) ,
78- ty:: FnPtr ( ..) => Some ( asm_ty_isize) ,
79- ty:: RawPtr ( ty, _) if self . is_thin_ptr_ty ( ty) => Some ( asm_ty_isize) ,
75+ ty:: Int ( IntTy :: I8 ) | ty:: Uint ( UintTy :: U8 ) => Ok ( InlineAsmType :: I8 ) ,
76+ ty:: Int ( IntTy :: I16 ) | ty:: Uint ( UintTy :: U16 ) => Ok ( InlineAsmType :: I16 ) ,
77+ ty:: Int ( IntTy :: I32 ) | ty:: Uint ( UintTy :: U32 ) => Ok ( InlineAsmType :: I32 ) ,
78+ ty:: Int ( IntTy :: I64 ) | ty:: Uint ( UintTy :: U64 ) => Ok ( InlineAsmType :: I64 ) ,
79+ ty:: Int ( IntTy :: I128 ) | ty:: Uint ( UintTy :: U128 ) => Ok ( InlineAsmType :: I128 ) ,
80+ ty:: Int ( IntTy :: Isize ) | ty:: Uint ( UintTy :: Usize ) => Ok ( asm_ty_isize) ,
81+ ty:: Float ( FloatTy :: F16 ) => Ok ( InlineAsmType :: F16 ) ,
82+ ty:: Float ( FloatTy :: F32 ) => Ok ( InlineAsmType :: F32 ) ,
83+ ty:: Float ( FloatTy :: F64 ) => Ok ( InlineAsmType :: F64 ) ,
84+ ty:: Float ( FloatTy :: F128 ) => Ok ( InlineAsmType :: F128 ) ,
85+ ty:: FnPtr ( ..) => Ok ( asm_ty_isize) ,
86+ ty:: RawPtr ( ty, _) if self . is_thin_ptr_ty ( ty) => Ok ( asm_ty_isize) ,
8087 ty:: Adt ( adt, args) if adt. repr ( ) . simd ( ) => {
8188 let fields = & adt. non_enum_variant ( ) . fields ;
82- let elem_ty = fields[ FieldIdx :: ZERO ] . ty ( self . tcx , args) ;
89+ let field = & fields[ FieldIdx :: ZERO ] ;
90+ let elem_ty = field. ty ( self . tcx , args) ;
8391
8492 let ( size, ty) = match elem_ty. kind ( ) {
8593 ty:: Array ( ty, len) => {
94+ let len = self . tcx . normalize_erasing_regions ( self . typing_env , * len) ;
8695 if let Some ( len) = len. try_to_target_usize ( self . tcx ) {
8796 ( len, * ty)
8897 } else {
89- return None ;
98+ return Err ( NonAsmTypeReason :: UnevaluatedSIMDArrayLength (
99+ field. did , len,
100+ ) ) ;
90101 }
91102 }
92103 _ => ( fields. len ( ) as u64 , elem_ty) ,
93104 } ;
94105
95106 match ty. kind ( ) {
96- ty:: Int ( IntTy :: I8 ) | ty:: Uint ( UintTy :: U8 ) => Some ( InlineAsmType :: VecI8 ( size) ) ,
97- ty:: Int ( IntTy :: I16 ) | ty:: Uint ( UintTy :: U16 ) => {
98- Some ( InlineAsmType :: VecI16 ( size) )
99- }
100- ty:: Int ( IntTy :: I32 ) | ty:: Uint ( UintTy :: U32 ) => {
101- Some ( InlineAsmType :: VecI32 ( size) )
102- }
103- ty:: Int ( IntTy :: I64 ) | ty:: Uint ( UintTy :: U64 ) => {
104- Some ( InlineAsmType :: VecI64 ( size) )
105- }
107+ ty:: Int ( IntTy :: I8 ) | ty:: Uint ( UintTy :: U8 ) => Ok ( InlineAsmType :: VecI8 ( size) ) ,
108+ ty:: Int ( IntTy :: I16 ) | ty:: Uint ( UintTy :: U16 ) => Ok ( InlineAsmType :: VecI16 ( size) ) ,
109+ ty:: Int ( IntTy :: I32 ) | ty:: Uint ( UintTy :: U32 ) => Ok ( InlineAsmType :: VecI32 ( size) ) ,
110+ ty:: Int ( IntTy :: I64 ) | ty:: Uint ( UintTy :: U64 ) => Ok ( InlineAsmType :: VecI64 ( size) ) ,
106111 ty:: Int ( IntTy :: I128 ) | ty:: Uint ( UintTy :: U128 ) => {
107- Some ( InlineAsmType :: VecI128 ( size) )
112+ Ok ( InlineAsmType :: VecI128 ( size) )
108113 }
109114 ty:: Int ( IntTy :: Isize ) | ty:: Uint ( UintTy :: Usize ) => {
110- Some ( match self . tcx . sess . target . pointer_width {
115+ Ok ( match self . tcx . sess . target . pointer_width {
111116 16 => InlineAsmType :: VecI16 ( size) ,
112117 32 => InlineAsmType :: VecI32 ( size) ,
113118 64 => InlineAsmType :: VecI64 ( size) ,
114119 width => bug ! ( "unsupported pointer width: {width}" ) ,
115120 } )
116121 }
117- ty:: Float ( FloatTy :: F16 ) => Some ( InlineAsmType :: VecF16 ( size) ) ,
118- ty:: Float ( FloatTy :: F32 ) => Some ( InlineAsmType :: VecF32 ( size) ) ,
119- ty:: Float ( FloatTy :: F64 ) => Some ( InlineAsmType :: VecF64 ( size) ) ,
120- ty:: Float ( FloatTy :: F128 ) => Some ( InlineAsmType :: VecF128 ( size) ) ,
121- _ => None ,
122+ ty:: Float ( FloatTy :: F16 ) => Ok ( InlineAsmType :: VecF16 ( size) ) ,
123+ ty:: Float ( FloatTy :: F32 ) => Ok ( InlineAsmType :: VecF32 ( size) ) ,
124+ ty:: Float ( FloatTy :: F64 ) => Ok ( InlineAsmType :: VecF64 ( size) ) ,
125+ ty:: Float ( FloatTy :: F128 ) => Ok ( InlineAsmType :: VecF128 ( size) ) ,
126+ _ => Err ( NonAsmTypeReason :: InvalidElement ( field . did , ty ) ) ,
122127 }
123128 }
124129 ty:: Infer ( _) => bug ! ( "unexpected infer ty in asm operand" ) ,
125- _ => None ,
130+ _ => Err ( NonAsmTypeReason :: Invalid ( ty ) ) ,
126131 }
127132 }
128133
@@ -163,17 +168,42 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
163168 }
164169 _ => self . get_asm_ty ( ty) ,
165170 } ;
166- let Some ( asm_ty) = asm_ty else {
167- let msg = format ! ( "cannot use value of type `{ty}` for inline assembly" ) ;
168- self . tcx
169- . dcx ( )
170- . struct_span_err ( expr. span , msg)
171- . with_note (
172- "only integers, floats, SIMD vectors, pointers and function pointers \
173- can be used as arguments for inline assembly",
174- )
175- . emit ( ) ;
176- return None ;
171+ let asm_ty = match asm_ty {
172+ Ok ( asm_ty) => asm_ty,
173+ Err ( reason) => {
174+ match reason {
175+ NonAsmTypeReason :: UnevaluatedSIMDArrayLength ( did, len) => {
176+ let msg = format ! ( "cannot evaluate SIMD vector length `{len}`" ) ;
177+ self . tcx
178+ . dcx ( )
179+ . struct_span_err ( self . tcx . def_span ( did) , msg)
180+ . with_span_note (
181+ expr. span ,
182+ "SIMD vector length needs to be known statically for use in `asm!`" ,
183+ )
184+ . emit ( ) ;
185+ }
186+ NonAsmTypeReason :: Invalid ( ty) => {
187+ let msg = format ! ( "cannot use value of type `{ty}` for inline assembly" ) ;
188+ self . tcx . dcx ( ) . struct_span_err ( expr. span , msg) . with_note (
189+ "only integers, floats, SIMD vectors, pointers and function pointers \
190+ can be used as arguments for inline assembly",
191+ ) . emit ( ) ;
192+ }
193+ NonAsmTypeReason :: InvalidElement ( did, ty) => {
194+ let msg = format ! (
195+ "cannot use SIMD vector with element type `{ty}` for inline assembly"
196+ ) ;
197+ self . tcx . dcx ( )
198+ . struct_span_err ( self . tcx . def_span ( did) , msg) . with_span_note (
199+ expr. span ,
200+ "only integers, floats, SIMD vectors, pointers and function pointers \
201+ can be used as arguments for inline assembly",
202+ ) . emit ( ) ;
203+ }
204+ }
205+ return None ;
206+ }
177207 } ;
178208
179209 // Check that the type implements Copy. The only case where this can
0 commit comments