authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-12-31 17:33:55-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-12-31 17:33:55-05:00
log5749f706ef866b3c77d6fb8fda9ed08e5c118f58
tree0f69b721e1728851a685b2596d98c63b88654488
parent39ee3bc0ecdfde43e6fa98ee454a0115b3cb7390
signaturelock-open Commit is signed but in an unrecognized format.

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.

2 files changed, 22 insertions(+), 13 deletions(-)

src-self-hosted/translate_c.zig+13-13
...@@ -2213,32 +2213,32 @@ fn transUnaryExprOrTypeTraitExpr(...@@ -2213,32 +2213,32 @@ fn transUnaryExprOrTypeTraitExpr(
2213 return maybeSuppressResult(rp, scope, result_used, &builtin_node.base);2213 return maybeSuppressResult(rp, scope, result_used, &builtin_node.base);
2214}2214}
22152215
2216fn qualTypeHaswrappingOverflow(qt: ZigClangQualType) bool {2216fn qualTypeHasWrappingOverflow(qt: ZigClangQualType) bool {
2217 if (cIsSignedInteger(qt) or cIsFloating(qt)) {2217 if (cIsUnsignedInteger(qt)) {
2218 // float and signed integer overflow is undefined behavior.
2219 return false;
2220 } else {
2221 // unsigned integer overflow wraps around.2218 // unsigned integer overflow wraps around.
2222 return true;2219 return true;
2220 } else {
2221 // float, signed integer, and pointer overflow is undefined behavior.
2222 return false;
2223 }2223 }
2224}2224}
22252225
2226fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnaryOperator, used: ResultUsed) TransError!*ast.Node {2226fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnaryOperator, used: ResultUsed) TransError!*ast.Node {
2227 const op_expr = ZigClangUnaryOperator_getSubExpr(stmt);2227 const op_expr = ZigClangUnaryOperator_getSubExpr(stmt);
2228 switch (ZigClangUnaryOperator_getOpcode(stmt)) {2228 switch (ZigClangUnaryOperator_getOpcode(stmt)) {
2229 .PostInc => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))2229 .PostInc => if (qualTypeHasWrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
2230 return transCreatePostCrement(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used)2230 return transCreatePostCrement(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used)
2231 else2231 else
2232 return transCreatePostCrement(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", used),2232 return transCreatePostCrement(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", used),
2233 .PostDec => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))2233 .PostDec => if (qualTypeHasWrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
2234 return transCreatePostCrement(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used)2234 return transCreatePostCrement(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used)
2235 else2235 else
2236 return transCreatePostCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used),2236 return transCreatePostCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used),
2237 .PreInc => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))2237 .PreInc => if (qualTypeHasWrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
2238 return transCreatePreCrement(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used)2238 return transCreatePreCrement(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used)
2239 else2239 else
2240 return transCreatePreCrement(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", used),2240 return transCreatePreCrement(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", used),
2241 .PreDec => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))2241 .PreDec => if (qualTypeHasWrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
2242 return transCreatePreCrement(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used)2242 return transCreatePreCrement(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used)
2243 else2243 else
2244 return transCreatePreCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used),2244 return transCreatePreCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used),
...@@ -2258,7 +2258,7 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnar...@@ -2258,7 +2258,7 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnar
2258 },2258 },
2259 .Plus => return transExpr(rp, scope, op_expr, used, .r_value),2259 .Plus => return transExpr(rp, scope, op_expr, used, .r_value),
2260 .Minus => {2260 .Minus => {
2261 if (!qualTypeHaswrappingOverflow(ZigClangExpr_getType(op_expr))) {2261 if (!qualTypeHasWrappingOverflow(ZigClangExpr_getType(op_expr))) {
2262 const op_node = try transCreateNodePrefixOp(rp.c, .Negation, .Minus, "-");2262 const op_node = try transCreateNodePrefixOp(rp.c, .Negation, .Minus, "-");
2263 op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);2263 op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
2264 return &op_node.base;2264 return &op_node.base;
...@@ -2426,15 +2426,15 @@ fn transCreatePostCrement(...@@ -2426,15 +2426,15 @@ fn transCreatePostCrement(
24262426
2427fn transCompoundAssignOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundAssignOperator, used: ResultUsed) TransError!*ast.Node {2427fn transCompoundAssignOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundAssignOperator, used: ResultUsed) TransError!*ast.Node {
2428 switch (ZigClangCompoundAssignOperator_getOpcode(stmt)) {2428 switch (ZigClangCompoundAssignOperator_getOpcode(stmt)) {
2429 .MulAssign => if (qualTypeHaswrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt)))2429 .MulAssign => if (qualTypeHasWrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt)))
2430 return transCreateCompoundAssign(rp, scope, stmt, .AssignMulWrap, .AsteriskPercentEqual, "*%=", .MulWrap, .AsteriskPercent, "*%", used)2430 return transCreateCompoundAssign(rp, scope, stmt, .AssignMulWrap, .AsteriskPercentEqual, "*%=", .MulWrap, .AsteriskPercent, "*%", used)
2431 else2431 else
2432 return transCreateCompoundAssign(rp, scope, stmt, .AssignMul, .AsteriskEqual, "*=", .Mul, .Asterisk, "*", used),2432 return transCreateCompoundAssign(rp, scope, stmt, .AssignMul, .AsteriskEqual, "*=", .Mul, .Asterisk, "*", used),
2433 .AddAssign => if (qualTypeHaswrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt)))2433 .AddAssign => if (qualTypeHasWrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt)))
2434 return transCreateCompoundAssign(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", .AddWrap, .PlusPercent, "+%", used)2434 return transCreateCompoundAssign(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", .AddWrap, .PlusPercent, "+%", used)
2435 else2435 else
2436 return transCreateCompoundAssign(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", .Add, .Plus, "+", used),2436 return transCreateCompoundAssign(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", .Add, .Plus, "+", used),
2437 .SubAssign => if (qualTypeHaswrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt)))2437 .SubAssign => if (qualTypeHasWrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt)))
2438 return transCreateCompoundAssign(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", .SubWrap, .MinusPercent, "-%", used)2438 return transCreateCompoundAssign(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", .SubWrap, .MinusPercent, "-%", used)
2439 else2439 else
2440 return transCreateCompoundAssign(rp, scope, stmt, .AssignSub, .MinusPercentEqual, "-=", .Sub, .Minus, "-", used),2440 return transCreateCompoundAssign(rp, scope, stmt, .AssignSub, .MinusPercentEqual, "-=", .Sub, .Minus, "-", used),
test/translate_c.zig+9
...@@ -1777,6 +1777,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1777,6 +1777,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1777 \\ a++;1777 \\ a++;
1778 \\ return a;1778 \\ return a;
1779 \\}1779 \\}
1780 \\int *foo3(int *a) {
1781 \\ a++;
1782 \\ return a;
1783 \\}
1780 , &[_][]const u8{1784 , &[_][]const u8{
1781 \\pub export fn foo1(_arg_a_1: c_uint) c_uint {1785 \\pub export fn foo1(_arg_a_1: c_uint) c_uint {
1782 \\ var a_1 = _arg_a_1;1786 \\ var a_1 = _arg_a_1;
...@@ -1788,6 +1792,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1788,6 +1792,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1788 \\ a_2 += 1;1792 \\ a_2 += 1;
1789 \\ return a_2;1793 \\ return a_2;
1790 \\}1794 \\}
1795 \\pub export fn foo3(_arg_a_3: [*c]c_int) [*c]c_int {
1796 \\ var a_3 = _arg_a_3;
1797 \\ a_3 += 1;
1798 \\ return a_3;
1799 \\}
1791 });1800 });
17921801
1793 cases.add("deref function pointer",1802 cases.add("deref function pointer",