| ... | @@ -386,8 +386,17 @@ static bool qual_type_child_is_fn_proto(const QualType &qt) { | ... | @@ -386,8 +386,17 @@ static bool qual_type_child_is_fn_proto(const QualType &qt) { |
| 386 | return false; | 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 | static bool c_is_signed_integer(Context *c, QualType qt) { | 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 | if (c_type->getTypeClass() != Type::Builtin) | 400 | if (c_type->getTypeClass() != Type::Builtin) |
| 392 | return false; | 401 | return false; |
| 393 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type); | 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,7 +415,7 @@ static bool c_is_signed_integer(Context *c, QualType qt) { |
| 406 | } | 415 | } |
| 407 | | 416 | |
| 408 | static bool c_is_unsigned_integer(Context *c, QualType qt) { | 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 | if (c_type->getTypeClass() != Type::Builtin) | 419 | if (c_type->getTypeClass() != Type::Builtin) |
| 411 | return false; | 420 | return false; |
| 412 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type); | 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,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 | enum TransLRValue { | 465 | enum TransLRValue { |
| 447 | TransLValue, | 466 | TransLValue, |
| 448 | TransRValue, | 467 | TransRValue, |
| ... | @@ -1286,11 +1305,35 @@ static AstNode *trans_decl_ref_expr(Context *c, DeclRefExpr *stmt, TransLRValue | ... | @@ -1286,11 +1305,35 @@ static AstNode *trans_decl_ref_expr(Context *c, DeclRefExpr *stmt, TransLRValue |
| 1286 | return trans_create_node_symbol(c, symbol_name); | 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 | switch (stmt->getOpcode()) { | 1309 | switch (stmt->getOpcode()) { |
| 1291 | case UO_PostInc: | 1310 | case UO_PostInc: { |
| 1292 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PostInc"); | 1311 | Expr *op_expr = stmt->getSubExpr(); |
| 1293 | return nullptr; | 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 | case UO_PostDec: | 1337 | case UO_PostDec: |
| 1295 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PostDec"); | 1338 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PostDec"); |
| 1296 | return nullptr; | 1339 | return nullptr; |
| ... | @@ -1312,7 +1355,7 @@ static AstNode *trans_unary_operator(Context *c, AstNode *block, UnaryOperator * | ... | @@ -1312,7 +1355,7 @@ static AstNode *trans_unary_operator(Context *c, AstNode *block, UnaryOperator * |
| 1312 | case UO_Minus: | 1355 | case UO_Minus: |
| 1313 | { | 1356 | { |
| 1314 | Expr *op_expr = stmt->getSubExpr(); | 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 | AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr); | 1359 | AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr); |
| 1317 | node->data.prefix_op_expr.prefix_op = PrefixOpNegation; | 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,7 +1685,7 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s |
| 1642 | case Stmt::DeclRefExprClass: | 1685 | case Stmt::DeclRefExprClass: |
| 1643 | return trans_decl_ref_expr(c, (DeclRefExpr *)stmt, lrvalue); | 1686 | return trans_decl_ref_expr(c, (DeclRefExpr *)stmt, lrvalue); |
| 1644 | case Stmt::UnaryOperatorClass: | 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 | case Stmt::DeclStmtClass: | 1689 | case Stmt::DeclStmtClass: |
| 1647 | return trans_local_declaration(c, block, (DeclStmt *)stmt); | 1690 | return trans_local_declaration(c, block, (DeclStmt *)stmt); |
| 1648 | case Stmt::WhileStmtClass: | 1691 | case Stmt::WhileStmtClass: |