3
3
4
4
use std:: cmp;
5
5
6
+ use chalk_ir:: TyKind ;
7
+ use hir_def:: resolver:: HasResolver ;
8
+ use hir_expand:: mod_path:: ModPath ;
9
+
6
10
use super :: * ;
7
11
8
12
mod simd;
@@ -186,44 +190,24 @@ impl Evaluator<'_> {
186
190
BeginPanic => Err ( MirEvalError :: Panic ( "<unknown-panic-payload>" . to_string ( ) ) ) ,
187
191
PanicFmt => {
188
192
let message = ( || {
189
- let arguments_struct =
190
- self . db . lang_item ( self . crate_id , LangItem :: FormatArguments ) ?. as_struct ( ) ?;
191
- let arguments_layout = self
192
- . layout_adt ( arguments_struct. into ( ) , Substitution :: empty ( Interner ) )
193
- . ok ( ) ?;
194
- let arguments_field_pieces =
195
- self . db . struct_data ( arguments_struct) . variant_data . field ( & name ! [ pieces] ) ?;
196
- let pieces_offset = arguments_layout
197
- . fields
198
- . offset ( u32:: from ( arguments_field_pieces. into_raw ( ) ) as usize )
199
- . bytes_usize ( ) ;
200
- let ptr_size = self . ptr_size ( ) ;
201
- let arg = args. next ( ) ?;
202
- let pieces_array_addr =
203
- Address :: from_bytes ( & arg[ pieces_offset..pieces_offset + ptr_size] ) . ok ( ) ?;
204
- let pieces_array_len = usize:: from_le_bytes (
205
- ( & arg[ pieces_offset + ptr_size..pieces_offset + 2 * ptr_size] )
206
- . try_into ( )
207
- . ok ( ) ?,
208
- ) ;
209
- let mut message = "" . to_string ( ) ;
210
- for i in 0 ..pieces_array_len {
211
- let piece_ptr_addr = pieces_array_addr. offset ( 2 * i * ptr_size) ;
212
- let piece_addr =
213
- Address :: from_bytes ( self . read_memory ( piece_ptr_addr, ptr_size) . ok ( ) ?)
214
- . ok ( ) ?;
215
- let piece_len = usize:: from_le_bytes (
216
- self . read_memory ( piece_ptr_addr. offset ( ptr_size) , ptr_size)
217
- . ok ( ) ?
218
- . try_into ( )
219
- . ok ( ) ?,
220
- ) ;
221
- let piece_data = self . read_memory ( piece_addr, piece_len) . ok ( ) ?;
222
- message += & std:: string:: String :: from_utf8_lossy ( piece_data) ;
223
- }
224
- Some ( message)
193
+ let x = self . db . crate_def_map ( self . crate_id ) . crate_root ( ) ;
194
+ let resolver = x. resolver ( self . db . upcast ( ) ) ;
195
+ let Some ( format_fn) = resolver. resolve_path_in_value_ns_fully (
196
+ self . db . upcast ( ) ,
197
+ & hir_def:: path:: Path :: from_known_path_with_no_generic ( ModPath :: from_segments (
198
+ hir_expand:: mod_path:: PathKind :: Abs ,
199
+ [ name ! [ std] , name ! [ fmt] , name ! [ format] ] . into_iter ( ) ,
200
+ ) ) ,
201
+ ) else {
202
+ not_supported ! ( "std::fmt::format not found" ) ;
203
+ } ;
204
+ let hir_def:: resolver:: ValueNs :: FunctionId ( format_fn) = format_fn else { not_supported ! ( "std::fmt::format is not a function" ) } ;
205
+ let message_string = self . interpret_mir ( & * self . db . mir_body ( format_fn. into ( ) ) . map_err ( |e| MirEvalError :: MirLowerError ( format_fn, e) ) ?, args. cloned ( ) ) ?;
206
+ let addr = Address :: from_bytes ( & message_string[ self . ptr_size ( ) ..2 * self . ptr_size ( ) ] ) ?;
207
+ let size = from_bytes ! ( usize , message_string[ 2 * self . ptr_size( ) ..] ) ;
208
+ Ok ( std:: string:: String :: from_utf8_lossy ( self . read_memory ( addr, size) ?) . into_owned ( ) )
225
209
} ) ( )
226
- . unwrap_or_else ( || "< format- args-evaluation-failed>" . to_string ( ) ) ;
210
+ . unwrap_or_else ( |e| format ! ( "Failed to render panic format args: {e:?}" ) ) ;
227
211
Err ( MirEvalError :: Panic ( message) )
228
212
}
229
213
SliceLen => {
@@ -544,6 +528,13 @@ impl Evaluator<'_> {
544
528
let size = self . size_of_sized ( ty, locals, "size_of arg" ) ?;
545
529
destination. write_from_bytes ( self , & size. to_le_bytes ( ) [ 0 ..destination. size ] )
546
530
}
531
+ "min_align_of" | "pref_align_of" => {
532
+ let Some ( ty) = generic_args. as_slice ( Interner ) . get ( 0 ) . and_then ( |x| x. ty ( Interner ) ) else {
533
+ return Err ( MirEvalError :: TypeError ( "align_of generic arg is not provided" ) ) ;
534
+ } ;
535
+ let align = self . layout ( ty) ?. align . abi . bytes ( ) ;
536
+ destination. write_from_bytes ( self , & align. to_le_bytes ( ) [ 0 ..destination. size ] )
537
+ }
547
538
"size_of_val" => {
548
539
let Some ( ty) = generic_args. as_slice ( Interner ) . get ( 0 ) . and_then ( |x| x. ty ( Interner ) )
549
540
else {
@@ -552,33 +543,28 @@ impl Evaluator<'_> {
552
543
let [ arg] = args else {
553
544
return Err ( MirEvalError :: TypeError ( "size_of_val args are not provided" ) ) ;
554
545
} ;
555
- let metadata = arg. interval . slice ( self . ptr_size ( ) ..self . ptr_size ( ) * 2 ) ;
556
- let size = match ty. kind ( Interner ) {
557
- TyKind :: Str => return destination. write_from_interval ( self , metadata) ,
558
- TyKind :: Slice ( inner) => {
559
- let len = from_bytes ! ( usize , metadata. get( self ) ?) ;
560
- len * self . size_of_sized ( inner, locals, "slice inner type" ) ?
561
- }
562
- TyKind :: Dyn ( _) => self . size_of_sized (
563
- self . vtable_map . ty_of_bytes ( metadata. get ( self ) ?) ?,
564
- locals,
565
- "dyn concrete type" ,
566
- ) ?,
567
- _ => self . size_of_sized (
568
- ty,
569
- locals,
570
- "unsized type other than str, slice, and dyn" ,
571
- ) ?,
572
- } ;
573
- destination. write_from_bytes ( self , & size. to_le_bytes ( ) )
546
+ if let Some ( ( size, _) ) = self . size_align_of ( ty, locals) ? {
547
+ destination. write_from_bytes ( self , & size. to_le_bytes ( ) )
548
+ } else {
549
+ let metadata = arg. interval . slice ( self . ptr_size ( ) ..self . ptr_size ( ) * 2 ) ;
550
+ let ( size, _) = self . size_align_of_unsized ( ty, metadata, locals) ?;
551
+ destination. write_from_bytes ( self , & size. to_le_bytes ( ) )
552
+ }
574
553
}
575
- "min_align_of" | "pref_align_of" => {
576
- let Some ( ty) = generic_args. as_slice ( Interner ) . get ( 0 ) . and_then ( |x| x. ty ( Interner ) )
577
- else {
578
- return Err ( MirEvalError :: TypeError ( "align_of generic arg is not provided" ) ) ;
554
+ "min_align_of_val" => {
555
+ let Some ( ty) = generic_args. as_slice ( Interner ) . get ( 0 ) . and_then ( |x| x. ty ( Interner ) ) else {
556
+ return Err ( MirEvalError :: TypeError ( "min_align_of_val generic arg is not provided" ) ) ;
579
557
} ;
580
- let align = self . layout ( ty) ?. align . abi . bytes ( ) ;
581
- destination. write_from_bytes ( self , & align. to_le_bytes ( ) [ 0 ..destination. size ] )
558
+ let [ arg] = args else {
559
+ return Err ( MirEvalError :: TypeError ( "min_align_of_val args are not provided" ) ) ;
560
+ } ;
561
+ if let Some ( ( _, align) ) = self . size_align_of ( ty, locals) ? {
562
+ destination. write_from_bytes ( self , & align. to_le_bytes ( ) )
563
+ } else {
564
+ let metadata = arg. interval . slice ( self . ptr_size ( ) ..self . ptr_size ( ) * 2 ) ;
565
+ let ( _, align) = self . size_align_of_unsized ( ty, metadata, locals) ?;
566
+ destination. write_from_bytes ( self , & align. to_le_bytes ( ) )
567
+ }
582
568
}
583
569
"needs_drop" => {
584
570
let Some ( ty) = generic_args. as_slice ( Interner ) . get ( 0 ) . and_then ( |x| x. ty ( Interner ) )
@@ -905,6 +891,58 @@ impl Evaluator<'_> {
905
891
}
906
892
}
907
893
894
+ fn size_align_of_unsized (
895
+ & mut self ,
896
+ ty : & Ty ,
897
+ metadata : Interval ,
898
+ locals : & Locals < ' _ > ,
899
+ ) -> Result < ( usize , usize ) > {
900
+ Ok ( match ty. kind ( Interner ) {
901
+ TyKind :: Str => ( from_bytes ! ( usize , metadata. get( self ) ?) , 1 ) ,
902
+ TyKind :: Slice ( inner) => {
903
+ let len = from_bytes ! ( usize , metadata. get( self ) ?) ;
904
+ let ( size, align) = self . size_align_of_sized ( inner, locals, "slice inner type" ) ?;
905
+ ( size * len, align)
906
+ }
907
+ TyKind :: Dyn ( _) => self . size_align_of_sized (
908
+ self . vtable_map . ty_of_bytes ( metadata. get ( self ) ?) ?,
909
+ locals,
910
+ "dyn concrete type" ,
911
+ ) ?,
912
+ TyKind :: Adt ( id, subst) => {
913
+ let id = id. 0 ;
914
+ let layout = self . layout_adt ( id, subst. clone ( ) ) ?;
915
+ let id = match id {
916
+ AdtId :: StructId ( s) => s,
917
+ _ => not_supported ! ( "unsized enum or union" ) ,
918
+ } ;
919
+ let field_types = & self . db . field_types ( id. into ( ) ) ;
920
+ let last_field_ty =
921
+ field_types. iter ( ) . rev ( ) . next ( ) . unwrap ( ) . 1 . clone ( ) . substitute ( Interner , subst) ;
922
+ let sized_part_size =
923
+ layout. fields . offset ( field_types. iter ( ) . count ( ) - 1 ) . bytes_usize ( ) ;
924
+ let sized_part_align = layout. align . abi . bytes ( ) as usize ;
925
+ let ( unsized_part_size, unsized_part_align) =
926
+ self . size_align_of_unsized ( & last_field_ty, metadata, locals) ?;
927
+ let align = sized_part_align. max ( unsized_part_align) as isize ;
928
+ let size = ( sized_part_size + unsized_part_size) as isize ;
929
+ // Must add any necessary padding to `size`
930
+ // (to make it a multiple of `align`) before returning it.
931
+ //
932
+ // Namely, the returned size should be, in C notation:
933
+ //
934
+ // `size + ((size & (align-1)) ? align : 0)`
935
+ //
936
+ // emulated via the semi-standard fast bit trick:
937
+ //
938
+ // `(size + (align-1)) & -align`
939
+ let size = ( size + ( align - 1 ) ) & ( -align) ;
940
+ ( size as usize , align as usize )
941
+ }
942
+ _ => not_supported ! ( "unsized type other than str, slice, struct and dyn" ) ,
943
+ } )
944
+ }
945
+
908
946
fn exec_atomic_intrinsic (
909
947
& mut self ,
910
948
name : & str ,
0 commit comments