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.
This commit is contained in:
Andrew Kelley 2019-12-31 17:33:55 -05:00
parent 39ee3bc0ec
commit 5749f706ef
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
2 changed files with 22 additions and 13 deletions

View File

@ -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),

View File

@ -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",