1- use rustc_abi:: FieldIdx ;
1+ use rustc_abi:: { FieldIdx , VariantIdx } ;
22use rustc_ast:: Mutability ;
33use rustc_hir:: LangItem ;
44use rustc_middle:: span_bug;
55use rustc_middle:: ty:: layout:: TyAndLayout ;
6- use rustc_middle:: ty:: { self , Const , ScalarInt , Ty } ;
6+ use rustc_middle:: ty:: { self , Const , FnHeader , ScalarInt , Ty } ;
77use rustc_span:: { Symbol , sym} ;
88
99use crate :: const_eval:: CompileTimeMachine ;
@@ -13,11 +13,59 @@ use crate::interpret::{
1313} ;
1414
1515impl < ' tcx > InterpCx < ' tcx , CompileTimeMachine < ' tcx > > {
16+ // FIXME: Merge with #151142
17+ fn downcast (
18+ & self ,
19+ place : & ( impl Writeable < ' tcx , CtfeProvenance > + ' tcx ) ,
20+ name : Symbol ,
21+ ) -> InterpResult < ' tcx , ( VariantIdx , impl Writeable < ' tcx , CtfeProvenance > + ' tcx ) > {
22+ let variants = place. layout ( ) . ty . ty_adt_def ( ) . unwrap ( ) . variants ( ) ;
23+ let variant_id = variants
24+ . iter_enumerated ( )
25+ . find ( |( _idx, var) | var. name == name)
26+ . unwrap_or_else ( || panic ! ( "got {name} but expected one of {variants:#?}" ) )
27+ . 0 ;
28+
29+ interp_ok ( ( variant_id, self . project_downcast ( place, variant_id) ?) )
30+ }
31+
32+ // FIXME: Merge with #151142
33+ // A general method to write an array to a static slice place.
34+ fn allocate_fill_and_write_slice_ptr (
35+ & mut self ,
36+ slice_place : impl Writeable < ' tcx , CtfeProvenance > ,
37+ len : u64 ,
38+ writer : impl Fn ( & mut Self , /* index */ u64 , MPlaceTy < ' tcx > ) -> InterpResult < ' tcx > ,
39+ ) -> InterpResult < ' tcx > {
40+ // Array element type
41+ let field_ty = slice_place
42+ . layout ( )
43+ . ty
44+ . builtin_deref ( false )
45+ . unwrap ( )
46+ . sequence_element_type ( self . tcx . tcx ) ;
47+
48+ // Allocate an array
49+ let array_layout = self . layout_of ( Ty :: new_array ( self . tcx . tcx , field_ty, len) ) ?;
50+ let array_place = self . allocate ( array_layout, MemoryKind :: Stack ) ?;
51+
52+ // Fill the array fields
53+ let mut field_places = self . project_array_fields ( & array_place) ?;
54+ while let Some ( ( i, place) ) = field_places. next ( self ) ? {
55+ writer ( self , i, place) ?;
56+ }
57+
58+ // Write the slice pointing to the array
59+ let array_place = array_place. map_provenance ( CtfeProvenance :: as_immutable) ;
60+ let ptr = Immediate :: new_slice ( array_place. ptr ( ) , len, self ) ;
61+ self . write_immediate ( ptr, & slice_place)
62+ }
63+
1664 /// Writes a `core::mem::type_info::TypeInfo` for a given type, `ty` to the given place.
1765 pub ( crate ) fn write_type_info (
1866 & mut self ,
1967 ty : Ty < ' tcx > ,
20- dest : & impl Writeable < ' tcx , CtfeProvenance > ,
68+ dest : & ( impl Writeable < ' tcx , CtfeProvenance > + ' tcx ) ,
2169 ) -> InterpResult < ' tcx > {
2270 let ty_struct = self . tcx . require_lang_item ( LangItem :: Type , self . tcx . span ) ;
2371 let ty_struct = self . tcx . type_of ( ty_struct) . no_bound_vars ( ) . unwrap ( ) ;
@@ -135,11 +183,24 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
135183 self . write_dyn_trait_type_info ( dyn_place, * predicates, * region) ?;
136184 variant
137185 }
186+ ty:: FnPtr ( binder, FnHeader { safety, c_variadic, abi } ) => {
187+ let ( variant, variant_place) = downcast ( sym:: FnPtr ) ?;
188+ let fn_ptr_place =
189+ self . project_field ( & variant_place, FieldIdx :: ZERO ) ?;
190+ self . write_fn_ptr_type_info (
191+ fn_ptr_place,
192+ binder. skip_binder ( ) . output ( ) ,
193+ safety. is_unsafe ( ) ,
194+ * c_variadic,
195+ ( !abi. is_rustic_abi ( ) ) . then_some ( abi. as_str ( ) ) ,
196+ binder. skip_binder ( ) . inputs ( ) ,
197+ ) ?;
198+ variant
199+ }
138200 ty:: Adt ( _, _)
139201 | ty:: Foreign ( _)
140202 | ty:: Pat ( _, _)
141203 | ty:: FnDef ( ..)
142- | ty:: FnPtr ( ..)
143204 | ty:: UnsafeBinder ( ..)
144205 | ty:: Closure ( ..)
145206 | ty:: CoroutineClosure ( ..)
@@ -354,6 +415,57 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
354415 interp_ok ( ( ) )
355416 }
356417
418+ pub ( crate ) fn write_fn_ptr_type_info (
419+ & mut self ,
420+ place : impl Writeable < ' tcx , CtfeProvenance > + ' tcx ,
421+ output : Ty < ' tcx > ,
422+ unsafety : bool ,
423+ variadic : bool ,
424+ abi : Option < & ' static str > ,
425+ inputs : & [ Ty < ' tcx > ] ,
426+ ) -> InterpResult < ' tcx > {
427+ for ( field_idx, field) in
428+ place. layout ( ) . ty . ty_adt_def ( ) . unwrap ( ) . non_enum_variant ( ) . fields . iter_enumerated ( )
429+ {
430+ let field_place = self . project_field ( & place, field_idx) ?;
431+
432+ match field. name {
433+ sym:: unsafety => {
434+ self . write_scalar ( Scalar :: from_bool ( unsafety) , & field_place) ?;
435+ }
436+ sym:: abi => {
437+ if let Some ( abi) = abi {
438+ let ( variant, variant_place) = self . downcast ( & field_place, sym:: Named ) ?;
439+ let str_place = self . allocate_str_dedup ( abi) ?;
440+ let str_ref = self . mplace_to_ref ( & str_place) ?;
441+ let payload = self . project_field ( & variant_place, FieldIdx :: ZERO ) ?;
442+ self . write_immediate ( * str_ref, & payload) ?;
443+ self . write_discriminant ( variant, & field_place) ?;
444+ } else {
445+ let ( rust_variant, _rust_place) = self . downcast ( & field_place, sym:: Rust ) ?;
446+ self . write_discriminant ( rust_variant, & field_place) ?;
447+ }
448+ }
449+ sym:: inputs => {
450+ self . allocate_fill_and_write_slice_ptr (
451+ field_place,
452+ inputs. len ( ) as _ ,
453+ |this, i, place| this. write_type_id ( inputs[ i as usize ] , & place) ,
454+ ) ?;
455+ }
456+ sym:: output => {
457+ self . write_type_id ( output, & field_place) ?;
458+ }
459+ sym:: variadic => {
460+ self . write_scalar ( Scalar :: from_bool ( variadic) , & field_place) ?;
461+ }
462+ other => span_bug ! ( self . tcx. def_span( field. did) , "unimplemented field {other}" ) ,
463+ }
464+ }
465+
466+ interp_ok ( ( ) )
467+ }
468+
357469 pub ( crate ) fn write_pointer_type_info (
358470 & mut self ,
359471 place : impl Writeable < ' tcx , CtfeProvenance > ,
0 commit comments