33
44use std:: cmp;
55
6+ use chalk_ir:: TyKind ;
7+ use hir_def:: resolver:: HasResolver ;
8+ use hir_expand:: mod_path:: ModPath ;
9+
610use super :: * ;
711
812mod simd;
@@ -186,44 +190,24 @@ impl Evaluator<'_> {
186190 BeginPanic => Err ( MirEvalError :: Panic ( "<unknown-panic-payload>" . to_string ( ) ) ) ,
187191 PanicFmt => {
188192 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 ( ) )
225209 } ) ( )
226- . unwrap_or_else ( || "< format- args-evaluation-failed>" . to_string ( ) ) ;
210+ . unwrap_or_else ( |e| format ! ( "Failed to render panic format args: {e:?}" ) ) ;
227211 Err ( MirEvalError :: Panic ( message) )
228212 }
229213 SliceLen => {
@@ -544,6 +528,13 @@ impl Evaluator<'_> {
544528 let size = self . size_of_sized ( ty, locals, "size_of arg" ) ?;
545529 destination. write_from_bytes ( self , & size. to_le_bytes ( ) [ 0 ..destination. size ] )
546530 }
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+ }
547538 "size_of_val" => {
548539 let Some ( ty) = generic_args. as_slice ( Interner ) . get ( 0 ) . and_then ( |x| x. ty ( Interner ) )
549540 else {
@@ -552,33 +543,28 @@ impl Evaluator<'_> {
552543 let [ arg] = args else {
553544 return Err ( MirEvalError :: TypeError ( "size_of_val args are not provided" ) ) ;
554545 } ;
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+ }
574553 }
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" ) ) ;
579557 } ;
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+ }
582568 }
583569 "needs_drop" => {
584570 let Some ( ty) = generic_args. as_slice ( Interner ) . get ( 0 ) . and_then ( |x| x. ty ( Interner ) )
@@ -905,6 +891,58 @@ impl Evaluator<'_> {
905891 }
906892 }
907893
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+
908946 fn exec_atomic_intrinsic (
909947 & mut self ,
910948 name : & str ,
0 commit comments