Skip to content

Commit 4c5a89c

Browse files
committed
transpile: Use strict provenance APIs for pointer casts
1 parent d40e5ca commit 4c5a89c

3 files changed

Lines changed: 93 additions & 19 deletions

File tree

c2rust-transpile/src/translator/pointers.rs

Lines changed: 91 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use c2rust_ast_builder::{mk, properties::Mutability};
22
use c2rust_ast_exporter::clang_ast::LRValue;
3+
use c2rust_rust_tools::RustEdition;
34
use failure::{err_msg, format_err};
45
use 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

tests/unit/pointers/src/test_pointers.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! feature_c_variadic, feature_raw_ref_op
1+
//! feature_c_variadic, feature_raw_ref_op, feature_strict_provenance
22
33
use crate::function_pointers::rust_entry3;
44
use crate::pointer_arith::rust_entry2;

tests/unit/statics/src/test_sections.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! feature_raw_ref_op
1+
//! feature_raw_ref_op, feature_strict_provenance
22
33
#[cfg(not(target_os = "macos"))]
44
use crate::attributes::{rust_no_attrs, rust_used_static, rust_used_static2, rust_used_static3};

0 commit comments

Comments
 (0)