| ... | @@ -1170,7 +1170,7 @@ fn transBinaryOperator( | ... | @@ -1170,7 +1170,7 @@ fn transBinaryOperator( |
| 1170 | } | 1170 | } |
| 1171 | }, | 1171 | }, |
| 1172 | .Div => { | 1172 | .Div => { |
| 1173 | if (!cIsUnsignedInteger(qt)) { | 1173 | if (cIsSignedInteger(qt)) { |
| 1174 | // signed integer division uses @divTrunc | 1174 | // signed integer division uses @divTrunc |
| 1175 | const div_trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@divTrunc"); | 1175 | const div_trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@divTrunc"); |
| 1176 | try div_trunc_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value)); | 1176 | try div_trunc_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value)); |
| ... | @@ -1182,7 +1182,7 @@ fn transBinaryOperator( | ... | @@ -1182,7 +1182,7 @@ fn transBinaryOperator( |
| 1182 | } | 1182 | } |
| 1183 | }, | 1183 | }, |
| 1184 | .Rem => { | 1184 | .Rem => { |
| 1185 | if (!cIsUnsignedInteger(qt)) { | 1185 | if (cIsSignedInteger(qt)) { |
| 1186 | // signed integer division uses @rem | 1186 | // signed integer division uses @rem |
| 1187 | const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem"); | 1187 | const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem"); |
| 1188 | try rem_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value)); | 1188 | try rem_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value)); |
| ... | @@ -3018,6 +3018,8 @@ fn transCompoundAssignOperator(rp: RestorePoint, scope: *Scope, stmt: *const Zig | ... | @@ -3018,6 +3018,8 @@ fn transCompoundAssignOperator(rp: RestorePoint, scope: *Scope, stmt: *const Zig |
| 3018 | return transCreateCompoundAssign(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", .SubWrap, .MinusPercent, "-%", used) | 3018 | return transCreateCompoundAssign(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", .SubWrap, .MinusPercent, "-%", used) |
| 3019 | else | 3019 | else |
| 3020 | return transCreateCompoundAssign(rp, scope, stmt, .AssignSub, .MinusPercentEqual, "-=", .Sub, .Minus, "-", used), | 3020 | return transCreateCompoundAssign(rp, scope, stmt, .AssignSub, .MinusPercentEqual, "-=", .Sub, .Minus, "-", used), |
| | 3021 | .DivAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignDiv, .SlashEqual, "/=", .Div, .Slash, "/", used), |
| | 3022 | .RemAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignMod, .PercentEqual, "%=", .Mod, .Percent, "%", used), |
| 3021 | .ShlAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitShiftLeft, .AngleBracketAngleBracketLeftEqual, "<<=", .BitShiftLeft, .AngleBracketAngleBracketLeft, "<<", used), | 3023 | .ShlAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitShiftLeft, .AngleBracketAngleBracketLeftEqual, "<<=", .BitShiftLeft, .AngleBracketAngleBracketLeft, "<<", used), |
| 3022 | .ShrAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitShiftRight, .AngleBracketAngleBracketRightEqual, ">>=", .BitShiftRight, .AngleBracketAngleBracketRight, ">>", used), | 3024 | .ShrAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitShiftRight, .AngleBracketAngleBracketRightEqual, ">>=", .BitShiftRight, .AngleBracketAngleBracketRight, ">>", used), |
| 3023 | .AndAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitAnd, .AmpersandEqual, "&=", .BitAnd, .Ampersand, "&", used), | 3025 | .AndAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitAnd, .AmpersandEqual, "&=", .BitAnd, .Ampersand, "&", used), |
| ... | @@ -3046,13 +3048,37 @@ fn transCreateCompoundAssign( | ... | @@ -3046,13 +3048,37 @@ fn transCreateCompoundAssign( |
| 3046 | used: ResultUsed, | 3048 | used: ResultUsed, |
| 3047 | ) TransError!*ast.Node { | 3049 | ) TransError!*ast.Node { |
| 3048 | const is_shift = bin_op == .BitShiftLeft or bin_op == .BitShiftRight; | 3050 | const is_shift = bin_op == .BitShiftLeft or bin_op == .BitShiftRight; |
| | 3051 | const is_div = bin_op == .Div; |
| | 3052 | const is_mod = bin_op == .Mod; |
| 3049 | const lhs = ZigClangCompoundAssignOperator_getLHS(stmt); | 3053 | const lhs = ZigClangCompoundAssignOperator_getLHS(stmt); |
| 3050 | const rhs = ZigClangCompoundAssignOperator_getRHS(stmt); | 3054 | const rhs = ZigClangCompoundAssignOperator_getRHS(stmt); |
| 3051 | const loc = ZigClangCompoundAssignOperator_getBeginLoc(stmt); | 3055 | const loc = ZigClangCompoundAssignOperator_getBeginLoc(stmt); |
| | 3056 | const is_signed = cIsSignedInteger(getExprQualType(rp.c, lhs)); |
| 3052 | if (used == .unused) { | 3057 | if (used == .unused) { |
| 3053 | // common case | 3058 | // common case |
| 3054 | // c: lhs += rhs | 3059 | // c: lhs += rhs |
| 3055 | // zig: lhs += rhs | 3060 | // zig: lhs += rhs |
| | 3061 | |
| | 3062 | if ((is_mod or is_div) and is_signed) { |
| | 3063 | const op_token = try appendToken(rp.c, .Equal, "="); |
| | 3064 | const op_node = try rp.c.a().create(ast.Node.InfixOp); |
| | 3065 | const builtin = if (is_mod) "@rem" else "@divTrunc"; |
| | 3066 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, builtin); |
| | 3067 | const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value); |
| | 3068 | try builtin_node.params.push(lhs_node); |
| | 3069 | _ = try appendToken(rp.c, .Comma, ","); |
| | 3070 | try builtin_node.params.push(try transExpr(rp, scope, rhs, .used, .r_value)); |
| | 3071 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| | 3072 | op_node.* = .{ |
| | 3073 | .op_token = op_token, |
| | 3074 | .lhs = lhs_node, |
| | 3075 | .op = .Assign, |
| | 3076 | .rhs = &builtin_node.base, |
| | 3077 | }; |
| | 3078 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| | 3079 | return &op_node.base; |
| | 3080 | } |
| | 3081 | |
| 3056 | const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value); | 3082 | const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value); |
| 3057 | const eq_token = try appendToken(rp.c, assign_tok_id, assign_bytes); | 3083 | const eq_token = try appendToken(rp.c, assign_tok_id, assign_bytes); |
| 3058 | var rhs_node = if (is_shift) | 3084 | var rhs_node = if (is_shift) |
| ... | @@ -3095,31 +3121,51 @@ fn transCreateCompoundAssign( | ... | @@ -3095,31 +3121,51 @@ fn transCreateCompoundAssign( |
| 3095 | const lhs_node = try transCreateNodeIdentifier(rp.c, ref); | 3121 | const lhs_node = try transCreateNodeIdentifier(rp.c, ref); |
| 3096 | const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node); | 3122 | const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node); |
| 3097 | _ = try appendToken(rp.c, .Semicolon, ";"); | 3123 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 3098 | const bin_token = try appendToken(rp.c, bin_tok_id, bin_bytes); | 3124 | |
| 3099 | var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value); | 3125 | if ((is_mod or is_div) and is_signed) { |
| 3100 | if (is_shift) { | 3126 | const op_token = try appendToken(rp.c, .Equal, "="); |
| 3101 | const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast"); | 3127 | const op_node = try rp.c.a().create(ast.Node.InfixOp); |
| 3102 | const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc); | 3128 | const builtin = if (is_mod) "@rem" else "@divTrunc"; |
| 3103 | try cast_node.params.push(rhs_type); | 3129 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, builtin); |
| | 3130 | try builtin_node.params.push(try transCreateNodePtrDeref(rp.c, lhs_node)); |
| 3104 | _ = try appendToken(rp.c, .Comma, ","); | 3131 | _ = try appendToken(rp.c, .Comma, ","); |
| 3105 | try cast_node.params.push(rhs_node); | 3132 | try builtin_node.params.push(try transExpr(rp, scope, rhs, .used, .r_value)); |
| 3106 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 3133 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 3107 | rhs_node = &cast_node.base; | 3134 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 3108 | } | 3135 | op_node.* = .{ |
| 3109 | const rhs_bin = try transCreateNodeInfixOp(rp, scope, ref_node, bin_op, bin_token, rhs_node, .used, false); | 3136 | .op_token = op_token, |
| | 3137 | .lhs = ref_node, |
| | 3138 | .op = .Assign, |
| | 3139 | .rhs = &builtin_node.base, |
| | 3140 | }; |
| | 3141 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| | 3142 | try block_scope.block_node.statements.push(&op_node.base); |
| | 3143 | } else { |
| | 3144 | const bin_token = try appendToken(rp.c, bin_tok_id, bin_bytes); |
| | 3145 | var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value); |
| 3110 | | 3146 | |
| 3111 | _ = try appendToken(rp.c, .Semicolon, ";"); | 3147 | if (is_shift) { |
| | 3148 | const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast"); |
| | 3149 | const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc); |
| | 3150 | try cast_node.params.push(rhs_type); |
| | 3151 | _ = try appendToken(rp.c, .Comma, ","); |
| | 3152 | try cast_node.params.push(rhs_node); |
| | 3153 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| | 3154 | rhs_node = &cast_node.base; |
| | 3155 | } |
| 3112 | | 3156 | |
| 3113 | const eq_token = try appendToken(rp.c, .Equal, "="); | 3157 | const rhs_bin = try transCreateNodeInfixOp(rp, scope, ref_node, bin_op, bin_token, rhs_node, .used, false); |
| 3114 | const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, eq_token, rhs_bin, .used, false); | 3158 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 3115 | try block_scope.block_node.statements.push(assign); | 3159 | |
| | 3160 | const eq_token = try appendToken(rp.c, .Equal, "="); |
| | 3161 | const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, eq_token, rhs_bin, .used, false); |
| | 3162 | try block_scope.block_node.statements.push(assign); |
| | 3163 | } |
| 3116 | | 3164 | |
| 3117 | const break_node = try transCreateNodeBreak(rp.c, block_scope.label); | 3165 | const break_node = try transCreateNodeBreak(rp.c, block_scope.label); |
| 3118 | break_node.rhs = ref_node; | 3166 | break_node.rhs = ref_node; |
| 3119 | try block_scope.block_node.statements.push(&break_node.base); | 3167 | try block_scope.block_node.statements.push(&break_node.base); |
| 3120 | block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | 3168 | block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); |
| 3121 | // semicolon must immediately follow rbrace because it is the last token in a block | | |
| 3122 | _ = try appendToken(rp.c, .Semicolon, ";"); | | |
| 3123 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); | 3169 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); |
| 3124 | grouped_expr.* = .{ | 3170 | grouped_expr.* = .{ |
| 3125 | .lparen = try appendToken(rp.c, .LParen, "("), | 3171 | .lparen = try appendToken(rp.c, .LParen, "("), |