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} ;
45use syn:: { BinOp , Expr , Type , UnOp } ;
56
@@ -483,17 +484,68 @@ impl<'c> Translation<'c> {
483484
484485 WithStmts :: new_val ( transmute_expr ( intptr_t, target_ty, val) ) . set_unsafe ( )
485486 } ) )
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) )
487+ }
488+ // Rust 1.90: `const_strict_provenance` feature added
489+ // Rust 1.91: stabilized
490+ else if ctx. is_const && self . tcfg . edition < RustEdition :: Edition2024 {
491+ if source_ty_kind. is_bool ( ) {
492+ self . use_crate ( ExternCrate :: Libc ) ;
493+ Ok ( val. map ( |mut val| {
494+ // First cast the boolean to pointer size
495+ val = mk ( ) . cast_expr ( val, mk ( ) . abs_path_ty ( vec ! [ "libc" , "size_t" ] ) ) ;
496+ mk ( ) . cast_expr ( val, target_ty)
497+ } ) )
498+ } else if let & CTypeKind :: Enum ( ..) = source_ty_kind {
499+ val. try_map ( |val| self . convert_cast_from_enum ( target_cty, val) )
500+ } else {
501+ Ok ( val. map ( |val| mk ( ) . cast_expr ( val, target_ty) ) )
502+ }
495503 } else {
496- Ok ( val. map ( |val| mk ( ) . cast_expr ( val, target_ty) ) )
504+ // First cast the value to `usize`.
505+ let source_type_kind = & self . ast_context . resolve_type ( source_cty) . kind ;
506+ let size_type_id = self . ast_context . type_for_kind ( & CTypeKind :: Size ) ;
507+
508+ let val = if let & CTypeKind :: Enum ( ..) = source_type_kind {
509+ val. try_map ( |val| self . convert_cast_from_enum ( size_type_id, val) ) ?
510+ } else {
511+ let size_type_rs = self . convert_type ( size_type_id) ?;
512+ val. map ( |val| mk ( ) . cast_expr ( val, size_type_rs) )
513+ } ;
514+
515+ // Then convert the `usize` into a pointer.
516+ let pointee_type_id = self
517+ . ast_context
518+ . get_pointee_qual_type ( target_cty)
519+ . expect ( "target type must be a pointer" ) ;
520+ let mutability = pointee_type_id. mutability ( ) ;
521+
522+ let fn_name = match self . tcfg . edition {
523+ RustEdition :: Edition2021 => {
524+ // Rust 1.76: feature name changed to `exposed_provenance[_mut]`
525+ // Rust 1.84: stabilized
526+ self . use_feature ( "strict_provenance" ) ;
527+
528+ // Rust 1.79: method name changed to `with_exposed_provenance[_mut]`
529+ match mutability {
530+ Mutability :: Immutable => "from_exposed_addr" ,
531+ Mutability :: Mutable => "from_exposed_addr_mut" ,
532+ }
533+ }
534+ RustEdition :: Edition2024 => match mutability {
535+ Mutability :: Immutable => "with_exposed_provenance" ,
536+ Mutability :: Mutable => "with_exposed_provenance_mut" ,
537+ } ,
538+ } ;
539+ let pointee_type_rs = self . convert_pointee_type ( pointee_type_id. ctype ) ?;
540+ let type_args = mk ( ) . angle_bracketed_args ( vec ! [ pointee_type_rs] ) ;
541+ let fn_expr = mk ( ) . abs_path_expr ( vec ! [
542+ mk( ) . path_segment( "core" ) ,
543+ mk( ) . path_segment( "ptr" ) ,
544+ mk( ) . path_segment_with_args( fn_name, type_args) ,
545+ ] ) ;
546+ let val = val. map ( |val| mk ( ) . call_expr ( fn_expr, vec ! [ val] ) ) ;
547+
548+ Ok ( val)
497549 }
498550 }
499551
@@ -512,18 +564,40 @@ impl<'c> Translation<'c> {
512564 ) ) ;
513565 }
514566
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 ;
567+ let target_type_rs = self . convert_type ( target_cty) ?;
518568
519569 if self . ast_context . is_function_pointer ( source_cty) {
570+ let source_ty = self . convert_type ( source_cty) ?;
571+
520572 Ok ( val. and_then ( |val| {
521- WithStmts :: new_val ( transmute_expr ( source_ty, target_ty , val) ) . set_unsafe ( )
573+ WithStmts :: new_val ( transmute_expr ( source_ty, target_type_rs , val) ) . set_unsafe ( )
522574 } ) )
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) )
525575 } else {
526- Ok ( val. map ( |val| mk ( ) . cast_expr ( val, target_ty) ) )
576+ // First convert the pointer to `usize`.
577+ let method_name = match self . tcfg . edition {
578+ RustEdition :: Edition2021 => {
579+ // Rust 1.76: feature name changed to `exposed_provenance`
580+ // Rust 1.84: stabilized
581+ self . use_feature ( "strict_provenance" ) ;
582+
583+ // Rust 1.79: method name changed to `expose_provenance`
584+ "expose_addr"
585+ }
586+ RustEdition :: Edition2024 => "expose_provenance" ,
587+ } ;
588+
589+ let val = val. map ( |val| mk ( ) . method_call_expr ( val, method_name, vec ! [ ] ) ) ;
590+
591+ // Then cast the `usize` to the target type.
592+ let target_ty_kind = & self . ast_context . resolve_type ( target_cty) . kind ;
593+
594+ if let & CTypeKind :: Enum ( enum_decl_id) = target_ty_kind {
595+ val. try_map ( |val| {
596+ self . convert_cast_to_enum ( ctx, target_cty, enum_decl_id, expr, val)
597+ } )
598+ } else {
599+ Ok ( val. map ( |val| mk ( ) . cast_expr ( val, target_type_rs) ) )
600+ }
527601 }
528602 }
529603
0 commit comments