Commit 5749f706ef

Andrew Kelley <andrew@ziglang.org>
2019-12-31 23:33:55
translate-c: non-wrapping operator for pointer arithmetic
According to C11 6.5.6.8, pointer arithmetic may not overflow. In fact, it may not even go more than 1 past the end of an object, or UB occurs. This is the same as Zig pointer arithmetic semantics, and so the `+` and `+=` operators rather than `+%` and `+%=` are appropriate for C-translated pointer arithmetic.
1 parent 39ee3bc
Changed files (2)
src-self-hosted
test
src-self-hosted/translate_c.zig
@@ -2213,32 +2213,32 @@ fn transUnaryExprOrTypeTraitExpr(
     return maybeSuppressResult(rp, scope, result_used, &builtin_node.base);
 }
 
-fn qualTypeHaswrappingOverflow(qt: ZigClangQualType) bool {
-    if (cIsSignedInteger(qt) or cIsFloating(qt)) {
-        // float and signed integer overflow is undefined behavior.
-        return false;
-    } else {
+fn qualTypeHasWrappingOverflow(qt: ZigClangQualType) bool {
+    if (cIsUnsignedInteger(qt)) {
         // unsigned integer overflow wraps around.
         return true;
+    } else {
+        // float, signed integer, and pointer overflow is undefined behavior.
+        return false;
     }
 }
 
 fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnaryOperator, used: ResultUsed) TransError!*ast.Node {
     const op_expr = ZigClangUnaryOperator_getSubExpr(stmt);
     switch (ZigClangUnaryOperator_getOpcode(stmt)) {
-        .PostInc => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
+        .PostInc => if (qualTypeHasWrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
             return transCreatePostCrement(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used)
         else
             return transCreatePostCrement(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", used),
-        .PostDec => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
+        .PostDec => if (qualTypeHasWrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
             return transCreatePostCrement(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used)
         else
             return transCreatePostCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used),
-        .PreInc => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
+        .PreInc => if (qualTypeHasWrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
             return transCreatePreCrement(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used)
         else
             return transCreatePreCrement(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", used),
-        .PreDec => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
+        .PreDec => if (qualTypeHasWrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
             return transCreatePreCrement(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used)
         else
             return transCreatePreCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used),
@@ -2258,7 +2258,7 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnar
         },
         .Plus => return transExpr(rp, scope, op_expr, used, .r_value),
         .Minus => {
-            if (!qualTypeHaswrappingOverflow(ZigClangExpr_getType(op_expr))) {
+            if (!qualTypeHasWrappingOverflow(ZigClangExpr_getType(op_expr))) {
                 const op_node = try transCreateNodePrefixOp(rp.c, .Negation, .Minus, "-");
                 op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
                 return &op_node.base;
@@ -2426,15 +2426,15 @@ fn transCreatePostCrement(
 
 fn transCompoundAssignOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundAssignOperator, used: ResultUsed) TransError!*ast.Node {
     switch (ZigClangCompoundAssignOperator_getOpcode(stmt)) {
-        .MulAssign => if (qualTypeHaswrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt)))
+        .MulAssign => if (qualTypeHasWrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt)))
             return transCreateCompoundAssign(rp, scope, stmt, .AssignMulWrap, .AsteriskPercentEqual, "*%=", .MulWrap, .AsteriskPercent, "*%", used)
         else
             return transCreateCompoundAssign(rp, scope, stmt, .AssignMul, .AsteriskEqual, "*=", .Mul, .Asterisk, "*", used),
-        .AddAssign => if (qualTypeHaswrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt)))
+        .AddAssign => if (qualTypeHasWrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt)))
             return transCreateCompoundAssign(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", .AddWrap, .PlusPercent, "+%", used)
         else
             return transCreateCompoundAssign(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", .Add, .Plus, "+", used),
-        .SubAssign => if (qualTypeHaswrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt)))
+        .SubAssign => if (qualTypeHasWrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt)))
             return transCreateCompoundAssign(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", .SubWrap, .MinusPercent, "-%", used)
         else
             return transCreateCompoundAssign(rp, scope, stmt, .AssignSub, .MinusPercentEqual, "-=", .Sub, .Minus, "-", used),
test/translate_c.zig
@@ -1777,6 +1777,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    a++;
         \\    return a;
         \\}
+        \\int *foo3(int *a) {
+        \\    a++;
+        \\    return a;
+        \\}
     , &[_][]const u8{
         \\pub export fn foo1(_arg_a_1: c_uint) c_uint {
         \\    var a_1 = _arg_a_1;
@@ -1788,6 +1792,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    a_2 += 1;
         \\    return a_2;
         \\}
+        \\pub export fn foo3(_arg_a_3: [*c]c_int) [*c]c_int {
+        \\    var a_3 = _arg_a_3;
+        \\    a_3 += 1;
+        \\    return a_3;
+        \\}
     });
 
     cases.add("deref function pointer",