| ... | @@ -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)); |
| ... | @@ -3048,13 +3048,37 @@ fn transCreateCompoundAssign( | ... | @@ -3048,13 +3048,37 @@ fn transCreateCompoundAssign( |
| 3048 | used: ResultUsed, | 3048 | used: ResultUsed, |
| 3049 | ) TransError!*ast.Node { | 3049 | ) TransError!*ast.Node { |
| 3050 | 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; |
| 3051 | const lhs = ZigClangCompoundAssignOperator_getLHS(stmt); | 3053 | const lhs = ZigClangCompoundAssignOperator_getLHS(stmt); |
| 3052 | const rhs = ZigClangCompoundAssignOperator_getRHS(stmt); | 3054 | const rhs = ZigClangCompoundAssignOperator_getRHS(stmt); |
| 3053 | const loc = ZigClangCompoundAssignOperator_getBeginLoc(stmt); | 3055 | const loc = ZigClangCompoundAssignOperator_getBeginLoc(stmt); |
| | 3056 | const is_signed = cIsSignedInteger(getExprQualType(rp.c, lhs)); |
| 3054 | if (used == .unused) { | 3057 | if (used == .unused) { |
| 3055 | // common case | 3058 | // common case |
| 3056 | // c: lhs += rhs | 3059 | // c: lhs += rhs |
| 3057 | // 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 | |
| 3058 | const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value); | 3082 | const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value); |
| 3059 | 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); |
| 3060 | var rhs_node = if (is_shift) | 3084 | var rhs_node = if (is_shift) |
| ... | @@ -3097,31 +3121,53 @@ fn transCreateCompoundAssign( | ... | @@ -3097,31 +3121,53 @@ fn transCreateCompoundAssign( |
| 3097 | const lhs_node = try transCreateNodeIdentifier(rp.c, ref); | 3121 | const lhs_node = try transCreateNodeIdentifier(rp.c, ref); |
| 3098 | const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node); | 3122 | const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node); |
| 3099 | _ = try appendToken(rp.c, .Semicolon, ";"); | 3123 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 3100 | const bin_token = try appendToken(rp.c, bin_tok_id, bin_bytes); | 3124 | |
| 3101 | var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value); | 3125 | if ((is_mod or is_div) and is_signed) { |
| 3102 | if (is_shift) { | 3126 | const op_token = try appendToken(rp.c, .Equal, "="); |
| 3103 | const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast"); | 3127 | const op_node = try rp.c.a().create(ast.Node.InfixOp); |
| 3104 | const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc); | 3128 | const builtin = if (is_mod) "@rem" else "@divTrunc"; |
| 3105 | 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)); |
| 3106 | _ = try appendToken(rp.c, .Comma, ","); | 3131 | _ = try appendToken(rp.c, .Comma, ","); |
| 3107 | try cast_node.params.push(rhs_node); | 3132 | try builtin_node.params.push(try transExpr(rp, scope, rhs, .used, .r_value)); |
| 3108 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 3133 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 3109 | rhs_node = &cast_node.base; | 3134 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 3110 | } | 3135 | op_node.* = .{ |
| 3111 | 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); |
| 3112 | | 3146 | |
| 3113 | _ = 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 | } |
| 3114 | | 3156 | |
| 3115 | 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); |
| 3116 | const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, eq_token, rhs_bin, .used, false); | 3158 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 3117 | 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 | } |
| 3118 | | 3164 | |
| 3119 | const break_node = try transCreateNodeBreak(rp.c, block_scope.label); | 3165 | const break_node = try transCreateNodeBreak(rp.c, block_scope.label); |
| 3120 | break_node.rhs = ref_node; | 3166 | break_node.rhs = ref_node; |
| 3121 | try block_scope.block_node.statements.push(&break_node.base); | 3167 | try block_scope.block_node.statements.push(&break_node.base); |
| 3122 | block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | 3168 | block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); |
| 3123 | // semicolon must immediately follow rbrace because it is the last token in a block | 3169 | // semicolon must immediately follow rbrace because it is the last token in a block |
| 3124 | _ = try appendToken(rp.c, .Semicolon, ";"); | 3170 | _ = try appendToken(rp.c, .Semicolon, ";4"); |
| 3125 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); | 3171 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); |
| 3126 | grouped_expr.* = .{ | 3172 | grouped_expr.* = .{ |
| 3127 | .lparen = try appendToken(rp.c, .LParen, "("), | 3173 | .lparen = try appendToken(rp.c, .LParen, "("), |