| ... | ... | @@ -350,6 +350,21 @@ static AstNode* trans_c_cast(Context *c, const SourceLocation &source_location, |
| 350 | 350 | return trans_create_node_fn_call_1(c, trans_qual_type(c, qt, source_location), expr); |
| 351 | 351 | } |
| 352 | 352 | |
| 353 | static bool qual_type_is_fn_ptr(Context *c, const QualType &qt) { |
| 354 | const Type *ty = qt.getTypePtr(); |
| 355 | if (ty->getTypeClass() != Type::Pointer) { |
| 356 | return false; |
| 357 | } |
| 358 | const PointerType *pointer_ty = static_cast<const PointerType*>(ty); |
| 359 | QualType child_qt = pointer_ty->getPointeeType(); |
| 360 | const Type *child_ty = child_qt.getTypePtr(); |
| 361 | if (child_ty->getTypeClass() != Type::Paren) { |
| 362 | return false; |
| 363 | } |
| 364 | const ParenType *paren_ty = static_cast<const ParenType *>(child_ty); |
| 365 | return paren_ty->getInnerType().getTypePtr()->getTypeClass() == Type::FunctionProto; |
| 366 | } |
| 367 | |
| 353 | 368 | static uint32_t qual_type_int_bit_width(Context *c, const QualType &qt, const SourceLocation &source_loc) { |
| 354 | 369 | const Type *ty = qt.getTypePtr(); |
| 355 | 370 | switch (ty->getTypeClass()) { |
| ... | ... | @@ -990,6 +1005,21 @@ static AstNode *trans_create_assign(Context *c, bool result_used, AstNode *block |
| 990 | 1005 | } |
| 991 | 1006 | } |
| 992 | 1007 | |
| 1008 | static AstNode *trans_create_shift_op(Context *c, AstNode *block, QualType result_type, Expr *lhs_expr, BinOpType bin_op, Expr *rhs_expr) { |
| 1009 | const SourceLocation &rhs_location = rhs_expr->getLocStart(); |
| 1010 | AstNode *rhs_type = qual_type_to_log2_int_ref(c, result_type, rhs_location); |
| 1011 | // lhs >> u5(rh) |
| 1012 | |
| 1013 | AstNode *lhs = trans_expr(c, true, block, lhs_expr, TransLValue); |
| 1014 | if (lhs == nullptr) return nullptr; |
| 1015 | |
| 1016 | AstNode *rhs = trans_expr(c, true, block, rhs_expr, TransRValue); |
| 1017 | if (rhs == nullptr) return nullptr; |
| 1018 | AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs); |
| 1019 | |
| 1020 | return trans_create_node_bin_op(c, lhs, bin_op, coerced_rhs); |
| 1021 | } |
| 1022 | |
| 993 | 1023 | static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *block, BinaryOperator *stmt) { |
| 994 | 1024 | switch (stmt->getOpcode()) { |
| 995 | 1025 | case BO_PtrMemD: |
| ... | ... | @@ -1022,7 +1052,7 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo |
| 1022 | 1052 | // unsigned/float division uses the operator |
| 1023 | 1053 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeMod, stmt->getRHS()); |
| 1024 | 1054 | } else { |
| 1025 | | // signed integer division uses @divTrunc |
| 1055 | // signed integer division uses @rem |
| 1026 | 1056 | AstNode *fn_call = trans_create_node_builtin_fn_call_str(c, "rem"); |
| 1027 | 1057 | AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue); |
| 1028 | 1058 | if (lhs == nullptr) return nullptr; |
| ... | ... | @@ -1041,11 +1071,9 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo |
| 1041 | 1071 | qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeSubWrap : BinOpTypeSub, |
| 1042 | 1072 | stmt->getRHS()); |
| 1043 | 1073 | case BO_Shl: |
| 1044 | | emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_Shl"); |
| 1045 | | return nullptr; |
| 1074 | return trans_create_shift_op(c, block, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftLeft, stmt->getRHS()); |
| 1046 | 1075 | case BO_Shr: |
| 1047 | | emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_Shr"); |
| 1048 | | return nullptr; |
| 1076 | return trans_create_shift_op(c, block, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftRight, stmt->getRHS()); |
| 1049 | 1077 | case BO_LT: |
| 1050 | 1078 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpLessThan, stmt->getRHS()); |
| 1051 | 1079 | case BO_GT: |
| ... | ... | @@ -1071,49 +1099,167 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo |
| 1071 | 1099 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBoolOr, stmt->getRHS()); |
| 1072 | 1100 | case BO_Assign: |
| 1073 | 1101 | return trans_create_assign(c, result_used, block, stmt->getLHS(), stmt->getRHS()); |
| 1102 | case BO_Comma: |
| 1103 | { |
| 1104 | block = trans_create_node(c, NodeTypeBlock); |
| 1105 | AstNode *lhs = trans_expr(c, false, block, stmt->getLHS(), TransRValue); |
| 1106 | if (lhs == nullptr) return nullptr; |
| 1107 | block->data.block.statements.append(maybe_suppress_result(c, false, lhs)); |
| 1108 | AstNode *rhs = trans_expr(c, result_used, block, stmt->getRHS(), TransRValue); |
| 1109 | if (rhs == nullptr) return nullptr; |
| 1110 | block->data.block.statements.append(maybe_suppress_result(c, result_used, rhs)); |
| 1111 | block->data.block.last_statement_is_result_expression = true; |
| 1112 | return block; |
| 1113 | } |
| 1074 | 1114 | case BO_MulAssign: |
| 1075 | | emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_MulAssign"); |
| 1076 | | return nullptr; |
| 1077 | 1115 | case BO_DivAssign: |
| 1078 | | emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_DivAssign"); |
| 1079 | | return nullptr; |
| 1080 | 1116 | case BO_RemAssign: |
| 1081 | | emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_RemAssign"); |
| 1082 | | return nullptr; |
| 1083 | 1117 | case BO_AddAssign: |
| 1084 | | emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_AddAssign"); |
| 1085 | | return nullptr; |
| 1086 | 1118 | case BO_SubAssign: |
| 1087 | | emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_SubAssign"); |
| 1088 | | return nullptr; |
| 1089 | 1119 | case BO_ShlAssign: |
| 1090 | | emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_ShlAssign"); |
| 1091 | | return nullptr; |
| 1092 | 1120 | case BO_ShrAssign: |
| 1093 | | emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_ShrAssign"); |
| 1094 | | return nullptr; |
| 1095 | 1121 | case BO_AndAssign: |
| 1096 | | emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_AndAssign"); |
| 1097 | | return nullptr; |
| 1098 | 1122 | case BO_XorAssign: |
| 1099 | | emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_XorAssign"); |
| 1100 | | return nullptr; |
| 1101 | 1123 | case BO_OrAssign: |
| 1102 | | emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_OrAssign"); |
| 1103 | | return nullptr; |
| 1104 | | case BO_Comma: |
| 1105 | | emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_Comma"); |
| 1106 | | return nullptr; |
| 1124 | zig_unreachable(); |
| 1107 | 1125 | } |
| 1108 | 1126 | |
| 1109 | 1127 | zig_unreachable(); |
| 1110 | 1128 | } |
| 1111 | 1129 | |
| 1130 | static AstNode *trans_create_compound_assign_shift(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) { |
| 1131 | const SourceLocation &rhs_location = stmt->getRHS()->getLocStart(); |
| 1132 | AstNode *rhs_type = qual_type_to_log2_int_ref(c, stmt->getComputationLHSType(), rhs_location); |
| 1133 | |
| 1134 | bool use_intermediate_casts = stmt->getComputationLHSType().getTypePtr() != stmt->getComputationResultType().getTypePtr(); |
| 1135 | if (!use_intermediate_casts && !result_used) { |
| 1136 | // simple common case, where the C and Zig are identical: |
| 1137 | // lhs >>= rhs |
| 1138 | AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue); |
| 1139 | if (lhs == nullptr) return nullptr; |
| 1140 | |
| 1141 | AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransRValue); |
| 1142 | if (rhs == nullptr) return nullptr; |
| 1143 | AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs); |
| 1144 | |
| 1145 | return trans_create_node_bin_op(c, lhs, assign_op, coerced_rhs); |
| 1146 | } else { |
| 1147 | // need more complexity. worst case, this looks like this: |
| 1148 | // c: lhs >>= rhs |
| 1149 | // zig: { |
| 1150 | // zig: const _ref = &lhs; |
| 1151 | // zig: *_ref = result_type(operation_type(*_ref) >> u5(rhs)); |
| 1152 | // zig: *_ref |
| 1153 | // zig: } |
| 1154 | // where u5 is the appropriate type |
| 1155 | |
| 1156 | AstNode *child_block = trans_create_node(c, NodeTypeBlock); |
| 1157 | |
| 1158 | // const _ref = &lhs; |
| 1159 | AstNode *lhs = trans_expr(c, true, child_block, stmt->getLHS(), TransLValue); |
| 1160 | if (lhs == nullptr) return nullptr; |
| 1161 | AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs); |
| 1162 | // TODO: avoid name collisions with generated variable names |
| 1163 | Buf* tmp_var_name = buf_create_from_str("_ref"); |
| 1164 | AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs); |
| 1165 | child_block->data.block.statements.append(tmp_var_decl); |
| 1166 | |
| 1167 | // *_ref = result_type(operation_type(*_ref) >> u5(rhs)); |
| 1168 | |
| 1169 | AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS(), TransRValue); |
| 1170 | if (rhs == nullptr) return nullptr; |
| 1171 | AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs); |
| 1172 | |
| 1173 | AstNode *assign_statement = trans_create_node_bin_op(c, |
| 1174 | trans_create_node_prefix_op(c, PrefixOpDereference, |
| 1175 | trans_create_node_symbol(c, tmp_var_name)), |
| 1176 | BinOpTypeAssign, |
| 1177 | trans_c_cast(c, rhs_location, |
| 1178 | stmt->getComputationResultType(), |
| 1179 | trans_create_node_bin_op(c, |
| 1180 | trans_c_cast(c, rhs_location, |
| 1181 | stmt->getComputationLHSType(), |
| 1182 | trans_create_node_prefix_op(c, PrefixOpDereference, |
| 1183 | trans_create_node_symbol(c, tmp_var_name))), |
| 1184 | bin_op, |
| 1185 | coerced_rhs))); |
| 1186 | child_block->data.block.statements.append(assign_statement); |
| 1187 | |
| 1188 | if (result_used) { |
| 1189 | // *_ref |
| 1190 | child_block->data.block.statements.append( |
| 1191 | trans_create_node_prefix_op(c, PrefixOpDereference, |
| 1192 | trans_create_node_symbol(c, tmp_var_name))); |
| 1193 | child_block->data.block.last_statement_is_result_expression = true; |
| 1194 | } |
| 1195 | |
| 1196 | return child_block; |
| 1197 | } |
| 1198 | } |
| 1199 | |
| 1200 | static AstNode *trans_create_compound_assign(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) { |
| 1201 | if (!result_used) { |
| 1202 | // simple common case, where the C and Zig are identical: |
| 1203 | // lhs += rhs |
| 1204 | AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue); |
| 1205 | if (lhs == nullptr) return nullptr; |
| 1206 | AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransRValue); |
| 1207 | if (rhs == nullptr) return nullptr; |
| 1208 | return trans_create_node_bin_op(c, lhs, assign_op, rhs); |
| 1209 | } else { |
| 1210 | // need more complexity. worst case, this looks like this: |
| 1211 | // c: lhs += rhs |
| 1212 | // zig: { |
| 1213 | // zig: const _ref = &lhs; |
| 1214 | // zig: *_ref = *_ref + rhs; |
| 1215 | // zig: *_ref |
| 1216 | // zig: } |
| 1217 | |
| 1218 | AstNode *child_block = trans_create_node(c, NodeTypeBlock); |
| 1219 | |
| 1220 | // const _ref = &lhs; |
| 1221 | AstNode *lhs = trans_expr(c, true, child_block, stmt->getLHS(), TransLValue); |
| 1222 | if (lhs == nullptr) return nullptr; |
| 1223 | AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs); |
| 1224 | // TODO: avoid name collisions with generated variable names |
| 1225 | Buf* tmp_var_name = buf_create_from_str("_ref"); |
| 1226 | AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs); |
| 1227 | child_block->data.block.statements.append(tmp_var_decl); |
| 1228 | |
| 1229 | // *_ref = *_ref + rhs; |
| 1230 | |
| 1231 | AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS(), TransRValue); |
| 1232 | if (rhs == nullptr) return nullptr; |
| 1233 | |
| 1234 | AstNode *assign_statement = trans_create_node_bin_op(c, |
| 1235 | trans_create_node_prefix_op(c, PrefixOpDereference, |
| 1236 | trans_create_node_symbol(c, tmp_var_name)), |
| 1237 | BinOpTypeAssign, |
| 1238 | trans_create_node_bin_op(c, |
| 1239 | trans_create_node_prefix_op(c, PrefixOpDereference, |
| 1240 | trans_create_node_symbol(c, tmp_var_name)), |
| 1241 | bin_op, |
| 1242 | rhs)); |
| 1243 | child_block->data.block.statements.append(assign_statement); |
| 1244 | |
| 1245 | // *_ref |
| 1246 | child_block->data.block.statements.append( |
| 1247 | trans_create_node_prefix_op(c, PrefixOpDereference, |
| 1248 | trans_create_node_symbol(c, tmp_var_name))); |
| 1249 | child_block->data.block.last_statement_is_result_expression = true; |
| 1250 | |
| 1251 | return child_block; |
| 1252 | } |
| 1253 | } |
| 1254 | |
| 1255 | |
| 1112 | 1256 | static AstNode *trans_compound_assign_operator(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt) { |
| 1113 | 1257 | switch (stmt->getOpcode()) { |
| 1114 | 1258 | case BO_MulAssign: |
| 1115 | | emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_MulAssign"); |
| 1116 | | return nullptr; |
| 1259 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) |
| 1260 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignTimesWrap, BinOpTypeMultWrap); |
| 1261 | else |
| 1262 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignTimes, BinOpTypeMult); |
| 1117 | 1263 | case BO_DivAssign: |
| 1118 | 1264 | emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_DivAssign"); |
| 1119 | 1265 | return nullptr; |
| ... | ... | @@ -1121,95 +1267,25 @@ static AstNode *trans_compound_assign_operator(Context *c, bool result_used, Ast |
| 1121 | 1267 | emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_RemAssign"); |
| 1122 | 1268 | return nullptr; |
| 1123 | 1269 | case BO_AddAssign: |
| 1124 | | emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_AddAssign"); |
| 1125 | | return nullptr; |
| 1270 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) |
| 1271 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignPlusWrap, BinOpTypeAddWrap); |
| 1272 | else |
| 1273 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignPlus, BinOpTypeAdd); |
| 1126 | 1274 | case BO_SubAssign: |
| 1127 | | emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_SubAssign"); |
| 1128 | | return nullptr; |
| 1275 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) |
| 1276 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignMinusWrap, BinOpTypeSubWrap); |
| 1277 | else |
| 1278 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignMinus, BinOpTypeSub); |
| 1129 | 1279 | case BO_ShlAssign: |
| 1130 | | emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_ShlAssign"); |
| 1131 | | return nullptr; |
| 1132 | | case BO_ShrAssign: { |
| 1133 | | BinOpType bin_op = BinOpTypeBitShiftRight; |
| 1134 | | |
| 1135 | | const SourceLocation &rhs_location = stmt->getRHS()->getLocStart(); |
| 1136 | | AstNode *rhs_type = qual_type_to_log2_int_ref(c, stmt->getComputationLHSType(), rhs_location); |
| 1137 | | |
| 1138 | | bool use_intermediate_casts = stmt->getComputationLHSType().getTypePtr() != stmt->getComputationResultType().getTypePtr(); |
| 1139 | | if (!use_intermediate_casts && !result_used) { |
| 1140 | | // simple common case, where the C and Zig are identical: |
| 1141 | | // lhs >>= rh* s |
| 1142 | | AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue); |
| 1143 | | if (lhs == nullptr) return nullptr; |
| 1144 | | |
| 1145 | | AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransRValue); |
| 1146 | | if (rhs == nullptr) return nullptr; |
| 1147 | | AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs); |
| 1148 | | |
| 1149 | | return trans_create_node_bin_op(c, lhs, BinOpTypeAssignBitShiftRight, coerced_rhs); |
| 1150 | | } else { |
| 1151 | | // need more complexity. worst case, this looks like this: |
| 1152 | | // c: lhs >>= rhs |
| 1153 | | // zig: { |
| 1154 | | // zig: const _ref = &lhs; |
| 1155 | | // zig: *_ref = result_type(operation_type(*_ref) >> u5(rhs)); |
| 1156 | | // zig: *_ref |
| 1157 | | // zig: } |
| 1158 | | // where u5 is the appropriate type |
| 1159 | | |
| 1160 | | // TODO: avoid mess when we don't need the assignment value for chained assignments or anything. |
| 1161 | | AstNode *child_block = trans_create_node(c, NodeTypeBlock); |
| 1162 | | |
| 1163 | | // const _ref = &lhs; |
| 1164 | | AstNode *lhs = trans_expr(c, true, child_block, stmt->getLHS(), TransLValue); |
| 1165 | | if (lhs == nullptr) return nullptr; |
| 1166 | | AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs); |
| 1167 | | // TODO: avoid name collisions with generated variable names |
| 1168 | | Buf* tmp_var_name = buf_create_from_str("_ref"); |
| 1169 | | AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs); |
| 1170 | | child_block->data.block.statements.append(tmp_var_decl); |
| 1171 | | |
| 1172 | | // *_ref = result_type(operation_type(*_ref) >> u5(rhs)); |
| 1173 | | |
| 1174 | | AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS(), TransRValue); |
| 1175 | | if (rhs == nullptr) return nullptr; |
| 1176 | | AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs); |
| 1177 | | |
| 1178 | | AstNode *assign_statement = trans_create_node_bin_op(c, |
| 1179 | | trans_create_node_prefix_op(c, PrefixOpDereference, |
| 1180 | | trans_create_node_symbol(c, tmp_var_name)), |
| 1181 | | BinOpTypeAssign, |
| 1182 | | trans_c_cast(c, rhs_location, |
| 1183 | | stmt->getComputationResultType(), |
| 1184 | | trans_create_node_bin_op(c, |
| 1185 | | trans_c_cast(c, rhs_location, |
| 1186 | | stmt->getComputationLHSType(), |
| 1187 | | trans_create_node_prefix_op(c, PrefixOpDereference, |
| 1188 | | trans_create_node_symbol(c, tmp_var_name))), |
| 1189 | | bin_op, |
| 1190 | | coerced_rhs))); |
| 1191 | | child_block->data.block.statements.append(assign_statement); |
| 1192 | | |
| 1193 | | if (result_used) { |
| 1194 | | // *_ref |
| 1195 | | child_block->data.block.statements.append( |
| 1196 | | trans_create_node_prefix_op(c, PrefixOpDereference, |
| 1197 | | trans_create_node_symbol(c, tmp_var_name))); |
| 1198 | | child_block->data.block.last_statement_is_result_expression = true; |
| 1199 | | } |
| 1200 | | |
| 1201 | | return child_block; |
| 1202 | | } |
| 1203 | | } |
| 1280 | return trans_create_compound_assign_shift(c, result_used, block, stmt, BinOpTypeAssignBitShiftLeft, BinOpTypeBitShiftLeft); |
| 1281 | case BO_ShrAssign: |
| 1282 | return trans_create_compound_assign_shift(c, result_used, block, stmt, BinOpTypeAssignBitShiftRight, BinOpTypeBitShiftRight); |
| 1204 | 1283 | case BO_AndAssign: |
| 1205 | | emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_AndAssign"); |
| 1206 | | return nullptr; |
| 1284 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignBitAnd, BinOpTypeBinAnd); |
| 1207 | 1285 | case BO_XorAssign: |
| 1208 | | emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_XorAssign"); |
| 1209 | | return nullptr; |
| 1286 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignBitXor, BinOpTypeBinXor); |
| 1210 | 1287 | case BO_OrAssign: |
| 1211 | | emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_OrAssign"); |
| 1212 | | return nullptr; |
| 1288 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignBitOr, BinOpTypeBinOr); |
| 1213 | 1289 | case BO_PtrMemD: |
| 1214 | 1290 | case BO_PtrMemI: |
| 1215 | 1291 | case BO_Assign: |
| ... | ... | @@ -1232,7 +1308,7 @@ static AstNode *trans_compound_assign_operator(Context *c, bool result_used, Ast |
| 1232 | 1308 | case BO_LAnd: |
| 1233 | 1309 | case BO_LOr: |
| 1234 | 1310 | case BO_Comma: |
| 1235 | | zig_panic("compound assign expected to be handled by binary operator"); |
| 1311 | zig_unreachable(); |
| 1236 | 1312 | } |
| 1237 | 1313 | |
| 1238 | 1314 | zig_unreachable(); |
| ... | ... | @@ -1270,6 +1346,8 @@ static AstNode *trans_implicit_cast_expr(Context *c, AstNode *block, ImplicitCas |
| 1270 | 1346 | node->data.fn_call_expr.params.append(target_node); |
| 1271 | 1347 | return node; |
| 1272 | 1348 | } |
| 1349 | case CK_NullToPointer: |
| 1350 | return trans_create_node(c, NodeTypeNullLiteral); |
| 1273 | 1351 | case CK_Dependent: |
| 1274 | 1352 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_Dependent"); |
| 1275 | 1353 | return nullptr; |
| ... | ... | @@ -1294,9 +1372,6 @@ static AstNode *trans_implicit_cast_expr(Context *c, AstNode *block, ImplicitCas |
| 1294 | 1372 | case CK_ToUnion: |
| 1295 | 1373 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ToUnion"); |
| 1296 | 1374 | return nullptr; |
| 1297 | | case CK_NullToPointer: |
| 1298 | | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_NullToPointer"); |
| 1299 | | return nullptr; |
| 1300 | 1375 | case CK_NullToMemberPointer: |
| 1301 | 1376 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_NullToMemberPointer"); |
| 1302 | 1377 | return nullptr; |
| ... | ... | @@ -1442,38 +1517,72 @@ static AstNode *trans_decl_ref_expr(Context *c, DeclRefExpr *stmt, TransLRValue |
| 1442 | 1517 | return trans_create_node_symbol(c, symbol_name); |
| 1443 | 1518 | } |
| 1444 | 1519 | |
| 1520 | static AstNode *trans_create_post_crement(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt, BinOpType assign_op) { |
| 1521 | Expr *op_expr = stmt->getSubExpr(); |
| 1522 | |
| 1523 | if (!result_used) { |
| 1524 | // common case |
| 1525 | // c: expr++ |
| 1526 | // zig: expr += 1 |
| 1527 | return trans_create_node_bin_op(c, |
| 1528 | trans_expr(c, true, block, op_expr, TransLValue), |
| 1529 | assign_op, |
| 1530 | trans_create_node_unsigned(c, 1)); |
| 1531 | } else { |
| 1532 | // worst case |
| 1533 | // c: expr++ |
| 1534 | // zig: { |
| 1535 | // zig: const _ref = &expr; |
| 1536 | // zig: const _tmp = *_ref; |
| 1537 | // zig: *_ref += 1; |
| 1538 | // zig: _tmp |
| 1539 | // zig: } |
| 1540 | AstNode *child_block = trans_create_node(c, NodeTypeBlock); |
| 1541 | |
| 1542 | // const _ref = &expr; |
| 1543 | AstNode *expr = trans_expr(c, true, child_block, op_expr, TransLValue); |
| 1544 | if (expr == nullptr) return nullptr; |
| 1545 | AstNode *addr_of_expr = trans_create_node_addr_of(c, false, false, expr); |
| 1546 | // TODO: avoid name collisions with generated variable names |
| 1547 | Buf* ref_var_name = buf_create_from_str("_ref"); |
| 1548 | AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr); |
| 1549 | child_block->data.block.statements.append(ref_var_decl); |
| 1550 | |
| 1551 | // const _tmp = *_ref; |
| 1552 | Buf* tmp_var_name = buf_create_from_str("_tmp"); |
| 1553 | AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, |
| 1554 | trans_create_node_prefix_op(c, PrefixOpDereference, |
| 1555 | trans_create_node_symbol(c, ref_var_name))); |
| 1556 | child_block->data.block.statements.append(tmp_var_decl); |
| 1557 | |
| 1558 | // *_ref += 1; |
| 1559 | AstNode *assign_statement = trans_create_node_bin_op(c, |
| 1560 | trans_create_node_prefix_op(c, PrefixOpDereference, |
| 1561 | trans_create_node_symbol(c, ref_var_name)), |
| 1562 | assign_op, |
| 1563 | trans_create_node_unsigned(c, 1)); |
| 1564 | child_block->data.block.statements.append(assign_statement); |
| 1565 | |
| 1566 | // _tmp |
| 1567 | child_block->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name)); |
| 1568 | child_block->data.block.last_statement_is_result_expression = true; |
| 1569 | |
| 1570 | return child_block; |
| 1571 | } |
| 1572 | } |
| 1573 | |
| 1445 | 1574 | static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt) { |
| 1446 | 1575 | switch (stmt->getOpcode()) { |
| 1447 | | case UO_PostInc: { |
| 1448 | | Expr *op_expr = stmt->getSubExpr(); |
| 1449 | | BinOpType bin_op = qual_type_has_wrapping_overflow(c, op_expr->getType()) |
| 1450 | | ? BinOpTypeAssignPlusWrap |
| 1451 | | : BinOpTypeAssignPlus; |
| 1452 | | |
| 1453 | | if (!result_used) { |
| 1454 | | // common case |
| 1455 | | // c: expr++ |
| 1456 | | // zig: expr += 1 |
| 1457 | | return trans_create_node_bin_op(c, |
| 1458 | | trans_expr(c, true, block, op_expr, TransLValue), |
| 1459 | | bin_op, |
| 1460 | | trans_create_node_unsigned(c, 1)); |
| 1461 | | } else { |
| 1462 | | // worst case |
| 1463 | | // c: expr++ |
| 1464 | | // zig: { |
| 1465 | | // zig: const _ref = &expr; |
| 1466 | | // zig: const _tmp = *_ref; |
| 1467 | | // zig: *_ref += 1; |
| 1468 | | // zig: _tmp |
| 1469 | | // zig: } |
| 1470 | | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PostInc with result_used"); |
| 1471 | | return nullptr; |
| 1472 | | } |
| 1473 | | } |
| 1576 | case UO_PostInc: |
| 1577 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) |
| 1578 | return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignPlusWrap); |
| 1579 | else |
| 1580 | return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignPlus); |
| 1474 | 1581 | case UO_PostDec: |
| 1475 | | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PostDec"); |
| 1476 | | return nullptr; |
| 1582 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) |
| 1583 | return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignMinusWrap); |
| 1584 | else |
| 1585 | return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignMinus); |
| 1477 | 1586 | case UO_PreInc: |
| 1478 | 1587 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PreInc"); |
| 1479 | 1588 | return nullptr; |
| ... | ... | @@ -1484,8 +1593,14 @@ static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *bloc |
| 1484 | 1593 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_AddrOf"); |
| 1485 | 1594 | return nullptr; |
| 1486 | 1595 | case UO_Deref: |
| 1487 | | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Deref"); |
| 1488 | | return nullptr; |
| 1596 | { |
| 1597 | bool is_fn_ptr = qual_type_is_fn_ptr(c, stmt->getSubExpr()->getType()); |
| 1598 | AstNode *value_node = trans_expr(c, result_used, block, stmt->getSubExpr(), TransRValue); |
| 1599 | if (is_fn_ptr) |
| 1600 | return value_node; |
| 1601 | AstNode *unwrapped = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, value_node); |
| 1602 | return trans_create_node_prefix_op(c, PrefixOpDereference, unwrapped); |
| 1603 | } |
| 1489 | 1604 | case UO_Plus: |
| 1490 | 1605 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Plus"); |
| 1491 | 1606 | return nullptr; |
| ... | ... | @@ -1828,10 +1943,20 @@ static AstNode *trans_if_statement(Context *c, AstNode *block, IfStmt *stmt) { |
| 1828 | 1943 | |
| 1829 | 1944 | static AstNode *trans_call_expr(Context *c, bool result_used, AstNode *block, CallExpr *stmt) { |
| 1830 | 1945 | AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); |
| 1831 | | node->data.fn_call_expr.fn_ref_expr = trans_expr(c, true, block, stmt->getCallee(), TransRValue); |
| 1832 | | if (node->data.fn_call_expr.fn_ref_expr == nullptr) |
| 1946 | |
| 1947 | AstNode *callee_raw_node = trans_expr(c, true, block, stmt->getCallee(), TransRValue); |
| 1948 | if (callee_raw_node == nullptr) |
| 1833 | 1949 | return nullptr; |
| 1834 | 1950 | |
| 1951 | AstNode *callee_node; |
| 1952 | if (qual_type_is_fn_ptr(c, stmt->getCallee()->getType())) { |
| 1953 | callee_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, callee_raw_node); |
| 1954 | } else { |
| 1955 | callee_node = callee_raw_node; |
| 1956 | } |
| 1957 | |
| 1958 | node->data.fn_call_expr.fn_ref_expr = callee_node; |
| 1959 | |
| 1835 | 1960 | unsigned num_args = stmt->getNumArgs(); |
| 1836 | 1961 | Expr **args = stmt->getArgs(); |
| 1837 | 1962 | for (unsigned i = 0; i < num_args; i += 1) { |
| ... | ... | @@ -1896,6 +2021,59 @@ static AstNode *trans_unary_expr_or_type_trait_expr(Context *c, AstNode *block, |
| 1896 | 2021 | return node; |
| 1897 | 2022 | } |
| 1898 | 2023 | |
| 2024 | static AstNode *trans_do_loop(Context *c, AstNode *block, DoStmt *stmt) { |
| 2025 | stmt->getBody(); |
| 2026 | stmt->getCond(); |
| 2027 | |
| 2028 | AstNode *while_node = trans_create_node(c, NodeTypeWhileExpr); |
| 2029 | |
| 2030 | AstNode *true_node = trans_create_node(c, NodeTypeBoolLiteral); |
| 2031 | true_node->data.bool_literal.value = true; |
| 2032 | while_node->data.while_expr.condition = true_node; |
| 2033 | |
| 2034 | AstNode *body_node; |
| 2035 | if (stmt->getBody()->getStmtClass() == Stmt::CompoundStmtClass) { |
| 2036 | // there's already a block in C, so we'll append our condition to it. |
| 2037 | // c: do { |
| 2038 | // c: a; |
| 2039 | // c: b; |
| 2040 | // c: } while(c); |
| 2041 | // zig: while (true) { |
| 2042 | // zig: a; |
| 2043 | // zig: b; |
| 2044 | // zig: if (!cond) break; |
| 2045 | // zig: } |
| 2046 | body_node = trans_stmt(c, false, block, stmt->getBody(), TransRValue); |
| 2047 | if (body_node == nullptr) return nullptr; |
| 2048 | assert(body_node->type == NodeTypeBlock); |
| 2049 | } else { |
| 2050 | // the C statement is without a block, so we need to create a block to contain it. |
| 2051 | // c: do |
| 2052 | // c: a; |
| 2053 | // c: while(c); |
| 2054 | // zig: while (true) { |
| 2055 | // zig: a; |
| 2056 | // zig: if (!cond) break; |
| 2057 | // zig: } |
| 2058 | body_node = trans_create_node(c, NodeTypeBlock); |
| 2059 | AstNode *child_statement = trans_stmt(c, false, body_node, stmt->getBody(), TransRValue); |
| 2060 | if (child_statement == nullptr) return nullptr; |
| 2061 | body_node->data.block.statements.append(child_statement); |
| 2062 | } |
| 2063 | |
| 2064 | // if (!cond) break; |
| 2065 | AstNode *condition_node = trans_expr(c, true, body_node, stmt->getCond(), TransRValue); |
| 2066 | if (condition_node == nullptr) return nullptr; |
| 2067 | AstNode *terminator_node = trans_create_node(c, NodeTypeIfBoolExpr); |
| 2068 | terminator_node->data.if_bool_expr.condition = trans_create_node_prefix_op(c, PrefixOpBoolNot, condition_node); |
| 2069 | terminator_node->data.if_bool_expr.then_block = trans_create_node(c, NodeTypeBreak); |
| 2070 | body_node->data.block.statements.append(terminator_node); |
| 2071 | |
| 2072 | while_node->data.while_expr.body = body_node; |
| 2073 | |
| 2074 | return while_node; |
| 2075 | } |
| 2076 | |
| 1899 | 2077 | static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *stmt, TransLRValue lrvalue) { |
| 1900 | 2078 | Stmt::StmtClass sc = stmt->getStmtClass(); |
| 1901 | 2079 | switch (sc) { |
| ... | ... | @@ -1935,6 +2113,8 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s |
| 1935 | 2113 | return trans_c_style_cast_expr(c, result_used, block, (CStyleCastExpr *)stmt, lrvalue); |
| 1936 | 2114 | case Stmt::UnaryExprOrTypeTraitExprClass: |
| 1937 | 2115 | return trans_unary_expr_or_type_trait_expr(c, block, (UnaryExprOrTypeTraitExpr *)stmt); |
| 2116 | case Stmt::DoStmtClass: |
| 2117 | return trans_do_loop(c, block, (DoStmt *)stmt); |
| 1938 | 2118 | case Stmt::CaseStmtClass: |
| 1939 | 2119 | emit_warning(c, stmt->getLocStart(), "TODO handle C CaseStmtClass"); |
| 1940 | 2120 | return nullptr; |
| ... | ... | @@ -1980,9 +2160,6 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s |
| 1980 | 2160 | case Stmt::CoroutineBodyStmtClass: |
| 1981 | 2161 | emit_warning(c, stmt->getLocStart(), "TODO handle C CoroutineBodyStmtClass"); |
| 1982 | 2162 | return nullptr; |
| 1983 | | case Stmt::DoStmtClass: |
| 1984 | | emit_warning(c, stmt->getLocStart(), "TODO handle C DoStmtClass"); |
| 1985 | | return nullptr; |
| 1986 | 2163 | case Stmt::BinaryConditionalOperatorClass: |
| 1987 | 2164 | emit_warning(c, stmt->getLocStart(), "TODO handle C BinaryConditionalOperatorClass"); |
| 1988 | 2165 | return nullptr; |