Commit 70cc1751ca

Ian Simonson <ian.simonson@protonmail.com>
2020-06-24 11:04:56
Translate-c fix rhs not cast on array access
Closes #5671. Checks if the rhs is integral and of differing or the same signedness. If they are different does an @intCast to the lhs type
1 parent 8b82c40
Changed files (2)
src-self-hosted/translate_c.zig
@@ -3268,7 +3268,14 @@ fn transCreateCompoundAssign(
     const lhs = ZigClangCompoundAssignOperator_getLHS(stmt);
     const rhs = ZigClangCompoundAssignOperator_getRHS(stmt);
     const loc = ZigClangCompoundAssignOperator_getBeginLoc(stmt);
-    const is_signed = cIsSignedInteger(getExprQualType(rp.c, lhs));
+    const lhs_qt = getExprQualType(rp.c, lhs);
+    const rhs_qt = getExprQualType(rp.c, rhs);
+    const is_signed = cIsSignedInteger(lhs_qt);
+    const requires_int_cast = blk: {
+        const are_integers = cIsInteger(lhs_qt) and cIsInteger(rhs_qt);
+        const are_same_sign = cIsSignedInteger(lhs_qt) == cIsSignedInteger(rhs_qt);
+        break :blk are_integers and !are_same_sign;
+    };
     if (used == .unused) {
         // common case
         // c: lhs += rhs
@@ -3295,15 +3302,18 @@ fn transCreateCompoundAssign(
 
         const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
         const eq_token = try appendToken(rp.c, assign_tok_id, assign_bytes);
-        var rhs_node = if (is_shift)
+        var rhs_node = if (is_shift or requires_int_cast)
             try transExprCoercing(rp, scope, rhs, .used, .r_value)
         else
             try transExpr(rp, scope, rhs, .used, .r_value);
 
-        if (is_shift) {
+        if (is_shift or requires_int_cast) {
             const cast_node = try rp.c.createBuiltinCall("@intCast", 2);
-            const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc);
-            cast_node.params()[0] = rhs_type;
+            const cast_to_type = if (is_shift)
+                try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc)
+            else
+                try transQualType(rp, getExprQualType(rp.c, lhs), loc);
+            cast_node.params()[0] = cast_to_type;
             _ = try appendToken(rp.c, .Comma, ",");
             cast_node.params()[1] = rhs_node;
             cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
@@ -3358,10 +3368,13 @@ fn transCreateCompoundAssign(
         const bin_token = try appendToken(rp.c, bin_tok_id, bin_bytes);
         var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
 
-        if (is_shift) {
+        if (is_shift or requires_int_cast) {
             const cast_node = try rp.c.createBuiltinCall("@intCast", 2);
-            const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc);
-            cast_node.params()[0] = rhs_type;
+            const cast_to_type = if (is_shift)
+                try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc)
+            else
+                try transQualType(rp, getExprQualType(rp.c, lhs), loc);
+            cast_node.params()[0] = cast_to_type;
             _ = try appendToken(rp.c, .Comma, ",");
             cast_node.params()[1] = rhs_node;
             cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
test/run_translated_c.zig
@@ -268,5 +268,77 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
         \\    if (count != 4) abort();
         \\    return 0;
         \\}
-    ,"");
+    , "");
+
+    cases.add("array value type casts properly",
+        \\#include <stdlib.h>
+        \\unsigned int choose[53][10];
+        \\static int hash_binary(int k)
+        \\{
+        \\    choose[0][k] = 3;
+        \\    int sum = 0;
+        \\    sum += choose[0][k];
+        \\    return sum;
+        \\}
+        \\
+        \\int main() {
+        \\    int s = hash_binary(4);
+        \\    if (s != 3) abort();
+        \\    return 0;
+        \\}
+    , "");
+
+    cases.add("array value type casts properly use +=",
+        \\#include <stdlib.h>
+        \\static int hash_binary(int k)
+        \\{
+        \\    unsigned int choose[1][1] = {{3}};
+        \\    int sum = -1;
+        \\    int prev = 0;
+        \\    prev = sum += choose[0][0];
+        \\    if (sum != 2) abort();
+        \\    return sum + prev;
+        \\}
+        \\
+        \\int main() {
+        \\    int x = hash_binary(4);
+        \\    if (x != 4) abort();
+        \\    return 0;
+        \\}
+    , "");
+
+    cases.add("ensure array casts outisde +=",
+        \\#include <stdlib.h>
+        \\static int hash_binary(int k)
+        \\{
+        \\    unsigned int choose[3] = {1, 2, 3};
+        \\    int sum = -2;
+        \\    int prev = sum + choose[k];
+        \\    if (prev != 0) abort();
+        \\    return sum + prev;
+        \\}
+        \\
+        \\int main() {
+        \\    int x = hash_binary(1);
+        \\    if (x != -2) abort();
+        \\    return 0;
+        \\}
+    , "");
+
+    cases.add("array cast int to uint",
+        \\#include <stdlib.h>
+        \\static unsigned int hash_binary(int k)
+        \\{
+        \\    int choose[3] = {-1, -2, 3};
+        \\    unsigned int sum = 2;
+        \\    sum += choose[k];
+        \\    return sum;
+        \\}
+        \\
+        \\int main() {
+        \\    unsigned int x = hash_binary(1);
+        \\    if (x != 0) abort();
+        \\    return 0;
+        \\}
+    , "");
 }