diff --git a/tests/cast.c b/tests/cast.c index 02ae14fa1..8c250df76 100644 --- a/tests/cast.c +++ b/tests/cast.c @@ -117,9 +117,15 @@ void test_static_array() is_eq('e', TEST2[3]); // can distinguish character at same column in different lines } +void castbitwise() { + pcre_uint32 x = 0xff; + x &= ~0x3c; + is_eq(x, 0xc3); +} + int main() { - plan(36); + plan(37); START_TEST(cast); START_TEST(castbool); @@ -216,5 +222,8 @@ int main() diag("Compare with static array") test_static_array(); + diag("Cast with compound assign operator") + castbitwise(); + done_testing(); } diff --git a/transpiler/cast.go b/transpiler/cast.go index 79cf9632d..ec3b0e7c8 100644 --- a/transpiler/cast.go +++ b/transpiler/cast.go @@ -9,6 +9,7 @@ import ( "github.com/elliotchance/c2go/program" "github.com/elliotchance/c2go/types" "github.com/elliotchance/c2go/util" + "go/token" ) func transpileImplicitCastExpr(n *ast.ImplicitCastExpr, p *program.Program, exprIsStmt bool) ( @@ -34,6 +35,9 @@ func transpileImplicitCastExpr(n *ast.ImplicitCastExpr, p *program.Program, expr return } } + if isCastToUnsignedOfUnaryComplement(n, p) { + return swapCastAndComplement(n, p, exprIsStmt) + } expr, exprType, preStmts, postStmts, err = transpileToExpr(n.Children()[0], p, exprIsStmt) if err != nil { return nil, "", nil, nil, err @@ -65,6 +69,31 @@ func transpileImplicitCastExpr(n *ast.ImplicitCastExpr, p *program.Program, expr return } +func isCastToUnsignedOfUnaryComplement(n *ast.ImplicitCastExpr, p *program.Program) (ret bool) { + if !types.IsCInteger(p, n.Type) || !strings.Contains(n.Type, "unsigned ") { + return + } + cn, ok := n.Children()[0].(*ast.UnaryOperator) + if !ok || getTokenForOperator(cn.Operator) != token.XOR { + return + } + return types.IsCInteger(p, cn.Type) && !strings.Contains(cn.Type, "unsigned ") +} + +func swapCastAndComplement(n *ast.ImplicitCastExpr, p *program.Program, exprIsStmt bool) ( + expr goast.Expr, + exprType string, + preStmts []goast.Stmt, + postStmts []goast.Stmt, + err error) { + uo := n.Children()[0].(*ast.UnaryOperator) + unaryChildren := uo.ChildNodes + uo.ChildNodes = []ast.Node{n} + uo.Type = n.Type + n.ChildNodes = unaryChildren + return transpileToExpr(uo, p, exprIsStmt) +} + func transpileCStyleCastExpr(n *ast.CStyleCastExpr, p *program.Program, exprIsStmt bool) ( expr goast.Expr, exprType string, diff --git a/transpiler/operators.go b/transpiler/operators.go index 497f11ab2..443824f7c 100644 --- a/transpiler/operators.go +++ b/transpiler/operators.go @@ -337,6 +337,12 @@ func transpileCompoundAssignOperator( } } + switch operator { + case token.AND_ASSIGN, token.OR_ASSIGN, token.XOR_ASSIGN, token.AND_NOT_ASSIGN: + right, err = types.CastExpr(p, right, rightType, leftType) + p.AddMessage(p.GenerateWarningMessage(err, n)) + } + resolvedLeftType, err := types.ResolveType(p, leftType) if err != nil { p.AddMessage(p.GenerateWarningMessage(err, n))