Skip to content

Commit 90a921c

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

3 files changed

Lines changed: 94 additions & 19 deletions

File tree

c2rust-transpile/src/translator/pointers.rs

Lines changed: 92 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
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};
5+
use std::ops::Index;
46
use syn::{BinOp, Expr, Type, UnOp};
57

68
use 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

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)