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
@@ -108,16 +109,14 @@ impl<'c> Translation<'c> {
108109
109110 let mut needs_cast = false ;
110111 let mut ref_cast_pointee_ty = None ;
111- let mutbl = if pointee_cty. qualifiers . is_const {
112- Mutability :: Immutable
113- } else if ctx. is_const {
112+ let mutbl = if ctx. is_const && !pointee_cty. qualifiers . is_const {
114113 // const contexts aren't able to use &mut, so we work around that
115114 // by using & and an extra cast through & to *const to *mut
116115 // TODO: Rust 1.83: Allowed, so this can be removed.
117116 needs_cast = true ;
118117 Mutability :: Immutable
119118 } else {
120- Mutability :: Mutable
119+ pointee_cty . mutability ( )
121120 } ;
122121
123122 // Narrow string literals are translated directly as `[u8; N]` literals when their address
@@ -485,17 +484,68 @@ impl<'c> Translation<'c> {
485484
486485 WithStmts :: new_val ( transmute_expr ( intptr_t, target_ty, val) ) . set_unsafe ( )
487486 } ) )
488- } else if source_ty_kind. is_bool ( ) {
489- self . use_crate ( ExternCrate :: Libc ) ;
490- Ok ( val. map ( |mut val| {
491- // First cast the boolean to pointer size
492- val = mk ( ) . cast_expr ( val, mk ( ) . abs_path_ty ( vec ! [ "libc" , "size_t" ] ) ) ;
493- mk ( ) . cast_expr ( val, target_ty)
494- } ) )
495- } else if let & CTypeKind :: Enum ( ..) = source_ty_kind {
496- 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+ }
497503 } else {
498- 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)
499549 }
500550 }
501551
@@ -514,18 +564,40 @@ impl<'c> Translation<'c> {
514564 ) ) ;
515565 }
516566
517- let target_ty = self . convert_type ( target_cty) ?;
518- let source_ty = self . convert_type ( source_cty) ?;
519- let target_ty_kind = & self . ast_context . resolve_type ( target_cty) . kind ;
567+ let target_type_rs = self . convert_type ( target_cty) ?;
520568
521569 if self . ast_context . is_function_pointer ( source_cty) {
570+ let source_ty = self . convert_type ( source_cty) ?;
571+
522572 Ok ( val. and_then ( |val| {
523- 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 ( )
524574 } ) )
525- } else if let & CTypeKind :: Enum ( enum_decl_id) = target_ty_kind {
526- val. try_map ( |val| self . convert_cast_to_enum ( ctx, target_cty, enum_decl_id, expr, val) )
527575 } else {
528- 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+ }
529601 }
530602 }
531603
0 commit comments