Skip to content

Commit 8b29087

Browse files
authored
transpile: Use strict provenance APIs for pointer casts (#1810)
- Depends on #1811 - Fixes #1136 The strict provenance APIs changed since the currently used nightly 1.67, so I've selected the API based on the edition, and left comments for when things were changed. Casts involving function pointers are not covered by this, as they use transmutes, and it doesn't seem immediately obvious how to make that work.
2 parents 5f1cecd + 51976e0 commit 8b29087

11 files changed

Lines changed: 129 additions & 81 deletions

File tree

c2rust-transpile/src/c_ast/conversion.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,7 @@ impl ConversionContext {
533533
for (_decl_id, located_kind) in self.typed_context.c_decls.iter() {
534534
if let kind @ CDeclKind::Function { .. } = &located_kind.kind {
535535
let new_kind = self.typed_context.fn_decl_ty_with_declared_args(kind);
536-
if self.typed_context.type_for_kind(&new_kind).is_none() {
536+
if self.typed_context.try_type_for_kind(&new_kind).is_none() {
537537
// Create and insert fn type
538538
let new_id = CTypeId(self.id_mapper.fresh_id());
539539
self.typed_context
@@ -2225,9 +2225,7 @@ impl ConversionContext {
22252225
}
22262226
};
22272227
log::trace!("Selected kind {kind} for typedef {name}");
2228-
Some(CQualTypeId::new(
2229-
self.typed_context.type_for_kind(&kind).unwrap(),
2230-
))
2228+
Some(CQualTypeId::new(self.typed_context.type_for_kind(&kind)))
22312229
})
22322230
.unwrap_or(typ);
22332231

@@ -2270,9 +2268,7 @@ impl ConversionContext {
22702268
}
22712269
};
22722270
log::trace!("Selected kind {kind} for typedef {name}");
2273-
Some(CQualTypeId::new(
2274-
self.typed_context.type_for_kind(&kind).unwrap(),
2275-
))
2271+
Some(CQualTypeId::new(self.typed_context.type_for_kind(&kind)))
22762272
};
22772273
let file = self
22782274
.typed_context

c2rust-transpile/src/c_ast/mod.rs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::c_ast::iterators::{immediate_children_all_types, NodeVisitor};
22
use crate::iterators::{DFNodes, SomeId};
3+
use c2rust_ast_builder::properties::Mutability;
34
use c2rust_ast_exporter::clang_ast::LRValue;
45
use indexmap::{IndexMap, IndexSet};
56
use itertools::Itertools;
@@ -777,12 +778,17 @@ impl TypedAstContext {
777778
ty.map(|ty| (expr_id, ty))
778779
}
779780

780-
pub fn type_for_kind(&self, kind: &CTypeKind) -> Option<CTypeId> {
781+
pub fn try_type_for_kind(&self, kind: &CTypeKind) -> Option<CTypeId> {
781782
self.c_types
782783
.iter()
783784
.find_map(|(id, k)| if kind == &k.kind { Some(*id) } else { None })
784785
}
785786

787+
pub fn type_for_kind(&self, kind: &CTypeKind) -> CTypeId {
788+
self.try_type_for_kind(kind)
789+
.expect("could not find type for CTypeKind::{kind:?}")
790+
}
791+
786792
pub fn resolve_type_id(&self, typ: CTypeId) -> CTypeId {
787793
use CTypeKind::*;
788794
let ty = match self.index(typ).kind {
@@ -881,9 +887,7 @@ impl TypedAstContext {
881887
pub fn fn_declref_ty_with_declared_args(&self, func_expr: CExprId) -> Option<CQualTypeId> {
882888
if let Some(func_decl @ CDeclKind::Function { .. }) = self.fn_declref_decl(func_expr) {
883889
let kind_with_declared_args = self.fn_decl_ty_with_declared_args(func_decl);
884-
let specific_typ = self
885-
.type_for_kind(&kind_with_declared_args)
886-
.unwrap_or_else(|| panic!("no type for kind {kind_with_declared_args:?}"));
890+
let specific_typ = self.type_for_kind(&kind_with_declared_args);
887891
return Some(CQualTypeId::new(specific_typ));
888892
}
889893
None
@@ -1383,10 +1387,7 @@ impl TypedAstContext {
13831387
CUnTypeOp::AlignOf => CTypeKind::Size,
13841388
CUnTypeOp::PreferredAlignOf => CTypeKind::Size,
13851389
};
1386-
let ty = self
1387-
.ast_context
1388-
.type_for_kind(&kind)
1389-
.expect("CTypeKind::Size should be size_t");
1390+
let ty = self.ast_context.type_for_kind(&kind);
13901391
Some(CQualTypeId::new(ty))
13911392
}
13921393
_ => return,
@@ -2101,7 +2102,7 @@ impl CUnOp {
21012102
}
21022103
Not => {
21032104
return ast_context
2104-
.type_for_kind(&CTypeKind::Int)
2105+
.try_type_for_kind(&CTypeKind::Int)
21052106
.map(CQualTypeId::new)
21062107
}
21072108
Real | Imag => {
@@ -2516,6 +2517,13 @@ impl Qualifiers {
25162517
is_volatile: self.is_volatile || other.is_volatile,
25172518
}
25182519
}
2520+
2521+
pub fn mutability(self) -> Mutability {
2522+
match self.is_const {
2523+
true => Mutability::Immutable,
2524+
false => Mutability::Mutable,
2525+
}
2526+
}
25192527
}
25202528

25212529
/// Qualified type
@@ -2536,6 +2544,10 @@ impl CQualTypeId {
25362544
pub fn with_ctype(self, ctype: CTypeId) -> Self {
25372545
Self { ctype, ..self }
25382546
}
2547+
2548+
pub fn mutability(self) -> Mutability {
2549+
self.qualifiers.mutability()
2550+
}
25392551
}
25402552

25412553
// TODO: these may be interesting, but I'm not sure if they fit here:

c2rust-transpile/src/convert_type.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::renamer::*;
55
use crate::translator::variadic::mk_va_list_ty;
66
use crate::TranspilerConfig;
77
use crate::{CrateSet, ExternCrate};
8-
use c2rust_ast_builder::{mk, properties::*};
8+
use c2rust_ast_builder::mk;
99
use c2rust_rust_tools::RustEdition;
1010
use failure::format_err;
1111
use indexmap::IndexSet;
@@ -170,13 +170,7 @@ impl TypeConverter {
170170
let param = mk().angle_bracketed_args(vec![pointee_ty]);
171171
Ok(mk().path_ty(vec![mk().path_segment_with_args("Option", param)]))
172172
} else {
173-
let mutbl = if qtype.qualifiers.is_const {
174-
Mutability::Immutable
175-
} else {
176-
Mutability::Mutable
177-
};
178-
179-
Ok(mk().set_mutbl(mutbl).ptr_ty(pointee_ty))
173+
Ok(mk().set_mutbl(qtype.mutability()).ptr_ty(pointee_ty))
180174
}
181175
}
182176

c2rust-transpile/src/translator/functions.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -341,11 +341,7 @@ impl<'c> Translation<'c> {
341341
typ: CQualTypeId,
342342
) -> TranslationResult<ConvertedFunctionParam> {
343343
if self.ast_context.is_va_list(typ.ctype) {
344-
let mutbl = if typ.qualifiers.is_const {
345-
Mutability::Immutable
346-
} else {
347-
Mutability::Mutable
348-
};
344+
let mutbl = typ.mutability();
349345
let ty = mk().abs_path_ty(vec!["core", "ffi", "VaList"]);
350346
return Ok(ConvertedFunctionParam { mutbl, ty });
351347
}

c2rust-transpile/src/translator/literals.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -193,13 +193,8 @@ impl<'c> Translation<'c> {
193193
}))
194194
} else {
195195
Ok(val.and_then(|val| {
196-
let mutbl = if qty.qualifiers.is_const {
197-
Mutability::Immutable
198-
} else {
199-
Mutability::Mutable
200-
};
201196
let local = mk().local(
202-
mk().set_mutbl(mutbl).ident_pat(&fresh_name),
197+
mk().set_mutbl(qty.mutability()).ident_pat(&fresh_name),
203198
Some(fresh_ty),
204199
Some(val),
205200
);

c2rust-transpile/src/translator/mod.rs

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2735,11 +2735,7 @@ impl<'c> Translation<'c> {
27352735
self.convert_type(typ.ctype)?
27362736
};
27372737

2738-
let mutbl = if typ.qualifiers.is_const {
2739-
Mutability::Immutable
2740-
} else {
2741-
Mutability::Mutable
2742-
};
2738+
let mutbl = typ.mutability();
27432739

27442740
Ok(ConvertedVariable { ty, mutbl, init })
27452741
}
@@ -3190,7 +3186,7 @@ impl<'c> Translation<'c> {
31903186

31913187
if let Some(ty) = self
31923188
.ast_context
3193-
.type_for_kind(&kind_with_declared_args)
3189+
.try_type_for_kind(&kind_with_declared_args)
31943190
.map(CQualTypeId::new)
31953191
{
31963192
let ty = self.convert_type(ty.ctype)?;
@@ -3679,14 +3675,10 @@ impl<'c> Translation<'c> {
36793675
// precise source type. The AST node's type will not preserve typedef arg types
36803676
// but the function's declaration will.
36813677
let kind_with_declared_args = self.ast_context.fn_decl_ty_with_declared_args(func_decl);
3682-
let func_ty = self
3683-
.ast_context
3684-
.type_for_kind(&kind_with_declared_args)
3685-
.unwrap_or_else(|| panic!("no type for kind {kind_with_declared_args:?}"));
3678+
let func_ty = self.ast_context.type_for_kind(&kind_with_declared_args);
36863679
let func_ptr_ty = self
36873680
.ast_context
3688-
.type_for_kind(&CTypeKind::Pointer(CQualTypeId::new(func_ty)))
3689-
.unwrap_or_else(|| panic!("no type for kind {kind_with_declared_args:?}"));
3681+
.type_for_kind(&CTypeKind::Pointer(CQualTypeId::new(func_ty)));
36903682

36913683
CQualTypeId::new(func_ptr_ty)
36923684
} else {

c2rust-transpile/src/translator/operators.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -632,11 +632,7 @@ impl<'c> Translation<'c> {
632632

633633
let one_type_id =
634634
if let CTypeKind::Pointer(..) = self.ast_context.resolve_type(arg_type.ctype).kind {
635-
CQualTypeId::new(
636-
self.ast_context
637-
.type_for_kind(&CTypeKind::Int)
638-
.ok_or_else(|| format_err!("couldn't find type for CTypeKind::Int"))?,
639-
)
635+
CQualTypeId::new(self.ast_context.type_for_kind(&CTypeKind::Int))
640636
} else {
641637
arg_type
642638
};

c2rust-transpile/src/translator/pointers.rs

Lines changed: 93 additions & 21 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

@@ -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

c2rust-transpile/src/translator/variadic.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -199,12 +199,7 @@ impl<'c> Translation<'c> {
199199
is_variadic,
200200
)?;
201201

202-
let m = if p.qualifiers.is_const {
203-
Mutability::Immutable
204-
} else {
205-
Mutability::Mutable
206-
};
207-
Some(mk().set_mutbl(m).ptr_ty(fn_ty))
202+
Some(mk().set_mutbl(p.mutability()).ptr_ty(fn_ty))
208203
} else {
209204
None
210205
}

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;

0 commit comments

Comments
 (0)