| ... | ... | @@ -78,6 +78,10 @@ const Scope = struct { |
| 78 | 78 | mangle_count: u32 = 0, |
| 79 | 79 | lbrace: ast.TokenIndex, |
| 80 | 80 | |
| 81 | /// When the block corresponds to a function, keep track of the return type |
| 82 | /// so that the return expression can be cast, if necessary |
| 83 | return_type: ?clang.QualType = null, |
| 84 | |
| 81 | 85 | fn init(c: *Context, parent: *Scope, labeled: bool) !Block { |
| 82 | 86 | var blk = Block{ |
| 83 | 87 | .base = .{ |
| ... | ... | @@ -209,6 +213,21 @@ const Scope = struct { |
| 209 | 213 | } |
| 210 | 214 | } |
| 211 | 215 | |
| 216 | fn findBlockReturnType(inner: *Scope, c: *Context) ?clang.QualType { |
| 217 | var scope = inner; |
| 218 | while (true) { |
| 219 | switch (scope.id) { |
| 220 | .Root => return null, |
| 221 | .Block => { |
| 222 | const block = @fieldParentPtr(Block, "base", scope); |
| 223 | if (block.return_type) |qt| return qt; |
| 224 | scope = scope.parent.?; |
| 225 | }, |
| 226 | else => scope = scope.parent.?, |
| 227 | } |
| 228 | } |
| 229 | } |
| 230 | |
| 212 | 231 | fn getAlias(scope: *Scope, name: []const u8) []const u8 { |
| 213 | 232 | return switch (scope.id) { |
| 214 | 233 | .Root => return name, |
| ... | ... | @@ -580,6 +599,8 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { |
| 580 | 599 | else => break fn_type, |
| 581 | 600 | } |
| 582 | 601 | } else unreachable; |
| 602 | const fn_ty = @ptrCast(*const clang.FunctionType, fn_type); |
| 603 | const return_qt = fn_ty.getReturnType(); |
| 583 | 604 | |
| 584 | 605 | const proto_node = switch (fn_type.getTypeClass()) { |
| 585 | 606 | .FunctionProto => blk: { |
| ... | ... | @@ -617,7 +638,9 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { |
| 617 | 638 | // actual function definition with body |
| 618 | 639 | const body_stmt = fn_decl.getBody(); |
| 619 | 640 | var block_scope = try Scope.Block.init(rp.c, &c.global_scope.base, false); |
| 641 | block_scope.return_type = return_qt; |
| 620 | 642 | defer block_scope.deinit(); |
| 643 | |
| 621 | 644 | var scope = &block_scope.base; |
| 622 | 645 | |
| 623 | 646 | var param_id: c_uint = 0; |
| ... | ... | @@ -667,10 +690,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { |
| 667 | 690 | }; |
| 668 | 691 | // add return statement if the function didn't have one |
| 669 | 692 | blk: { |
| 670 | | const fn_ty = @ptrCast(*const clang.FunctionType, fn_type); |
| 671 | | |
| 672 | 693 | if (fn_ty.getNoReturnAttr()) break :blk; |
| 673 | | const return_qt = fn_ty.getReturnType(); |
| 674 | 694 | if (isCVoid(return_qt)) break :blk; |
| 675 | 695 | |
| 676 | 696 | if (block_scope.statements.items.len > 0) { |
| ... | ... | @@ -2018,16 +2038,32 @@ fn transIntegerLiteral( |
| 2018 | 2038 | return maybeSuppressResult(rp, scope, result_used, &as_node.base); |
| 2019 | 2039 | } |
| 2020 | 2040 | |
| 2041 | /// In C if a function has return type `int` and the return value is a boolean |
| 2042 | /// expression, there is no implicit cast. So the translated Zig will need to |
| 2043 | /// call @boolToInt |
| 2044 | fn zigShouldCastBooleanReturnToInt(node: ?*ast.Node, qt: ?clang.QualType) bool { |
| 2045 | if (node == null or qt == null) return false; |
| 2046 | return isBoolRes(node.?) and cIsNativeInt(qt.?); |
| 2047 | } |
| 2048 | |
| 2021 | 2049 | fn transReturnStmt( |
| 2022 | 2050 | rp: RestorePoint, |
| 2023 | 2051 | scope: *Scope, |
| 2024 | 2052 | expr: *const clang.ReturnStmt, |
| 2025 | 2053 | ) TransError!*ast.Node { |
| 2026 | 2054 | const return_kw = try appendToken(rp.c, .Keyword_return, "return"); |
| 2027 | | const rhs: ?*ast.Node = if (expr.getRetValue()) |val_expr| |
| 2055 | var rhs: ?*ast.Node = if (expr.getRetValue()) |val_expr| |
| 2028 | 2056 | try transExprCoercing(rp, scope, val_expr, .used, .r_value) |
| 2029 | 2057 | else |
| 2030 | 2058 | null; |
| 2059 | const return_qt = scope.findBlockReturnType(rp.c); |
| 2060 | if (zigShouldCastBooleanReturnToInt(rhs, return_qt)) { |
| 2061 | const bool_to_int_node = try rp.c.createBuiltinCall("@boolToInt", 1); |
| 2062 | bool_to_int_node.params()[0] = rhs.?; |
| 2063 | bool_to_int_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 2064 | |
| 2065 | rhs = &bool_to_int_node.base; |
| 2066 | } |
| 2031 | 2067 | const return_expr = try ast.Node.ControlFlowExpression.create(rp.c.arena, .{ |
| 2032 | 2068 | .ltoken = return_kw, |
| 2033 | 2069 | .tag = .Return, |