| ... | ... | @@ -386,8 +386,17 @@ static bool qual_type_child_is_fn_proto(const QualType &qt) { |
| 386 | 386 | return false; |
| 387 | 387 | } |
| 388 | 388 | |
| 389 | static QualType resolve_any_typedef(Context *c, QualType qt) { |
| 390 | const Type * ty = qt.getTypePtr(); |
| 391 | if (ty->getTypeClass() != Type::Typedef) |
| 392 | return qt; |
| 393 | const TypedefType *typedef_ty = static_cast<const TypedefType*>(ty); |
| 394 | const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); |
| 395 | return typedef_decl->getUnderlyingType(); |
| 396 | } |
| 397 | |
| 389 | 398 | static bool c_is_signed_integer(Context *c, QualType qt) { |
| 390 | | const Type *c_type = qt.getTypePtr(); |
| 399 | const Type *c_type = resolve_any_typedef(c, qt).getTypePtr(); |
| 391 | 400 | if (c_type->getTypeClass() != Type::Builtin) |
| 392 | 401 | return false; |
| 393 | 402 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type); |
| ... | ... | @@ -406,7 +415,7 @@ static bool c_is_signed_integer(Context *c, QualType qt) { |
| 406 | 415 | } |
| 407 | 416 | |
| 408 | 417 | static bool c_is_unsigned_integer(Context *c, QualType qt) { |
| 409 | | const Type *c_type = qt.getTypePtr(); |
| 418 | const Type *c_type = resolve_any_typedef(c, qt).getTypePtr(); |
| 410 | 419 | if (c_type->getTypeClass() != Type::Builtin) |
| 411 | 420 | return false; |
| 412 | 421 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type); |
| ... | ... | @@ -443,6 +452,16 @@ static bool c_is_float(Context *c, QualType qt) { |
| 443 | 452 | } |
| 444 | 453 | } |
| 445 | 454 | |
| 455 | static bool qual_type_has_wrapping_overflow(Context *c, QualType qt) { |
| 456 | if (c_is_signed_integer(c, qt) || c_is_float(c, qt)) { |
| 457 | // float and signed integer overflow is undefined behavior. |
| 458 | return false; |
| 459 | } else { |
| 460 | // unsigned integer overflow wraps around. |
| 461 | return true; |
| 462 | } |
| 463 | } |
| 464 | |
| 446 | 465 | enum TransLRValue { |
| 447 | 466 | TransLValue, |
| 448 | 467 | TransRValue, |
| ... | ... | @@ -1286,11 +1305,35 @@ static AstNode *trans_decl_ref_expr(Context *c, DeclRefExpr *stmt, TransLRValue |
| 1286 | 1305 | return trans_create_node_symbol(c, symbol_name); |
| 1287 | 1306 | } |
| 1288 | 1307 | |
| 1289 | | static AstNode *trans_unary_operator(Context *c, AstNode *block, UnaryOperator *stmt) { |
| 1308 | static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt) { |
| 1290 | 1309 | switch (stmt->getOpcode()) { |
| 1291 | | case UO_PostInc: |
| 1292 | | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PostInc"); |
| 1293 | | return nullptr; |
| 1310 | case UO_PostInc: { |
| 1311 | Expr *op_expr = stmt->getSubExpr(); |
| 1312 | BinOpType bin_op = qual_type_has_wrapping_overflow(c, op_expr->getType()) |
| 1313 | ? BinOpTypeAssignPlusWrap |
| 1314 | : BinOpTypeAssignPlus; |
| 1315 | |
| 1316 | if (!result_used) { |
| 1317 | // common case |
| 1318 | // c: expr++ |
| 1319 | // zig: expr += 1 |
| 1320 | return trans_create_node_bin_op(c, |
| 1321 | trans_expr(c, true, block, op_expr, TransLValue), |
| 1322 | bin_op, |
| 1323 | trans_create_node_unsigned(c, 1)); |
| 1324 | } else { |
| 1325 | // worst case |
| 1326 | // c: expr++ |
| 1327 | // zig: { |
| 1328 | // zig: const _ref = &expr; |
| 1329 | // zig: const _tmp = *_ref; |
| 1330 | // zig: *_ref += 1; |
| 1331 | // zig: _tmp |
| 1332 | // zig: } |
| 1333 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PostInc with result_used"); |
| 1334 | return nullptr; |
| 1335 | } |
| 1336 | } |
| 1294 | 1337 | case UO_PostDec: |
| 1295 | 1338 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PostDec"); |
| 1296 | 1339 | return nullptr; |
| ... | ... | @@ -1312,7 +1355,7 @@ static AstNode *trans_unary_operator(Context *c, AstNode *block, UnaryOperator * |
| 1312 | 1355 | case UO_Minus: |
| 1313 | 1356 | { |
| 1314 | 1357 | Expr *op_expr = stmt->getSubExpr(); |
| 1315 | | if (c_is_signed_integer(c, op_expr->getType()) || c_is_float(c, op_expr->getType())) { |
| 1358 | if (!qual_type_has_wrapping_overflow(c, op_expr->getType())) { |
| 1316 | 1359 | AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr); |
| 1317 | 1360 | node->data.prefix_op_expr.prefix_op = PrefixOpNegation; |
| 1318 | 1361 | |
| ... | ... | @@ -1642,7 +1685,7 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s |
| 1642 | 1685 | case Stmt::DeclRefExprClass: |
| 1643 | 1686 | return trans_decl_ref_expr(c, (DeclRefExpr *)stmt, lrvalue); |
| 1644 | 1687 | case Stmt::UnaryOperatorClass: |
| 1645 | | return trans_unary_operator(c, block, (UnaryOperator *)stmt); |
| 1688 | return trans_unary_operator(c, result_used, block, (UnaryOperator *)stmt); |
| 1646 | 1689 | case Stmt::DeclStmtClass: |
| 1647 | 1690 | return trans_local_declaration(c, block, (DeclStmt *)stmt); |
| 1648 | 1691 | case Stmt::WhileStmtClass: |