Skip to content

Commit 95b71c3

Browse files
committed
transpile: use expected types when translating binary operators
1 parent 3f1787f commit 95b71c3

File tree

3 files changed

+54
-14
lines changed

3 files changed

+54
-14
lines changed

c2rust-transpile/src/c_ast/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1383,6 +1383,24 @@ impl BinOp {
13831383
Comma => ", ",
13841384
}
13851385
}
1386+
1387+
/// Does the rust equivalent of this operator have type (T, T) -> T?
1388+
pub fn all_types_same(&self) -> bool {
1389+
use BinOp::*;
1390+
match self {
1391+
Multiply => true,
1392+
Divide => true,
1393+
Modulus => true,
1394+
Add => true,
1395+
Subtract => true,
1396+
ShiftLeft => true,
1397+
ShiftRight => true,
1398+
BitAnd => true,
1399+
BitXor => true,
1400+
BitOr => true,
1401+
_ => false,
1402+
}
1403+
}
13861404
}
13871405

13881406
impl Display for BinOp {

c2rust-transpile/src/translator/mod.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3520,10 +3520,17 @@ impl<'c> Translation<'c> {
35203520
if self.casting_simd_builtin_call(expr, is_explicit, kind) {
35213521
return Ok(val);
35223522
}
3523+
3524+
let target_ty = if kind == CastKind::ArrayToPointerDecay {
3525+
ty
3526+
} else {
3527+
override_ty.unwrap_or(ty)
3528+
};
3529+
35233530
self.convert_cast(
35243531
ctx,
35253532
source_ty,
3526-
ty,
3533+
target_ty,
35273534
val,
35283535
Some(expr),
35293536
Some(kind),
@@ -3612,7 +3619,15 @@ impl<'c> Translation<'c> {
36123619
}
36133620

36143621
Binary(type_id, op, lhs, rhs, opt_lhs_type_id, opt_res_type_id) => self
3615-
.convert_binary_expr(ctx, type_id, op, lhs, rhs, opt_lhs_type_id, opt_res_type_id)
3622+
.convert_binary_expr(
3623+
ctx,
3624+
override_ty.unwrap_or(type_id),
3625+
op,
3626+
lhs,
3627+
rhs,
3628+
opt_lhs_type_id,
3629+
opt_res_type_id,
3630+
)
36163631
.map_err(|e| e.add_loc(self.ast_context.display_loc(src_loc))),
36173632

36183633
ArraySubscript(_, ref lhs, ref rhs, _) => {

c2rust-transpile/src/translator/operators.rs

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -104,25 +104,32 @@ impl<'c> Translation<'c> {
104104

105105
let ty = self.convert_type(type_id.ctype)?;
106106

107-
let lhs_type_id = self
108-
.ast_context
109-
.index(lhs)
110-
.kind
111-
.get_qual_type()
112-
.ok_or_else(|| {
113-
format_translation_err!(
114-
self.ast_context.display_loc(lhs_loc),
115-
"bad lhs type for assignment"
116-
)
117-
})?;
107+
let lhs_kind = &self.ast_context.index(lhs).kind;
108+
let mut lhs_type_id = lhs_kind.get_qual_type().ok_or_else(|| {
109+
format_translation_err!(
110+
self.ast_context.display_loc(lhs_loc),
111+
"bad lhs type for assignment"
112+
)
113+
})?;
118114
let rhs_kind = &self.ast_context.index(rhs).kind;
119-
let rhs_type_id = rhs_kind.get_qual_type().ok_or_else(|| {
115+
let mut rhs_type_id = rhs_kind.get_qual_type().ok_or_else(|| {
120116
format_translation_err!(
121117
self.ast_context.display_loc(rhs_loc),
122118
"bad rhs type for assignment"
123119
)
124120
})?;
125121

122+
// If this is an operation like addition or bitxor that (for rust built-ins) accepts
123+
// and produces values all of the same type, then propagate our expected type down
124+
// to the translation of our argument expressions.
125+
if op.all_types_same()
126+
&& !self.ast_context.index(lhs_type_id.ctype).kind.is_pointer()
127+
&& !self.ast_context.index(rhs_type_id.ctype).kind.is_pointer()
128+
{
129+
lhs_type_id = type_id;
130+
rhs_type_id = type_id;
131+
}
132+
126133
if ctx.is_unused() {
127134
Ok(self
128135
.convert_expr(ctx, lhs, Some(lhs_type_id))?

0 commit comments

Comments
 (0)