Skip to content
Open
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: 6 additions & 0 deletions c2rust-transpile/src/c_ast/conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,12 @@ impl ConversionContext {
self.add_type(new_id, not_located(rust_type_kind));
self.processed_nodes
.insert(new_id, self::node_types::OTHER_TYPE);

let complex_kind = CTypeKind::Complex(CTypeId(new_id));
let new_id = self.id_mapper.fresh_id();
self.add_type(new_id, not_located(complex_kind));
self.processed_nodes
.insert(new_id, self::node_types::OTHER_TYPE);
}

// Continue popping Clang nodes off of the stack of nodes we have promised to visit
Expand Down
50 changes: 34 additions & 16 deletions c2rust-transpile/src/c_ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1336,35 +1336,53 @@ impl TypedAstContext {
let rhs_type_id =
self.ast_context.c_exprs[&rhs].kind.get_qual_type().unwrap();

let lhs_resolved_ty = self.ast_context.resolve_type(lhs_type_id.ctype);
let rhs_resolved_ty = self.ast_context.resolve_type(rhs_type_id.ctype);
let lhs_type_kind = &self.ast_context.resolve_type(lhs_type_id.ctype).kind;
let rhs_type_kind = &self.ast_context.resolve_type(rhs_type_id.ctype).kind;

if CTypeKind::PULLBACK_KINDS.contains(&lhs_resolved_ty.kind) {
if CTypeKind::PULLBACK_KINDS.contains(lhs_type_kind) {
Some(lhs_type_id)
} else if CTypeKind::PULLBACK_KINDS.contains(&rhs_resolved_ty.kind) {
} else if CTypeKind::PULLBACK_KINDS.contains(rhs_type_kind) {
Some(rhs_type_id)
} else {
None
}
}
CExprKind::Binary(_ty, op, lhs, rhs, _, _) => {
CExprKind::Binary(result_type_id, op, lhs, rhs, _, _) => {
let lhs_type_id =
self.ast_context.c_exprs[&lhs].kind.get_qual_type().unwrap();
let rhs_type_id =
self.ast_context.c_exprs[&rhs].kind.get_qual_type().unwrap();
let lhs_kind = &self.ast_context.c_exprs[&lhs].kind;
let lhs_type_id = lhs_kind.get_qual_type().unwrap();

let lhs_resolved_ty = self.ast_context.resolve_type(lhs_type_id.ctype);
let rhs_resolved_ty = self.ast_context.resolve_type(rhs_type_id.ctype);
let lhs_type_kind = &self.ast_context.resolve_type(lhs_type_id.ctype).kind;
let rhs_type_kind = &self.ast_context.resolve_type(rhs_type_id.ctype).kind;

let neither_ptr = !lhs_resolved_ty.kind.is_pointer()
&& !rhs_resolved_ty.kind.is_pointer();
if lhs_type_kind.is_pointer() || rhs_type_kind.is_pointer() {
return;
}

if op.all_types_same() && neither_ptr {
if CTypeKind::PULLBACK_KINDS.contains(&lhs_resolved_ty.kind) {
Some(lhs_type_id)
} else {
Some(rhs_type_id)
if op.all_types_same() {
let result_type_kind =
&self.ast_context.resolve_type(result_type_id.ctype).kind;

let mut result_type_id =
if CTypeKind::PULLBACK_KINDS.contains(lhs_type_kind) {
lhs_type_id
} else {
rhs_type_id
};

// For complex arithmetic, complex and real values can be mixed.
// See if a `Complex` version of the new result type exists.
if matches!(result_type_kind, CTypeKind::Complex(..)) {
let new_result_type_kind = CTypeKind::Complex(result_type_id.ctype);
let new_type_id = self
.ast_context
.type_for_kind(&new_result_type_kind)
.unwrap();
result_type_id.ctype = new_type_id;
}

Some(result_type_id)
} else if op.is_bitshift() {
Some(lhs_type_id)
} else {
Expand Down
99 changes: 55 additions & 44 deletions c2rust-transpile/src/translator/operators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,38 +85,47 @@ impl<'c> Translation<'c> {

// If this operation will (in Rust) take args of the same type, then propagate our
// expected type down to the translation of our argument expressions.
let lhs_resolved_ty = self.ast_context.resolve_type(lhs_type_id.ctype);
let rhs_resolved_ty = self.ast_context.resolve_type(rhs_type_id.ctype);
let expr_ty_kind = &self.ast_context.index(expr_type_id.ctype).kind;
let lhs_type_kind = &self.ast_context.resolve_type(lhs_type_id.ctype).kind;
let rhs_type_kind = &self.ast_context.resolve_type(rhs_type_id.ctype).kind;

// Addition and subtraction can accept one pointer argument for .offset(), in which
// case we don't want to homogenize arg types.
if !lhs_resolved_ty.kind.is_pointer()
&& !rhs_resolved_ty.kind.is_pointer()
&& !expr_ty_kind.is_pointer()
if !(op.is_pointer_arithmetic()
&& (lhs_type_kind.is_pointer() || rhs_type_kind.is_pointer()))
{
if op.all_types_same() {
// Ops like division and bitxor accept inputs of their expected result type.
lhs_type_id = expr_type_id;
rhs_type_id = expr_type_id;
} else if op.input_types_same() && lhs_resolved_ty.kind != rhs_resolved_ty.kind
{
lhs_type_id.ctype = expr_type_id.ctype;
rhs_type_id.ctype = expr_type_id.ctype;

// For complex arithmetic, complex and real values can be mixed.
let expr_type_kind =
&self.ast_context.resolve_type(expr_type_id.ctype).kind;
if let &CTypeKind::Complex(result_scalar_type_id) = expr_type_kind {
if !matches!(lhs_type_kind, CTypeKind::Complex(..)) {
lhs_type_id.ctype = result_scalar_type_id;
}

if !matches!(rhs_type_kind, CTypeKind::Complex(..)) {
rhs_type_id.ctype = result_scalar_type_id;
}
}
} else if op.input_types_same() && lhs_type_kind != rhs_type_kind {
// Ops like comparisons require argument types to match, but the result type
// doesn't inform us what type to choose. Select a synthetic definition of a
// portable rust type (e.g. u64 or usize) if either arg is one.
trace!(
"Binary op arg types differ: {:?} vs {:?}",
lhs_resolved_ty.kind,
rhs_resolved_ty.kind
lhs_type_kind,
rhs_type_kind
);
let ty = if CTypeKind::PULLBACK_KINDS.contains(&lhs_resolved_ty.kind) {
lhs_type_id
if CTypeKind::PULLBACK_KINDS.contains(&lhs_type_kind) {
rhs_type_id.ctype = lhs_type_id.ctype;
} else {
rhs_type_id
lhs_type_id.ctype = rhs_type_id.ctype;
};
lhs_type_id = ty;
rhs_type_id = ty;
} else if matches!(op, ShiftLeft | ShiftRight) {
lhs_type_id = expr_type_id;
} else if op.is_bitshift() {
lhs_type_id.ctype = expr_type_id.ctype;
}
}

Expand Down Expand Up @@ -271,31 +280,33 @@ impl<'c> Translation<'c> {
.get_qual_type()
.ok_or_else(|| format_err!("bad initial lhs type"))?;

// First, translate the rhs. Then, if it must match the lhs but doesn't, add a cast.
let mut rhs_translation = self.convert_expr(ctx.used(), rhs, Some(rhs_type_id))?;
let lhs_rhs_types_must_match = {
let lhs_resolved_ty = &self.ast_context.resolve_type(lhs_type_id.ctype);
let rhs_resolved_ty = &self.ast_context.resolve_type(rhs_type_id.ctype);
// Addition and subtraction can accept one pointer argument for .offset(), in which
// case we don't want to homogenize arg types.
let neither_ptr =
!lhs_resolved_ty.kind.is_pointer() && !rhs_resolved_ty.kind.is_pointer();

op.underlying_assignment().map_or(true, |op| {
if op.is_pointer_arithmetic() {
neither_ptr
} else {
op.is_arithmetic() || op.is_bitwise()
// First, translate the rhs.
let mut rhs_rs = self.convert_expr(ctx.used(), rhs, Some(rhs_type_id))?;

let lhs_type_kind = &self.ast_context.resolve_type(lhs_type_id.ctype).kind;
let rhs_type_kind = &self.ast_context.resolve_type(rhs_type_id.ctype).kind;

// Addition and subtraction can accept one pointer argument for .offset(), in which
// case we don't want to homogenize arg types.
if !(op.is_pointer_arithmetic()
&& (lhs_type_kind.is_pointer() || rhs_type_kind.is_pointer()))
{
if op
.underlying_assignment()
.map_or(true, |op| op.is_arithmetic() || op.is_bitwise())
{
// If the rhs must match the lhs but doesn't, add a cast.
// For compound assignment, use the compute type; for regular assignment, use lhs type.
let mut target_type_id = compute_lhs_type_id.unwrap_or(lhs_type_id);

// For complex arithmetic, complex and real values can be mixed.
if let &CTypeKind::Complex(lhs_scalar_type_id) = lhs_type_kind {
if !matches!(rhs_type_kind, CTypeKind::Complex(..)) {
target_type_id.ctype = lhs_scalar_type_id;
}
}
})
};
if lhs_rhs_types_must_match {
// For compound assignment, use the compute type; for regular assignment, use lhs type
let effective_lhs_ty = compute_lhs_type_id.unwrap_or(lhs_type_id);
if effective_lhs_ty.ctype != rhs_type_id.ctype {
let new_rhs_ty =
self.convert_type(compute_lhs_type_id.unwrap_or(lhs_type_id).ctype)?;
rhs_translation = rhs_translation.map(|val| mk().cast_expr(val, new_rhs_ty));

rhs_rs = self.make_cast(ctx.used(), rhs_type_id, target_type_id, rhs_rs)?;
}
}

Expand All @@ -306,7 +317,7 @@ impl<'c> Translation<'c> {
expr_type_id,
lhs,
rhs_type_id,
rhs_translation,
rhs_rs,
compute_lhs_type_id,
compute_res_type_id,
)
Expand Down
Loading