11use c2rust_ast_builder:: { mk, properties:: Mutability } ;
22use c2rust_ast_exporter:: clang_ast:: LRValue ;
3+ use c2rust_rust_tools:: RustEdition ;
34use failure:: { err_msg, format_err} ;
5+ use std:: ops:: Index ;
46use syn:: { BinOp , Expr , Type , UnOp } ;
57
68use crate :: c_ast:: CUnOp ;
@@ -483,17 +485,68 @@ impl<'c> Translation<'c> {
483485
484486 WithStmts :: new_val ( transmute_expr ( intptr_t, target_ty, val) ) . set_unsafe ( )
485487 } ) )
486- } else if source_ty_kind. is_bool ( ) {
487- self . use_crate ( ExternCrate :: Libc ) ;
488- Ok ( val. map ( |mut val| {
489- // First cast the boolean to pointer size
490- val = mk ( ) . cast_expr ( val, mk ( ) . abs_path_ty ( vec ! [ "libc" , "size_t" ] ) ) ;
491- mk ( ) . cast_expr ( val, target_ty)
492- } ) )
493- } else if let & CTypeKind :: Enum ( ..) = source_ty_kind {
494- val. try_map ( |val| self . convert_cast_from_enum ( target_cty, val) )
488+ }
489+ // Rust 1.90: `const_strict_provenance` feature added
490+ // Rust 1.91: stabilized
491+ else if ctx. is_const && self . tcfg . edition < RustEdition :: Edition2024 {
492+ if source_ty_kind. is_bool ( ) {
493+ self . use_crate ( ExternCrate :: Libc ) ;
494+ Ok ( val. map ( |mut val| {
495+ // First cast the boolean to pointer size
496+ val = mk ( ) . cast_expr ( val, mk ( ) . abs_path_ty ( vec ! [ "libc" , "size_t" ] ) ) ;
497+ mk ( ) . cast_expr ( val, target_ty)
498+ } ) )
499+ } else if let & CTypeKind :: Enum ( ..) = source_ty_kind {
500+ val. try_map ( |val| self . convert_cast_from_enum ( target_cty, val) )
501+ } else {
502+ Ok ( val. map ( |val| mk ( ) . cast_expr ( val, target_ty) ) )
503+ }
495504 } else {
496- Ok ( val. map ( |val| mk ( ) . cast_expr ( val, target_ty) ) )
505+ // First cast the value to `usize`.
506+ let source_type_kind = & self . ast_context . resolve_type ( source_cty) . kind ;
507+ let size_type_id = self . ast_context . type_for_kind ( & CTypeKind :: Size ) ;
508+
509+ let val = if let & CTypeKind :: Enum ( ..) = source_type_kind {
510+ val. try_map ( |val| self . convert_cast_from_enum ( size_type_id, val) ) ?
511+ } else {
512+ let size_type_rs = self . convert_type ( size_type_id) ?;
513+ val. map ( |val| mk ( ) . cast_expr ( val, size_type_rs) )
514+ } ;
515+
516+ // Then convert the `usize` into a pointer.
517+ let pointee_type_id = self
518+ . ast_context
519+ . get_pointee_qual_type ( target_cty)
520+ . expect ( "target type must be a pointer" ) ;
521+ let mutability = pointee_type_id. mutability ( ) ;
522+
523+ let fn_name = match self . tcfg . edition {
524+ RustEdition :: Edition2021 => {
525+ // Rust 1.76: feature name changed to `exposed_provenance[_mut]`
526+ // Rust 1.84: stabilized
527+ self . use_feature ( "strict_provenance" ) ;
528+
529+ // Rust 1.79: method name changed to `with_exposed_provenance[_mut]`
530+ match mutability {
531+ Mutability :: Immutable => "from_exposed_addr" ,
532+ Mutability :: Mutable => "from_exposed_addr_mut" ,
533+ }
534+ }
535+ RustEdition :: Edition2024 => match mutability {
536+ Mutability :: Immutable => "with_exposed_provenance" ,
537+ Mutability :: Mutable => "with_exposed_provenance_mut" ,
538+ } ,
539+ } ;
540+ let pointee_type_rs = self . convert_pointee_type ( pointee_type_id. ctype ) ?;
541+ let type_args = mk ( ) . angle_bracketed_args ( vec ! [ pointee_type_rs] ) ;
542+ let fn_expr = mk ( ) . abs_path_expr ( vec ! [
543+ mk( ) . path_segment( "core" ) ,
544+ mk( ) . path_segment( "ptr" ) ,
545+ mk( ) . path_segment_with_args( fn_name, type_args) ,
546+ ] ) ;
547+ let val = val. map ( |val| mk ( ) . call_expr ( fn_expr, vec ! [ val] ) ) ;
548+
549+ Ok ( val)
497550 }
498551 }
499552
@@ -512,18 +565,40 @@ impl<'c> Translation<'c> {
512565 ) ) ;
513566 }
514567
515- let target_ty = self . convert_type ( target_cty) ?;
516- let source_ty = self . convert_type ( source_cty) ?;
517- let target_ty_kind = & self . ast_context . resolve_type ( target_cty) . kind ;
568+ let target_type_rs = self . convert_type ( target_cty) ?;
518569
519570 if self . ast_context . is_function_pointer ( source_cty) {
571+ let source_ty = self . convert_type ( source_cty) ?;
572+
520573 Ok ( val. and_then ( |val| {
521- WithStmts :: new_val ( transmute_expr ( source_ty, target_ty , val) ) . set_unsafe ( )
574+ WithStmts :: new_val ( transmute_expr ( source_ty, target_type_rs , val) ) . set_unsafe ( )
522575 } ) )
523- } else if let & CTypeKind :: Enum ( enum_decl_id) = target_ty_kind {
524- val. try_map ( |val| self . convert_cast_to_enum ( ctx, target_cty, enum_decl_id, expr, val) )
525576 } else {
526- Ok ( val. map ( |val| mk ( ) . cast_expr ( val, target_ty) ) )
577+ // First convert the pointer to `usize`.
578+ let method_name = match self . tcfg . edition {
579+ RustEdition :: Edition2021 => {
580+ // Rust 1.76: feature name changed to `exposed_provenance`
581+ // Rust 1.84: stabilized
582+ self . use_feature ( "strict_provenance" ) ;
583+
584+ // Rust 1.79: method name changed to `expose_provenance`
585+ "expose_addr"
586+ }
587+ RustEdition :: Edition2024 => "expose_provenance" ,
588+ } ;
589+
590+ let val = val. map ( |val| mk ( ) . method_call_expr ( val, method_name, vec ! [ ] ) ) ;
591+
592+ // Then cast the `usize` to the target type.
593+ let target_ty_kind = & self . ast_context . resolve_type ( target_cty) . kind ;
594+
595+ if let & CTypeKind :: Enum ( enum_decl_id) = target_ty_kind {
596+ val. try_map ( |val| {
597+ self . convert_cast_to_enum ( ctx, target_cty, enum_decl_id, expr, val)
598+ } )
599+ } else {
600+ Ok ( val. map ( |val| mk ( ) . cast_expr ( val, target_type_rs) ) )
601+ }
527602 }
528603 }
529604
0 commit comments