Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions c2rust-refactor/src/transform/canonicalize_refs.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use rustc_ast::ptr::P;
use rustc_ast::{Crate, Expr, ExprKind, Mutability, UnOp};
use rustc_ast::{BorrowKind, Crate, Expr, ExprKind, Mutability, UnOp};
use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability};
use rustc_type_ir::sty;

Expand Down Expand Up @@ -85,7 +85,7 @@ impl Transform for RemoveUnnecessaryRefs {

fn remove_ref(expr: &mut P<Expr>) {
match &expr.kind {
ExprKind::AddrOf(_, _, inner) => *expr = inner.clone(),
ExprKind::AddrOf(BorrowKind::Ref, _, inner) => *expr = inner.clone(),
_ => {}
}
}
Expand All @@ -106,7 +106,7 @@ fn remove_all_derefs(expr: &mut P<Expr>, cx: &RefactorCtxt) {
}

fn remove_reborrow(expr: &mut P<Expr>, cx: &RefactorCtxt) {
if let ExprKind::AddrOf(_, _, ref subexpr) = expr.kind {
if let ExprKind::AddrOf(BorrowKind::Ref, _, ref subexpr) = expr.kind {
if let ExprKind::Unary(UnOp::Deref, ref subexpr) = subexpr.kind {
if is_pointer(subexpr, cx) {
// &* on a pointer produces a reference, so it's not a no-op
Expand Down
10 changes: 3 additions & 7 deletions c2rust-transpile/src/c_ast/conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ impl ConversionContext {
for (_decl_id, located_kind) in self.typed_context.c_decls.iter() {
if let kind @ CDeclKind::Function { .. } = &located_kind.kind {
let new_kind = self.typed_context.fn_decl_ty_with_declared_args(kind);
if self.typed_context.type_for_kind(&new_kind).is_none() {
if self.typed_context.try_type_for_kind(&new_kind).is_none() {
// Create and insert fn type
let new_id = CTypeId(self.id_mapper.fresh_id());
self.typed_context
Expand Down Expand Up @@ -2126,9 +2126,7 @@ impl ConversionContext {
}
};
log::trace!("Selected kind {kind} for typedef {name}");
Some(CQualTypeId::new(
self.typed_context.type_for_kind(&kind).unwrap(),
))
Some(CQualTypeId::new(self.typed_context.type_for_kind(&kind)))
})
.unwrap_or(typ);

Expand Down Expand Up @@ -2171,9 +2169,7 @@ impl ConversionContext {
}
};
log::trace!("Selected kind {kind} for typedef {name}");
Some(CQualTypeId::new(
self.typed_context.type_for_kind(&kind).unwrap(),
))
Some(CQualTypeId::new(self.typed_context.type_for_kind(&kind)))
};
let file = self
.typed_context
Expand Down
30 changes: 21 additions & 9 deletions c2rust-transpile/src/c_ast/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::c_ast::iterators::{immediate_children_all_types, NodeVisitor};
use crate::iterators::{DFNodes, SomeId};
use c2rust_ast_builder::properties::Mutability;
use c2rust_ast_exporter::clang_ast::LRValue;
use indexmap::{IndexMap, IndexSet};
use itertools::Itertools;
Expand Down Expand Up @@ -742,12 +743,17 @@ impl TypedAstContext {
ty.map(|ty| (expr_id, ty))
}

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

pub fn type_for_kind(&self, kind: &CTypeKind) -> CTypeId {
self.try_type_for_kind(kind)
.expect("could not find type for CTypeKind::{kind:?}")
}

pub fn resolve_type_id(&self, typ: CTypeId) -> CTypeId {
use CTypeKind::*;
let ty = match self.index(typ).kind {
Expand Down Expand Up @@ -845,9 +851,7 @@ impl TypedAstContext {
pub fn fn_declref_ty_with_declared_args(&self, func_expr: CExprId) -> Option<CQualTypeId> {
if let Some(func_decl @ CDeclKind::Function { .. }) = self.fn_declref_decl(func_expr) {
let kind_with_declared_args = self.fn_decl_ty_with_declared_args(func_decl);
let specific_typ = self
.type_for_kind(&kind_with_declared_args)
.unwrap_or_else(|| panic!("no type for kind {kind_with_declared_args:?}"));
let specific_typ = self.type_for_kind(&kind_with_declared_args);
return Some(CQualTypeId::new(specific_typ));
}
None
Expand Down Expand Up @@ -1297,10 +1301,7 @@ impl TypedAstContext {
CUnTypeOp::AlignOf => CTypeKind::Size,
CUnTypeOp::PreferredAlignOf => CTypeKind::Size,
};
let ty = self
.ast_context
.type_for_kind(&kind)
.expect("CTypeKind::Size should be size_t");
let ty = self.ast_context.type_for_kind(&kind);
Some(CQualTypeId::new(ty))
}
_ => return,
Expand Down Expand Up @@ -2020,7 +2021,7 @@ impl CUnOp {
}
Not => {
return ast_context
.type_for_kind(&CTypeKind::Int)
.try_type_for_kind(&CTypeKind::Int)
.map(CQualTypeId::new)
}
Real | Imag => {
Expand Down Expand Up @@ -2433,6 +2434,13 @@ impl Qualifiers {
is_volatile: self.is_volatile || other.is_volatile,
}
}

pub fn mutability(self) -> Mutability {
match self.is_const {
true => Mutability::Immutable,
false => Mutability::Mutable,
}
}
}

/// Qualified type
Expand All @@ -2449,6 +2457,10 @@ impl CQualTypeId {
ctype,
}
}

pub fn mutability(self) -> Mutability {
self.qualifiers.mutability()
}
}

// TODO: these may be interesting, but I'm not sure if they fit here:
Expand Down
10 changes: 2 additions & 8 deletions c2rust-transpile/src/convert_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::renamer::*;
use crate::translator::variadic::mk_va_list_ty;
use crate::TranspilerConfig;
use crate::{CrateSet, ExternCrate};
use c2rust_ast_builder::{mk, properties::*};
use c2rust_ast_builder::mk;
use c2rust_rust_tools::RustEdition;
use failure::format_err;
use indexmap::IndexSet;
Expand Down Expand Up @@ -170,13 +170,7 @@ impl TypeConverter {
let param = mk().angle_bracketed_args(vec![pointee_ty]);
Ok(mk().path_ty(vec![mk().path_segment_with_args("Option", param)]))
} else {
let mutbl = if qtype.qualifiers.is_const {
Mutability::Immutable
} else {
Mutability::Mutable
};

Ok(mk().set_mutbl(mutbl).ptr_ty(pointee_ty))
Ok(mk().set_mutbl(qtype.mutability()).ptr_ty(pointee_ty))
}
}

Expand Down
6 changes: 1 addition & 5 deletions c2rust-transpile/src/translator/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,11 +341,7 @@ impl<'c> Translation<'c> {
typ: CQualTypeId,
) -> TranslationResult<ConvertedFunctionParam> {
if self.ast_context.is_va_list(typ.ctype) {
let mutbl = if typ.qualifiers.is_const {
Mutability::Immutable
} else {
Mutability::Mutable
};
let mutbl = typ.mutability();
let ty = mk().abs_path_ty(vec!["core", "ffi", "VaList"]);
return Ok(ConvertedFunctionParam { mutbl, ty });
}
Expand Down
7 changes: 1 addition & 6 deletions c2rust-transpile/src/translator/literals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,13 +193,8 @@ impl<'c> Translation<'c> {
}))
} else {
Ok(val.and_then(|val| {
let mutbl = if qty.qualifiers.is_const {
Mutability::Immutable
} else {
Mutability::Mutable
};
let local = mk().local(
mk().set_mutbl(mutbl).ident_pat(&fresh_name),
mk().set_mutbl(qty.mutability()).ident_pat(&fresh_name),
Some(fresh_ty),
Some(val),
);
Expand Down
16 changes: 4 additions & 12 deletions c2rust-transpile/src/translator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2630,11 +2630,7 @@ impl<'c> Translation<'c> {
self.convert_type(typ.ctype)?
};

let mutbl = if typ.qualifiers.is_const {
Mutability::Immutable
} else {
Mutability::Mutable
};
let mutbl = typ.mutability();

Ok(ConvertedVariable { ty, mutbl, init })
}
Expand Down Expand Up @@ -3085,7 +3081,7 @@ impl<'c> Translation<'c> {

if let Some(ty) = self
.ast_context
.type_for_kind(&kind_with_declared_args)
.try_type_for_kind(&kind_with_declared_args)
.map(CQualTypeId::new)
{
let ty = self.convert_type(ty.ctype)?;
Expand Down Expand Up @@ -3270,14 +3266,10 @@ impl<'c> Translation<'c> {
// but the function's declaration will.
let kind_with_declared_args =
self.ast_context.fn_decl_ty_with_declared_args(func_decl);
let func_ty = self
.ast_context
.type_for_kind(&kind_with_declared_args)
.unwrap_or_else(|| panic!("no type for kind {kind_with_declared_args:?}"));
let func_ty = self.ast_context.type_for_kind(&kind_with_declared_args);
let func_ptr_ty = self
.ast_context
.type_for_kind(&CTypeKind::Pointer(CQualTypeId::new(func_ty)))
.unwrap_or_else(|| panic!("no type for kind {kind_with_declared_args:?}"));
.type_for_kind(&CTypeKind::Pointer(CQualTypeId::new(func_ty)));

CQualTypeId::new(func_ptr_ty)
} else {
Expand Down
6 changes: 1 addition & 5 deletions c2rust-transpile/src/translator/operators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -640,11 +640,7 @@ impl<'c> Translation<'c> {

let one_type_id =
if let CTypeKind::Pointer(..) = self.ast_context.resolve_type(arg_type.ctype).kind {
CQualTypeId::new(
self.ast_context
.type_for_kind(&CTypeKind::Int)
.ok_or_else(|| format_err!("couldn't find type for CTypeKind::Int"))?,
)
CQualTypeId::new(self.ast_context.type_for_kind(&CTypeKind::Int))
} else {
arg_type
};
Expand Down
117 changes: 94 additions & 23 deletions c2rust-transpile/src/translator/pointers.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::ops::Index;

use c2rust_ast_builder::{mk, properties::Mutability};
use c2rust_ast_exporter::clang_ast::LRValue;
use c2rust_rust_tools::RustEdition;
use failure::{err_msg, format_err};
use std::ops::Index;
use syn::{BinOp, Expr, Type, UnOp};

use crate::c_ast::CUnOp;
Expand Down Expand Up @@ -110,16 +110,14 @@ impl<'c> Translation<'c> {

let mut needs_cast = false;
let mut ref_cast_pointee_ty = None;
let mutbl = if pointee_cty.qualifiers.is_const {
Mutability::Immutable
} else if ctx.is_const {
let mutbl = if ctx.is_const && !pointee_cty.qualifiers.is_const {
// const contexts aren't able to use &mut, so we work around that
// by using & and an extra cast through & to *const to *mut
// TODO: Rust 1.83: Allowed, so this can be removed.
needs_cast = true;
Mutability::Immutable
} else {
Mutability::Mutable
pointee_cty.mutability()
};

// Narrow string literals are translated directly as `[u8; N]` literals when their address
Expand Down Expand Up @@ -485,17 +483,68 @@ impl<'c> Translation<'c> {

WithStmts::new_val(transmute_expr(intptr_t, target_ty, val)).set_unsafe()
}))
} else if source_ty_kind.is_bool() {
self.use_crate(ExternCrate::Libc);
Ok(val.map(|mut val| {
// First cast the boolean to pointer size
val = mk().cast_expr(val, mk().abs_path_ty(vec!["libc", "size_t"]));
mk().cast_expr(val, target_ty)
}))
} else if let &CTypeKind::Enum(..) = source_ty_kind {
val.try_map(|val| self.convert_cast_from_enum(target_cty, val))
} else
// Rust 1.90: `const_strict_provenance` feature added
// Rust 1.91: stabilized
if ctx.is_const && self.tcfg.edition < RustEdition::Edition2024 {
if source_ty_kind.is_bool() {
self.use_crate(ExternCrate::Libc);
Ok(val.map(|mut val| {
// First cast the boolean to pointer size
val = mk().cast_expr(val, mk().abs_path_ty(vec!["libc", "size_t"]));
mk().cast_expr(val, target_ty)
}))
} else if let &CTypeKind::Enum(..) = source_ty_kind {
val.try_map(|val| self.convert_cast_from_enum(target_cty, val))
} else {
Ok(val.map(|val| mk().cast_expr(val, target_ty)))
}
} else {
Ok(val.map(|val| mk().cast_expr(val, target_ty)))
// First cast the value to `usize`.
let source_type_kind = &self.ast_context.resolve_type(source_cty).kind;
let size_type_id = self.ast_context.type_for_kind(&CTypeKind::Size);

let val = if let &CTypeKind::Enum(..) = source_type_kind {
val.try_map(|val| self.convert_cast_from_enum(size_type_id, val))?
} else {
let size_type_rs = self.convert_type(size_type_id)?;
val.map(|val| mk().cast_expr(val, size_type_rs))
};

// Then convert the `usize` into a pointer.
let pointee_type_id = self
.ast_context
.get_pointee_qual_type(target_cty)
.expect("target type must be a pointer");
let mutability = pointee_type_id.mutability();

let fn_name = match self.tcfg.edition {
RustEdition::Edition2021 => {
// Rust 1.76: feature name changed to `exposed_provenance[_mut]`
// Rust 1.84: stabilized
self.use_feature("strict_provenance");

// Rust 1.79: method name changed to `with_exposed_provenance[_mut]`
match mutability {
Mutability::Immutable => "from_exposed_addr",
Mutability::Mutable => "from_exposed_addr_mut",
}
}
RustEdition::Edition2024 => match mutability {
Mutability::Immutable => "with_exposed_provenance",
Mutability::Mutable => "with_exposed_provenance_mut",
},
};
let pointee_type_rs = self.convert_pointee_type(pointee_type_id.ctype)?;
let type_args = mk().angle_bracketed_args(vec![pointee_type_rs]);
let fn_expr = mk().abs_path_expr(vec![
mk().path_segment("core"),
mk().path_segment("ptr"),
mk().path_segment_with_args(fn_name, type_args),
]);
let val = val.map(|val| mk().call_expr(fn_expr, vec![val]));

Ok(val)
}
}

Expand All @@ -514,18 +563,40 @@ impl<'c> Translation<'c> {
));
}

let target_ty = self.convert_type(target_cty)?;
let source_ty = self.convert_type(source_cty)?;
let target_ty_kind = &self.ast_context.resolve_type(target_cty).kind;
let target_type_rs = self.convert_type(target_cty)?;

if self.ast_context.is_function_pointer(source_cty) {
let source_ty = self.convert_type(source_cty)?;

Ok(val.and_then(|val| {
WithStmts::new_val(transmute_expr(source_ty, target_ty, val)).set_unsafe()
WithStmts::new_val(transmute_expr(source_ty, target_type_rs, val)).set_unsafe()
}))
} else if let &CTypeKind::Enum(enum_decl_id) = target_ty_kind {
val.try_map(|val| self.convert_cast_to_enum(ctx, target_cty, enum_decl_id, expr, val))
} else {
Ok(val.map(|val| mk().cast_expr(val, target_ty)))
// First convert the pointer to `usize`.
let method_name = match self.tcfg.edition {
RustEdition::Edition2021 => {
// Rust 1.76: feature name changed to `exposed_provenance`
// Rust 1.84: stabilized
self.use_feature("strict_provenance");

// Rust 1.79: method name changed to `expose_provenance`
"expose_addr"
}
RustEdition::Edition2024 => "expose_provenance",
};

let val = val.map(|val| mk().method_call_expr(val, method_name, vec![]));

// Then cast the `usize` to the target type.
let target_ty_kind = &self.ast_context.resolve_type(target_cty).kind;

if let &CTypeKind::Enum(enum_decl_id) = target_ty_kind {
val.try_map(|val| {
self.convert_cast_to_enum(ctx, target_cty, enum_decl_id, expr, val)
})
} else {
Ok(val.map(|val| mk().cast_expr(val, target_type_rs)))
}
}
}

Expand Down
Loading
Loading