authorgravatar for ryan.saunderson88@gmail.comRyan Saunderson <ryan.saunderson88@gmail.com> 2017-11-14 07:00:27-06:00
committergravatar for ryan.saunderson88@gmail.comRyan Saunderson <ryan.saunderson88@gmail.com> 2017-11-14 07:00:27-06:00
log371e578151b1bc402d766ace161cfb4e06777db6
tree662f1d4ca878e55df3de297ade566057109093f7
parentb3b4786c245d7e49241ab65a56af0e4ac83d080b
parent5029322aa127cd20a08740a2215fad5863c574fa

Merge remote-tracking branch 'upstream/master' into llvm6


6 files changed, 722 insertions(+), 158 deletions(-)

src/ast_render.cpp+1-1
......@@ -625,7 +625,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
625625 fprintf(ar->f, "@");
626626 }
627627 AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;
628 bool grouped = (fn_ref_node->type != NodeTypeBinOpExpr);
628 bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr);
629629 render_node_extra(ar, fn_ref_node, grouped);
630630 fprintf(ar->f, "(");
631631 for (size_t i = 0; i < node->data.fn_call_expr.params.length; i += 1) {
src/parsec.cpp+331-154
......@@ -350,6 +350,21 @@ static AstNode* trans_c_cast(Context *c, const SourceLocation &source_location,
350350 return trans_create_node_fn_call_1(c, trans_qual_type(c, qt, source_location), expr);
351351}
352352
353static 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
353368static uint32_t qual_type_int_bit_width(Context *c, const QualType &qt, const SourceLocation &source_loc) {
354369 const Type *ty = qt.getTypePtr();
355370 switch (ty->getTypeClass()) {
......@@ -990,6 +1005,21 @@ static AstNode *trans_create_assign(Context *c, bool result_used, AstNode *block
9901005 }
9911006}
9921007
1008static 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
9931023static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *block, BinaryOperator *stmt) {
9941024 switch (stmt->getOpcode()) {
9951025 case BO_PtrMemD:
......@@ -1022,7 +1052,7 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo
10221052 // unsigned/float division uses the operator
10231053 return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeMod, stmt->getRHS());
10241054 } else {
1025 // signed integer division uses @divTrunc
1055 // signed integer division uses @rem
10261056 AstNode *fn_call = trans_create_node_builtin_fn_call_str(c, "rem");
10271057 AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue);
10281058 if (lhs == nullptr) return nullptr;
......@@ -1041,11 +1071,9 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo
10411071 qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeSubWrap : BinOpTypeSub,
10421072 stmt->getRHS());
10431073 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());
10461075 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());
10491077 case BO_LT:
10501078 return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpLessThan, stmt->getRHS());
10511079 case BO_GT:
......@@ -1071,49 +1099,167 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo
10711099 return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBoolOr, stmt->getRHS());
10721100 case BO_Assign:
10731101 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 }
10741114 case BO_MulAssign:
1075 emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_MulAssign");
1076 return nullptr;
10771115 case BO_DivAssign:
1078 emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_DivAssign");
1079 return nullptr;
10801116 case BO_RemAssign:
1081 emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_RemAssign");
1082 return nullptr;
10831117 case BO_AddAssign:
1084 emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_AddAssign");
1085 return nullptr;
10861118 case BO_SubAssign:
1087 emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_SubAssign");
1088 return nullptr;
10891119 case BO_ShlAssign:
1090 emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_ShlAssign");
1091 return nullptr;
10921120 case BO_ShrAssign:
1093 emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_ShrAssign");
1094 return nullptr;
10951121 case BO_AndAssign:
1096 emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_AndAssign");
1097 return nullptr;
10981122 case BO_XorAssign:
1099 emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_XorAssign");
1100 return nullptr;
11011123 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();
11071125 }
11081126
11091127 zig_unreachable();
11101128}
11111129
1130static 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
1200static 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
11121256static AstNode *trans_compound_assign_operator(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt) {
11131257 switch (stmt->getOpcode()) {
11141258 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);
11171263 case BO_DivAssign:
11181264 emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_DivAssign");
11191265 return nullptr;
......@@ -1121,95 +1267,25 @@ static AstNode *trans_compound_assign_operator(Context *c, bool result_used, Ast
11211267 emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_RemAssign");
11221268 return nullptr;
11231269 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);
11261274 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);
11291279 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);
12041283 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);
12071285 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);
12101287 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);
12131289 case BO_PtrMemD:
12141290 case BO_PtrMemI:
12151291 case BO_Assign:
......@@ -1232,7 +1308,7 @@ static AstNode *trans_compound_assign_operator(Context *c, bool result_used, Ast
12321308 case BO_LAnd:
12331309 case BO_LOr:
12341310 case BO_Comma:
1235 zig_panic("compound assign expected to be handled by binary operator");
1311 zig_unreachable();
12361312 }
12371313
12381314 zig_unreachable();
......@@ -1270,6 +1346,8 @@ static AstNode *trans_implicit_cast_expr(Context *c, AstNode *block, ImplicitCas
12701346 node->data.fn_call_expr.params.append(target_node);
12711347 return node;
12721348 }
1349 case CK_NullToPointer:
1350 return trans_create_node(c, NodeTypeNullLiteral);
12731351 case CK_Dependent:
12741352 emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_Dependent");
12751353 return nullptr;
......@@ -1294,9 +1372,6 @@ static AstNode *trans_implicit_cast_expr(Context *c, AstNode *block, ImplicitCas
12941372 case CK_ToUnion:
12951373 emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ToUnion");
12961374 return nullptr;
1297 case CK_NullToPointer:
1298 emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_NullToPointer");
1299 return nullptr;
13001375 case CK_NullToMemberPointer:
13011376 emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_NullToMemberPointer");
13021377 return nullptr;
......@@ -1442,38 +1517,72 @@ static AstNode *trans_decl_ref_expr(Context *c, DeclRefExpr *stmt, TransLRValue
14421517 return trans_create_node_symbol(c, symbol_name);
14431518}
14441519
1520static 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
14451574static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt) {
14461575 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);
14741581 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);
14771586 case UO_PreInc:
14781587 emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PreInc");
14791588 return nullptr;
......@@ -1484,8 +1593,14 @@ static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *bloc
14841593 emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_AddrOf");
14851594 return nullptr;
14861595 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 }
14891604 case UO_Plus:
14901605 emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Plus");
14911606 return nullptr;
......@@ -1828,10 +1943,20 @@ static AstNode *trans_if_statement(Context *c, AstNode *block, IfStmt *stmt) {
18281943
18291944static AstNode *trans_call_expr(Context *c, bool result_used, AstNode *block, CallExpr *stmt) {
18301945 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)
18331949 return nullptr;
18341950
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
18351960 unsigned num_args = stmt->getNumArgs();
18361961 Expr **args = stmt->getArgs();
18371962 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,
18962021 return node;
18972022}
18982023
2024static 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
18992077static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *stmt, TransLRValue lrvalue) {
19002078 Stmt::StmtClass sc = stmt->getStmtClass();
19012079 switch (sc) {
......@@ -1935,6 +2113,8 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s
19352113 return trans_c_style_cast_expr(c, result_used, block, (CStyleCastExpr *)stmt, lrvalue);
19362114 case Stmt::UnaryExprOrTypeTraitExprClass:
19372115 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);
19382118 case Stmt::CaseStmtClass:
19392119 emit_warning(c, stmt->getLocStart(), "TODO handle C CaseStmtClass");
19402120 return nullptr;
......@@ -1980,9 +2160,6 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s
19802160 case Stmt::CoroutineBodyStmtClass:
19812161 emit_warning(c, stmt->getLocStart(), "TODO handle C CoroutineBodyStmtClass");
19822162 return nullptr;
1983 case Stmt::DoStmtClass:
1984 emit_warning(c, stmt->getLocStart(), "TODO handle C DoStmtClass");
1985 return nullptr;
19862163 case Stmt::BinaryConditionalOperatorClass:
19872164 emit_warning(c, stmt->getLocStart(), "TODO handle C BinaryConditionalOperatorClass");
19882165 return nullptr;
std/io_test.zig+6
......@@ -5,8 +5,14 @@ const Rand = std.rand.Rand;
55const assert = std.debug.assert;
66const mem = std.mem;
77const os = std.os;
8const builtin = @import("builtin");
89
910test "write a file, read it, then delete it" {
11 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
12 // TODO get this test passing
13 // https://github.com/zig-lang/zig/issues/537
14 return;
15 }
1016 var data: [1024]u8 = undefined;
1117 var rng = Rand.init(1234);
1218 rng.fillBytes(data[0..]);
std/os/linux.zig+83
......@@ -328,6 +328,45 @@ pub const TIOCGPKT = 0x80045438;
328328pub const TIOCGPTLCK = 0x80045439;
329329pub const TIOCGEXCL = 0x80045440;
330330
331pub const EPOLL_CTL_ADD = 1;
332pub const EPOLL_CTL_DEL = 2;
333pub const EPOLL_CTL_MOD = 3;
334
335pub const EPOLLIN = 0x001;
336pub const EPOLLPRI = 0x002;
337pub const EPOLLOUT = 0x004;
338pub const EPOLLRDNORM = 0x040;
339pub const EPOLLRDBAND = 0x080;
340pub const EPOLLWRNORM = 0x100;
341pub const EPOLLWRBAND = 0x200;
342pub const EPOLLMSG = 0x400;
343pub const EPOLLERR = 0x008;
344pub const EPOLLHUP = 0x010;
345pub const EPOLLRDHUP = 0x2000;
346pub const EPOLLEXCLUSIVE = (u32(1) << 28);
347pub const EPOLLWAKEUP = (u32(1) << 29);
348pub const EPOLLONESHOT = (u32(1) << 30);
349pub const EPOLLET = (u32(1) << 31);
350
351pub const CLOCK_REALTIME = 0;
352pub const CLOCK_MONOTONIC = 1;
353pub const CLOCK_PROCESS_CPUTIME_ID = 2;
354pub const CLOCK_THREAD_CPUTIME_ID = 3;
355pub const CLOCK_MONOTONIC_RAW = 4;
356pub const CLOCK_REALTIME_COARSE = 5;
357pub const CLOCK_MONOTONIC_COARSE = 6;
358pub const CLOCK_BOOTTIME = 7;
359pub const CLOCK_REALTIME_ALARM = 8;
360pub const CLOCK_BOOTTIME_ALARM = 9;
361pub const CLOCK_SGI_CYCLE = 10;
362pub const CLOCK_TAI = 11;
363
364pub const TFD_NONBLOCK = O_NONBLOCK;
365pub const TFD_CLOEXEC = O_CLOEXEC;
366
367pub const TFD_TIMER_ABSTIME = 1;
368pub const TFD_TIMER_CANCEL_ON_SET = (1 << 1);
369
331370fn unsigned(s: i32) -> u32 { @bitCast(u32, s) }
332371fn signed(s: u32) -> i32 { @bitCast(i32, s) }
333372pub fn WEXITSTATUS(s: i32) -> i32 { signed((unsigned(s) & 0xff00) >> 8) }
......@@ -734,3 +773,47 @@ pub const timespec = arch.timespec;
734773pub fn fstat(fd: i32, stat_buf: &Stat) -> usize {
735774 arch.syscall2(arch.SYS_fstat, usize(fd), @ptrToInt(stat_buf))
736775}
776
777pub const epoll_data = u64;
778
779pub const epoll_event = extern struct {
780 events: u32,
781 data: epoll_data
782};
783
784pub fn epoll_create() -> usize {
785 arch.syscall1(arch.SYS_epoll_create, usize(1))
786}
787
788pub fn epoll_ctl(epoll_fd: i32, op: i32, fd: i32, ev: &epoll_event) -> usize {
789 arch.syscall4(arch.SYS_epoll_ctl, usize(epoll_fd), usize(op), usize(fd), @ptrToInt(ev))
790}
791
792pub fn epoll_wait(epoll_fd: i32, events: &epoll_event, maxevents: i32, timeout: i32) -> usize {
793 arch.syscall4(arch.SYS_epoll_wait, usize(epoll_fd), @ptrToInt(events), usize(maxevents), usize(timeout))
794}
795
796pub fn timerfd_create(clockid: i32, flags: u32) -> usize {
797 arch.syscall2(arch.SYS_timerfd_create, usize(clockid), usize(flags))
798}
799
800pub const itimerspec = extern struct {
801 it_interval: timespec,
802 it_value: timespec
803};
804
805pub fn timerfd_gettime(fd: i32, curr_value: &itimerspec) -> usize {
806 arch.syscall2(arch.SYS_timerfd_gettime, usize(fd), @ptrToInt(curr_value))
807}
808
809pub fn timerfd_settime(fd: i32, flags: u32, new_value: &const itimerspec, old_value: ?&itimerspec) -> usize {
810 arch.syscall4(arch.SYS_timerfd_settime, usize(fd), usize(flags), @ptrToInt(new_value), @ptrToInt(old_value))
811}
812
813test "import linux_test" {
814 // TODO lazy analysis should prevent this test from being compiled on windows, but
815 // it is still compiled on windows
816 if (builtin.os == builtin.Os.linux) {
817 _ = @import("linux_test.zig");
818 }
819}
std/os/linux_test.zig created+38
......@@ -0,0 +1,38 @@
1const std = @import("std");
2const linux = std.os.linux;
3const assert = std.debug.assert;
4
5test "timer" {
6 const epoll_fd = linux.epoll_create();
7 var err = linux.getErrno(epoll_fd);
8 assert(err == 0);
9
10 const timer_fd = linux.timerfd_create(linux.CLOCK_MONOTONIC, 0);
11 assert(linux.getErrno(timer_fd) == 0);
12
13 const time_interval = linux.timespec {
14 .tv_sec = 0,
15 .tv_nsec = 2000000
16 };
17
18 const new_time = linux.itimerspec {
19 .it_interval = time_interval,
20 .it_value = time_interval
21 };
22
23 err = linux.timerfd_settime(i32(timer_fd), 0, &new_time, null);
24 assert(err == 0);
25
26 var event = linux.epoll_event {
27 .events = linux.EPOLLIN | linux.EPOLLOUT | linux.EPOLLET,
28 .data = 0
29 };
30
31 err = linux.epoll_ctl(i32(epoll_fd), linux.EPOLL_CTL_ADD, i32(timer_fd), &event);
32 assert(err == 0);
33
34 const events_one: linux.epoll_event = undefined;
35 var events = []linux.epoll_event{events_one} ** 8;
36
37 err = linux.epoll_wait(i32(epoll_fd), &events[0], 8, -1);
38}
test/parsec.zig+263-3
......@@ -203,13 +203,13 @@ pub fn addCases(cases: &tests.ParseCContext) {
203203 \\pub extern var fn_ptr: ?extern fn();
204204 ,
205205 \\pub inline fn foo() {
206 \\ ??fn_ptr()
206 \\ (??fn_ptr)()
207207 \\}
208208 ,
209209 \\pub extern var fn_ptr2: ?extern fn(c_int, f32) -> u8;
210210 ,
211211 \\pub inline fn bar(arg0: c_int, arg1: f32) -> u8 {
212 \\ ??fn_ptr2(arg0, arg1)
212 \\ (??fn_ptr2)(arg0, arg1)
213213 \\}
214214 );
215215
......@@ -596,8 +596,268 @@ pub fn addCases(cases: &tests.ParseCContext) {
596596 \\ return @sizeOf(c_int);
597597 \\}
598598 );
599}
600599
600 cases.addC("null pointer implicit cast",
601 \\int* foo(void) {
602 \\ return 0;
603 \\}
604 ,
605 \\export fn foo() -> ?&c_int {
606 \\ return null;
607 \\}
608 );
609
610 cases.addC("comma operator",
611 \\int foo(void) {
612 \\ return 1, 2;
613 \\}
614 ,
615 \\export fn foo() -> c_int {
616 \\ return {
617 \\ _ = 1;
618 \\ 2
619 \\ };
620 \\}
621 );
622
623 cases.addC("bitshift",
624 \\int foo(void) {
625 \\ return (1 << 2) >> 1;
626 \\}
627 ,
628 \\export fn foo() -> c_int {
629 \\ return (1 << @import("std").math.Log2Int(c_int)(2)) >> @import("std").math.Log2Int(c_int)(1);
630 \\}
631 );
632
633 cases.addC("compound assignment operators",
634 \\void foo(void) {
635 \\ int a = 0;
636 \\ a += (a += 1);
637 \\ a -= (a -= 1);
638 \\ a *= (a *= 1);
639 \\ a &= (a &= 1);
640 \\ a |= (a |= 1);
641 \\ a ^= (a ^= 1);
642 \\ a >>= (a >>= 1);
643 \\ a <<= (a <<= 1);
644 \\}
645 ,
646 \\export fn foo() {
647 \\ var a: c_int = 0;
648 \\ a += {
649 \\ const _ref = &a;
650 \\ (*_ref) = ((*_ref) + 1);
651 \\ *_ref
652 \\ };
653 \\ a -= {
654 \\ const _ref = &a;
655 \\ (*_ref) = ((*_ref) - 1);
656 \\ *_ref
657 \\ };
658 \\ a *= {
659 \\ const _ref = &a;
660 \\ (*_ref) = ((*_ref) * 1);
661 \\ *_ref
662 \\ };
663 \\ a &= {
664 \\ const _ref = &a;
665 \\ (*_ref) = ((*_ref) & 1);
666 \\ *_ref
667 \\ };
668 \\ a |= {
669 \\ const _ref = &a;
670 \\ (*_ref) = ((*_ref) | 1);
671 \\ *_ref
672 \\ };
673 \\ a ^= {
674 \\ const _ref = &a;
675 \\ (*_ref) = ((*_ref) ^ 1);
676 \\ *_ref
677 \\ };
678 \\ a >>= @import("std").math.Log2Int(c_int)({
679 \\ const _ref = &a;
680 \\ (*_ref) = c_int(c_int(*_ref) >> @import("std").math.Log2Int(c_int)(1));
681 \\ *_ref
682 \\ });
683 \\ a <<= @import("std").math.Log2Int(c_int)({
684 \\ const _ref = &a;
685 \\ (*_ref) = c_int(c_int(*_ref) << @import("std").math.Log2Int(c_int)(1));
686 \\ *_ref
687 \\ });
688 \\}
689 );
690
691 cases.addC("compound assignment operators unsigned",
692 \\void foo(void) {
693 \\ unsigned a = 0;
694 \\ a += (a += 1);
695 \\ a -= (a -= 1);
696 \\ a *= (a *= 1);
697 \\ a &= (a &= 1);
698 \\ a |= (a |= 1);
699 \\ a ^= (a ^= 1);
700 \\ a >>= (a >>= 1);
701 \\ a <<= (a <<= 1);
702 \\}
703 ,
704 \\export fn foo() {
705 \\ var a: c_uint = c_uint(0);
706 \\ a +%= {
707 \\ const _ref = &a;
708 \\ (*_ref) = ((*_ref) +% c_uint(1));
709 \\ *_ref
710 \\ };
711 \\ a -%= {
712 \\ const _ref = &a;
713 \\ (*_ref) = ((*_ref) -% c_uint(1));
714 \\ *_ref
715 \\ };
716 \\ a *%= {
717 \\ const _ref = &a;
718 \\ (*_ref) = ((*_ref) *% c_uint(1));
719 \\ *_ref
720 \\ };
721 \\ a &= {
722 \\ const _ref = &a;
723 \\ (*_ref) = ((*_ref) & c_uint(1));
724 \\ *_ref
725 \\ };
726 \\ a |= {
727 \\ const _ref = &a;
728 \\ (*_ref) = ((*_ref) | c_uint(1));
729 \\ *_ref
730 \\ };
731 \\ a ^= {
732 \\ const _ref = &a;
733 \\ (*_ref) = ((*_ref) ^ c_uint(1));
734 \\ *_ref
735 \\ };
736 \\ a >>= @import("std").math.Log2Int(c_uint)({
737 \\ const _ref = &a;
738 \\ (*_ref) = c_uint(c_uint(*_ref) >> @import("std").math.Log2Int(c_uint)(1));
739 \\ *_ref
740 \\ });
741 \\ a <<= @import("std").math.Log2Int(c_uint)({
742 \\ const _ref = &a;
743 \\ (*_ref) = c_uint(c_uint(*_ref) << @import("std").math.Log2Int(c_uint)(1));
744 \\ *_ref
745 \\ });
746 \\}
747 );
748
749 cases.addC("duplicate typedef",
750 \\typedef long foo;
751 \\typedef int bar;
752 \\typedef long foo;
753 \\typedef int baz;
754 ,
755 \\pub const foo = c_long;
756 \\pub const bar = c_int;
757 \\pub const baz = c_int;
758 );
759
760 cases.addC("post increment/decrement",
761 \\void foo(void) {
762 \\ int i = 0;
763 \\ unsigned u = 0;
764 \\ i++;
765 \\ i--;
766 \\ u++;
767 \\ u--;
768 \\ i = i++;
769 \\ i = i--;
770 \\ u = u++;
771 \\ u = u--;
772 \\}
773 ,
774 \\export fn foo() {
775 \\ var i: c_int = 0;
776 \\ var u: c_uint = c_uint(0);
777 \\ i += 1;
778 \\ i -= 1;
779 \\ u +%= 1;
780 \\ u -%= 1;
781 \\ i = {
782 \\ const _ref = &i;
783 \\ const _tmp = *_ref;
784 \\ (*_ref) += 1;
785 \\ _tmp
786 \\ };
787 \\ i = {
788 \\ const _ref = &i;
789 \\ const _tmp = *_ref;
790 \\ (*_ref) -= 1;
791 \\ _tmp
792 \\ };
793 \\ u = {
794 \\ const _ref = &u;
795 \\ const _tmp = *_ref;
796 \\ (*_ref) +%= 1;
797 \\ _tmp
798 \\ };
799 \\ u = {
800 \\ const _ref = &u;
801 \\ const _tmp = *_ref;
802 \\ (*_ref) -%= 1;
803 \\ _tmp
804 \\ };
805 \\}
806 );
807
808 cases.addC("do loop",
809 \\void foo(void) {
810 \\ int a = 2;
811 \\ do {
812 \\ a--;
813 \\ } while (a != 0);
814 \\
815 \\ int b = 2;
816 \\ do
817 \\ b--;
818 \\ while (b != 0);
819 \\}
820 ,
821 \\export fn foo() {
822 \\ var a: c_int = 2;
823 \\ while (true) {
824 \\ a -= 1;
825 \\ if (!(a != 0)) break;
826 \\ };
827 \\ var b: c_int = 2;
828 \\ while (true) {
829 \\ b -= 1;
830 \\ if (!(b != 0)) break;
831 \\ };
832 \\}
833 );
834
835 cases.addC("deref function pointer",
836 \\void foo(void) {}
837 \\void bar(void) {
838 \\ void(*f)(void) = foo;
839 \\ f();
840 \\ (*(f))();
841 \\}
842 ,
843 \\export fn foo() {}
844 \\export fn bar() {
845 \\ var f: ?extern fn() = foo;
846 \\ (??f)();
847 \\ (??f)();
848 \\}
849 );
850
851 cases.addC("normal deref",
852 \\void foo(int *x) {
853 \\ *x = 1;
854 \\}
855 ,
856 \\export fn foo(x: ?&c_int) {
857 \\ (*(??x)) = 1;
858 \\}
859 );
860}
601861
602862
603863