| ... | @@ -179,6 +179,14 @@ pub const DeclGen = struct { | ... | @@ -179,6 +179,14 @@ pub const DeclGen = struct { |
| 179 | return error.AnalysisFail; | 179 | return error.AnalysisFail; |
| 180 | } | 180 | } |
| 181 | | 181 | |
| | 182 | fn getTypedefName(dg: *DeclGen, t: Type) ?[]const u8 { |
| | 183 | if (dg.typedefs.get(t)) |some| { |
| | 184 | return some.name; |
| | 185 | } else { |
| | 186 | return null; |
| | 187 | } |
| | 188 | } |
| | 189 | |
| 182 | fn renderDeclValue( | 190 | fn renderDeclValue( |
| 183 | dg: *DeclGen, | 191 | dg: *DeclGen, |
| 184 | writer: anytype, | 192 | writer: anytype, |
| ... | @@ -200,14 +208,20 @@ pub const DeclGen = struct { | ... | @@ -200,14 +208,20 @@ pub const DeclGen = struct { |
| 200 | return; | 208 | return; |
| 201 | } | 209 | } |
| 202 | | 210 | |
| 203 | // Determine if we must pointer cast. | | |
| 204 | assert(decl.has_tv); | 211 | assert(decl.has_tv); |
| 205 | if (ty.eql(decl.ty)) { | 212 | // We shouldn't cast C function pointers as this is UB (when you call |
| 206 | try writer.writeByte('&'); | 213 | // them). The analysis until now should ensure that the C function |
| 207 | } else { | 214 | // pointers are compatible. If they are not, then there is a bug |
| 208 | try writer.writeAll("("); | 215 | // somewhere and we should let the C compiler tell us about it. |
| 209 | try dg.renderType(writer, ty); | 216 | if (ty.castPtrToFn() == null) { |
| 210 | try writer.writeAll(")&"); | 217 | // Determine if we must pointer cast. |
| | 218 | if (ty.eql(decl.ty)) { |
| | 219 | try writer.writeByte('&'); |
| | 220 | } else { |
| | 221 | try writer.writeAll("("); |
| | 222 | try dg.renderType(writer, ty); |
| | 223 | try writer.writeAll(")&"); |
| | 224 | } |
| 211 | } | 225 | } |
| 212 | try dg.renderDeclName(decl, writer); | 226 | try dg.renderDeclName(decl, writer); |
| 213 | } | 227 | } |
| ... | @@ -514,7 +528,190 @@ pub const DeclGen = struct { | ... | @@ -514,7 +528,190 @@ pub const DeclGen = struct { |
| 514 | try w.writeByte(')'); | 528 | try w.writeByte(')'); |
| 515 | } | 529 | } |
| 516 | | 530 | |
| | 531 | fn renderPtrToFnTypedef(dg: *DeclGen, t: Type, fn_ty: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |
| | 532 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| | 533 | defer buffer.deinit(); |
| | 534 | const bw = buffer.writer(); |
| | 535 | |
| | 536 | const fn_info = fn_ty.fnInfo(); |
| | 537 | |
| | 538 | try bw.writeAll("typedef "); |
| | 539 | try dg.renderType(bw, fn_info.return_type); |
| | 540 | try bw.writeAll(" (*"); |
| | 541 | |
| | 542 | const name_start = buffer.items.len; |
| | 543 | // TODO: typeToCIdentifier truncates to 128 bytes, we probably don't want to do this |
| | 544 | try bw.print("zig_F_{s})(", .{typeToCIdentifier(t)}); |
| | 545 | const name_end = buffer.items.len - 2; |
| | 546 | |
| | 547 | const param_len = fn_info.param_types.len; |
| | 548 | const is_var_args = fn_info.is_var_args; |
| | 549 | if (param_len == 0 and !is_var_args) |
| | 550 | try bw.writeAll("void") |
| | 551 | else { |
| | 552 | var index: usize = 0; |
| | 553 | while (index < param_len) : (index += 1) { |
| | 554 | if (index > 0) { |
| | 555 | try bw.writeAll(", "); |
| | 556 | } |
| | 557 | try dg.renderType(bw, fn_info.param_types[index]); |
| | 558 | } |
| | 559 | } |
| | 560 | if (is_var_args) { |
| | 561 | if (param_len != 0) try bw.writeAll(", "); |
| | 562 | try bw.writeAll("..."); |
| | 563 | } |
| | 564 | try bw.writeAll(");\n"); |
| | 565 | |
| | 566 | const rendered = buffer.toOwnedSlice(); |
| | 567 | errdefer dg.typedefs.allocator.free(rendered); |
| | 568 | const name = rendered[name_start..name_end]; |
| | 569 | |
| | 570 | try dg.typedefs.ensureUnusedCapacity(1); |
| | 571 | dg.typedefs.putAssumeCapacityNoClobber( |
| | 572 | try t.copy(dg.typedefs_arena), |
| | 573 | .{ .name = name, .rendered = rendered }, |
| | 574 | ); |
| | 575 | |
| | 576 | return name; |
| | 577 | } |
| | 578 | |
| | 579 | fn renderSliceTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |
| | 580 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| | 581 | defer buffer.deinit(); |
| | 582 | const bw = buffer.writer(); |
| | 583 | |
| | 584 | try bw.writeAll("typedef struct { "); |
| | 585 | const elem_type = t.elemType(); |
| | 586 | try dg.renderType(bw, elem_type); |
| | 587 | if (t.isConstPtr()) { |
| | 588 | try bw.writeAll(" const"); |
| | 589 | } |
| | 590 | if (t.isVolatilePtr()) { |
| | 591 | try bw.writeAll(" volatile"); |
| | 592 | } |
| | 593 | try bw.writeAll(" *"); |
| | 594 | try bw.writeAll("ptr; size_t len; } "); |
| | 595 | const name_index = buffer.items.len; |
| | 596 | if (t.isConstPtr()) { |
| | 597 | try bw.print("zig_L_{s};\n", .{typeToCIdentifier(elem_type)}); |
| | 598 | } else { |
| | 599 | try bw.print("zig_M_{s};\n", .{typeToCIdentifier(elem_type)}); |
| | 600 | } |
| | 601 | |
| | 602 | const rendered = buffer.toOwnedSlice(); |
| | 603 | errdefer dg.typedefs.allocator.free(rendered); |
| | 604 | const name = rendered[name_index .. rendered.len - 2]; |
| | 605 | |
| | 606 | try dg.typedefs.ensureUnusedCapacity(1); |
| | 607 | dg.typedefs.putAssumeCapacityNoClobber( |
| | 608 | try t.copy(dg.typedefs_arena), |
| | 609 | .{ .name = name, .rendered = rendered }, |
| | 610 | ); |
| | 611 | |
| | 612 | return name; |
| | 613 | } |
| | 614 | |
| | 615 | fn renderStructTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |
| | 616 | const struct_obj = t.castTag(.@"struct").?.data; // Handle 0 bit types elsewhere. |
| | 617 | const fqn = try struct_obj.getFullyQualifiedName(dg.typedefs.allocator); |
| | 618 | defer dg.typedefs.allocator.free(fqn); |
| | 619 | |
| | 620 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| | 621 | defer buffer.deinit(); |
| | 622 | |
| | 623 | try buffer.appendSlice("typedef struct {\n"); |
| | 624 | { |
| | 625 | var it = struct_obj.fields.iterator(); |
| | 626 | while (it.next()) |entry| { |
| | 627 | const field_ty = entry.value_ptr.ty; |
| | 628 | const name: CValue = .{ .bytes = entry.key_ptr.* }; |
| | 629 | try buffer.append(' '); |
| | 630 | try dg.renderTypeAndName(buffer.writer(), field_ty, name, .Mut); |
| | 631 | try buffer.appendSlice(";\n"); |
| | 632 | } |
| | 633 | } |
| | 634 | try buffer.appendSlice("} "); |
| | 635 | |
| | 636 | const name_start = buffer.items.len; |
| | 637 | try buffer.writer().print("zig_S_{s};\n", .{fmtIdent(fqn)}); |
| | 638 | |
| | 639 | const rendered = buffer.toOwnedSlice(); |
| | 640 | errdefer dg.typedefs.allocator.free(rendered); |
| | 641 | const name = rendered[name_start .. rendered.len - 2]; |
| | 642 | |
| | 643 | try dg.typedefs.ensureUnusedCapacity(1); |
| | 644 | dg.typedefs.putAssumeCapacityNoClobber( |
| | 645 | try t.copy(dg.typedefs_arena), |
| | 646 | .{ .name = name, .rendered = rendered }, |
| | 647 | ); |
| | 648 | |
| | 649 | return name; |
| | 650 | } |
| | 651 | |
| | 652 | fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |
| | 653 | const child_type = t.errorUnionPayload(); |
| | 654 | const err_set_type = t.errorUnionSet(); |
| | 655 | |
| | 656 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| | 657 | defer buffer.deinit(); |
| | 658 | const bw = buffer.writer(); |
| | 659 | |
| | 660 | try bw.writeAll("typedef struct { "); |
| | 661 | try dg.renderType(bw, child_type); |
| | 662 | try bw.writeAll(" payload; uint16_t error; } "); |
| | 663 | const name_index = buffer.items.len; |
| | 664 | if (err_set_type.castTag(.error_set_inferred)) |inf_err_set_payload| { |
| | 665 | const func = inf_err_set_payload.data.func; |
| | 666 | try bw.writeAll("zig_E_"); |
| | 667 | try dg.renderDeclName(func.owner_decl, bw); |
| | 668 | try bw.writeAll(";\n"); |
| | 669 | } else { |
| | 670 | try bw.print("zig_E_{s}_{s};\n", .{ |
| | 671 | typeToCIdentifier(err_set_type), typeToCIdentifier(child_type), |
| | 672 | }); |
| | 673 | } |
| | 674 | |
| | 675 | const rendered = buffer.toOwnedSlice(); |
| | 676 | errdefer dg.typedefs.allocator.free(rendered); |
| | 677 | const name = rendered[name_index .. rendered.len - 2]; |
| | 678 | |
| | 679 | try dg.typedefs.ensureUnusedCapacity(1); |
| | 680 | dg.typedefs.putAssumeCapacityNoClobber( |
| | 681 | try t.copy(dg.typedefs_arena), |
| | 682 | .{ .name = name, .rendered = rendered }, |
| | 683 | ); |
| | 684 | |
| | 685 | return name; |
| | 686 | } |
| | 687 | |
| | 688 | fn renderOptionalTypedef(dg: *DeclGen, t: Type, child_type: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |
| | 689 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| | 690 | defer buffer.deinit(); |
| | 691 | const bw = buffer.writer(); |
| | 692 | |
| | 693 | try bw.writeAll("typedef struct { "); |
| | 694 | try dg.renderType(bw, child_type); |
| | 695 | try bw.writeAll(" payload; bool is_null; } "); |
| | 696 | const name_index = buffer.items.len; |
| | 697 | try bw.print("zig_Q_{s};\n", .{typeToCIdentifier(child_type)}); |
| | 698 | |
| | 699 | const rendered = buffer.toOwnedSlice(); |
| | 700 | errdefer dg.typedefs.allocator.free(rendered); |
| | 701 | const name = rendered[name_index .. rendered.len - 2]; |
| | 702 | |
| | 703 | try dg.typedefs.ensureUnusedCapacity(1); |
| | 704 | dg.typedefs.putAssumeCapacityNoClobber( |
| | 705 | try t.copy(dg.typedefs_arena), |
| | 706 | .{ .name = name, .rendered = rendered }, |
| | 707 | ); |
| | 708 | |
| | 709 | return name; |
| | 710 | } |
| | 711 | |
| 517 | fn renderType(dg: *DeclGen, w: anytype, t: Type) error{ OutOfMemory, AnalysisFail }!void { | 712 | fn renderType(dg: *DeclGen, w: anytype, t: Type) error{ OutOfMemory, AnalysisFail }!void { |
| | 713 | const target = dg.module.getTarget(); |
| | 714 | |
| 518 | switch (t.zigTypeTag()) { | 715 | switch (t.zigTypeTag()) { |
| 519 | .NoReturn => { | 716 | .NoReturn => { |
| 520 | try w.writeAll("zig_noreturn void"); | 717 | try w.writeAll("zig_noreturn void"); |
| ... | @@ -542,7 +739,7 @@ pub const DeclGen = struct { | ... | @@ -542,7 +739,7 @@ pub const DeclGen = struct { |
| 542 | .c_longlong => try w.writeAll("long long"), | 739 | .c_longlong => try w.writeAll("long long"), |
| 543 | .c_ulonglong => try w.writeAll("unsigned long long"), | 740 | .c_ulonglong => try w.writeAll("unsigned long long"), |
| 544 | .int_signed, .int_unsigned => { | 741 | .int_signed, .int_unsigned => { |
| 545 | const info = t.intInfo(dg.module.getTarget()); | 742 | const info = t.intInfo(target); |
| 546 | const sign_prefix = switch (info.signedness) { | 743 | const sign_prefix = switch (info.signedness) { |
| 547 | .signed => "", | 744 | .signed => "", |
| 548 | .unsigned => "u", | 745 | .unsigned => "u", |
| ... | @@ -554,7 +751,6 @@ pub const DeclGen = struct { | ... | @@ -554,7 +751,6 @@ pub const DeclGen = struct { |
| 554 | else => unreachable, | 751 | else => unreachable, |
| 555 | } | 752 | } |
| 556 | }, | 753 | }, |
| 557 | | | |
| 558 | .Float => { | 754 | .Float => { |
| 559 | switch (t.tag()) { | 755 | switch (t.tag()) { |
| 560 | .f32 => try w.writeAll("float"), | 756 | .f32 => try w.writeAll("float"), |
| ... | @@ -565,196 +761,71 @@ pub const DeclGen = struct { | ... | @@ -565,196 +761,71 @@ pub const DeclGen = struct { |
| 565 | else => unreachable, | 761 | else => unreachable, |
| 566 | } | 762 | } |
| 567 | }, | 763 | }, |
| 568 | | | |
| 569 | .Pointer => { | 764 | .Pointer => { |
| 570 | if (t.isSlice()) { | 765 | if (t.isSlice()) { |
| 571 | if (dg.typedefs.get(t)) |some| { | 766 | const name = dg.getTypedefName(t) orelse |
| 572 | return w.writeAll(some.name); | 767 | try dg.renderSliceTypedef(t); |
| 573 | } | | |
| 574 | | 768 | |
| 575 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); | 769 | return w.writeAll(name); |
| 576 | defer buffer.deinit(); | | |
| 577 | const bw = buffer.writer(); | | |
| 578 | | | |
| 579 | try bw.writeAll("typedef struct { "); | | |
| 580 | const elem_type = t.elemType(); | | |
| 581 | try dg.renderType(bw, elem_type); | | |
| 582 | try bw.writeAll(" *"); | | |
| 583 | // We skip the const qualifier because C's type system | | |
| 584 | // would not allow a local mutable variable which is this slice type | | |
| 585 | // to be overwritten with a new slice type. | | |
| 586 | if (t.isVolatilePtr()) { | | |
| 587 | try bw.writeAll("volatile "); | | |
| 588 | } | | |
| 589 | try bw.writeAll("ptr; size_t len; } "); | | |
| 590 | const name_index = buffer.items.len; | | |
| 591 | try bw.print("zig_L_{s};\n", .{typeToCIdentifier(elem_type)}); | | |
| 592 | | | |
| 593 | const rendered = buffer.toOwnedSlice(); | | |
| 594 | errdefer dg.typedefs.allocator.free(rendered); | | |
| 595 | const name = rendered[name_index .. rendered.len - 2]; | | |
| 596 | | | |
| 597 | try dg.typedefs.ensureUnusedCapacity(1); | | |
| 598 | try w.writeAll(name); | | |
| 599 | dg.typedefs.putAssumeCapacityNoClobber( | | |
| 600 | try t.copy(dg.typedefs_arena), | | |
| 601 | .{ .name = name, .rendered = rendered }, | | |
| 602 | ); | | |
| 603 | return; | | |
| 604 | } | 770 | } |
| | 771 | |
| 605 | if (t.castPtrToFn()) |fn_ty| { | 772 | if (t.castPtrToFn()) |fn_ty| { |
| 606 | const fn_info = fn_ty.fnInfo(); | 773 | const name = dg.getTypedefName(t) orelse |
| 607 | try dg.renderType(w, fn_info.return_type); | 774 | try dg.renderPtrToFnTypedef(t, fn_ty); |
| 608 | try w.writeAll(" (*)("); | 775 | |
| 609 | const param_len = fn_info.param_types.len; | 776 | return w.writeAll(name); |
| 610 | const is_var_args = fn_info.is_var_args; | | |
| 611 | if (param_len == 0 and !is_var_args) | | |
| 612 | try w.writeAll("void") | | |
| 613 | else { | | |
| 614 | var index: usize = 0; | | |
| 615 | while (index < param_len) : (index += 1) { | | |
| 616 | if (index > 0) { | | |
| 617 | try w.writeAll(", "); | | |
| 618 | } | | |
| 619 | try dg.renderType(w, fn_info.param_types[index]); | | |
| 620 | } | | |
| 621 | } | | |
| 622 | if (is_var_args) { | | |
| 623 | if (param_len != 0) try w.writeAll(", "); | | |
| 624 | try w.writeAll("..."); | | |
| 625 | } | | |
| 626 | try w.writeByte(')'); | | |
| 627 | return; | | |
| 628 | } | 777 | } |
| 629 | | 778 | |
| 630 | try dg.renderType(w, t.elemType()); | 779 | try dg.renderType(w, t.elemType()); |
| 631 | try w.writeAll(" *"); | | |
| 632 | if (t.isConstPtr()) { | 780 | if (t.isConstPtr()) { |
| 633 | try w.writeAll("const "); | 781 | try w.writeAll(" const"); |
| 634 | } | 782 | } |
| 635 | if (t.isVolatilePtr()) { | 783 | if (t.isVolatilePtr()) { |
| 636 | try w.writeAll("volatile "); | 784 | try w.writeAll(" volatile"); |
| 637 | } | 785 | } |
| | 786 | return w.writeAll(" *"); |
| 638 | }, | 787 | }, |
| 639 | .Array => { | 788 | .Array => { |
| | 789 | // We are referencing the array so it will decay to a C pointer. |
| 640 | try dg.renderType(w, t.elemType()); | 790 | try dg.renderType(w, t.elemType()); |
| 641 | try w.writeAll(" *"); | 791 | return w.writeAll(" *"); |
| 642 | }, | 792 | }, |
| 643 | .Optional => { | 793 | .Optional => { |
| 644 | var opt_buf: Type.Payload.ElemType = undefined; | 794 | var opt_buf: Type.Payload.ElemType = undefined; |
| 645 | const child_type = t.optionalChild(&opt_buf); | 795 | const child_type = t.optionalChild(&opt_buf); |
| 646 | const target = dg.module.getTarget(); | 796 | |
| 647 | if (t.isPtrLikeOptional()) { | 797 | if (t.isPtrLikeOptional()) { |
| 648 | return dg.renderType(w, child_type); | 798 | return dg.renderType(w, child_type); |
| 649 | } else if (dg.typedefs.get(t)) |some| { | 799 | } |
| 650 | return w.writeAll(some.name); | 800 | |
| 651 | } else if (child_type.abiSize(target) == 0) { | 801 | if (child_type.abiSize(target) == 0) { |
| 652 | return w.writeAll("bool"); | 802 | return w.writeAll("bool"); |
| 653 | } | 803 | } |
| 654 | | 804 | |
| 655 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); | 805 | const name = dg.getTypedefName(t) orelse |
| 656 | defer buffer.deinit(); | 806 | try dg.renderOptionalTypedef(t, child_type); |
| 657 | const bw = buffer.writer(); | 807 | |
| 658 | | 808 | return w.writeAll(name); |
| 659 | try bw.writeAll("typedef struct { "); | | |
| 660 | try dg.renderType(bw, child_type); | | |
| 661 | try bw.writeAll(" payload; bool is_null; } "); | | |
| 662 | const name_index = buffer.items.len; | | |
| 663 | try bw.print("zig_Q_{s};\n", .{typeToCIdentifier(child_type)}); | | |
| 664 | | | |
| 665 | const rendered = buffer.toOwnedSlice(); | | |
| 666 | errdefer dg.typedefs.allocator.free(rendered); | | |
| 667 | const name = rendered[name_index .. rendered.len - 2]; | | |
| 668 | | | |
| 669 | try dg.typedefs.ensureUnusedCapacity(1); | | |
| 670 | try w.writeAll(name); | | |
| 671 | dg.typedefs.putAssumeCapacityNoClobber( | | |
| 672 | try t.copy(dg.typedefs_arena), | | |
| 673 | .{ .name = name, .rendered = rendered }, | | |
| 674 | ); | | |
| 675 | }, | 809 | }, |
| 676 | .ErrorSet => { | 810 | .ErrorSet => { |
| 677 | comptime std.debug.assert(Type.initTag(.anyerror).abiSize(builtin.target) == 2); | 811 | comptime std.debug.assert(Type.initTag(.anyerror).abiSize(builtin.target) == 2); |
| 678 | try w.writeAll("uint16_t"); | 812 | return w.writeAll("uint16_t"); |
| 679 | }, | 813 | }, |
| 680 | .ErrorUnion => { | 814 | .ErrorUnion => { |
| 681 | if (dg.typedefs.get(t)) |some| { | 815 | if (t.errorUnionPayload().abiSize(target) == 0) { |
| 682 | return w.writeAll(some.name); | 816 | return dg.renderType(w, t.errorUnionSet()); |
| 683 | } | | |
| 684 | const child_type = t.errorUnionPayload(); | | |
| 685 | const err_set_type = t.errorUnionSet(); | | |
| 686 | | | |
| 687 | if (!child_type.hasCodeGenBits()) { | | |
| 688 | return dg.renderType(w, err_set_type); | | |
| 689 | } | | |
| 690 | | | |
| 691 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); | | |
| 692 | defer buffer.deinit(); | | |
| 693 | const bw = buffer.writer(); | | |
| 694 | | | |
| 695 | try bw.writeAll("typedef struct { "); | | |
| 696 | try dg.renderType(bw, child_type); | | |
| 697 | try bw.writeAll(" payload; uint16_t error; } "); | | |
| 698 | const name_index = buffer.items.len; | | |
| 699 | if (err_set_type.castTag(.error_set_inferred)) |inf_err_set_payload| { | | |
| 700 | const func = inf_err_set_payload.data.func; | | |
| 701 | try bw.writeAll("zig_E_"); | | |
| 702 | try dg.renderDeclName(func.owner_decl, bw); | | |
| 703 | try bw.writeAll(";\n"); | | |
| 704 | } else { | | |
| 705 | try bw.print("zig_E_{s}_{s};\n", .{ | | |
| 706 | typeToCIdentifier(err_set_type), typeToCIdentifier(child_type), | | |
| 707 | }); | | |
| 708 | } | 817 | } |
| 709 | | 818 | |
| 710 | const rendered = buffer.toOwnedSlice(); | 819 | const name = dg.getTypedefName(t) orelse |
| 711 | errdefer dg.typedefs.allocator.free(rendered); | 820 | try dg.renderErrorUnionTypedef(t); |
| 712 | const name = rendered[name_index .. rendered.len - 2]; | | |
| 713 | | 821 | |
| 714 | try dg.typedefs.ensureUnusedCapacity(1); | 822 | return w.writeAll(name); |
| 715 | try w.writeAll(name); | | |
| 716 | dg.typedefs.putAssumeCapacityNoClobber( | | |
| 717 | try t.copy(dg.typedefs_arena), | | |
| 718 | .{ .name = name, .rendered = rendered }, | | |
| 719 | ); | | |
| 720 | }, | 823 | }, |
| 721 | .Struct => { | 824 | .Struct => { |
| 722 | if (dg.typedefs.get(t)) |some| { | 825 | const name = dg.getTypedefName(t) orelse |
| 723 | return w.writeAll(some.name); | 826 | try dg.renderStructTypedef(t); |
| 724 | } | | |
| 725 | const struct_obj = t.castTag(.@"struct").?.data; // Handle 0 bit types elsewhere. | | |
| 726 | const fqn = try struct_obj.getFullyQualifiedName(dg.typedefs.allocator); | | |
| 727 | defer dg.typedefs.allocator.free(fqn); | | |
| 728 | | | |
| 729 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); | | |
| 730 | defer buffer.deinit(); | | |
| 731 | | | |
| 732 | try buffer.appendSlice("typedef struct {\n"); | | |
| 733 | { | | |
| 734 | var it = struct_obj.fields.iterator(); | | |
| 735 | while (it.next()) |entry| { | | |
| 736 | const field_ty = entry.value_ptr.ty; | | |
| 737 | const name: CValue = .{ .bytes = entry.key_ptr.* }; | | |
| 738 | try buffer.append(' '); | | |
| 739 | try dg.renderTypeAndName(buffer.writer(), field_ty, name, .Mut); | | |
| 740 | try buffer.appendSlice(";\n"); | | |
| 741 | } | | |
| 742 | } | | |
| 743 | try buffer.appendSlice("} "); | | |
| 744 | | | |
| 745 | const name_start = buffer.items.len; | | |
| 746 | try buffer.writer().print("zig_S_{s};\n", .{fmtIdent(fqn)}); | | |
| 747 | | 827 | |
| 748 | const rendered = buffer.toOwnedSlice(); | 828 | return w.writeAll(name); |
| 749 | errdefer dg.typedefs.allocator.free(rendered); | | |
| 750 | const name = rendered[name_start .. rendered.len - 2]; | | |
| 751 | | | |
| 752 | try dg.typedefs.ensureUnusedCapacity(1); | | |
| 753 | try w.writeAll(name); | | |
| 754 | dg.typedefs.putAssumeCapacityNoClobber( | | |
| 755 | try t.copy(dg.typedefs_arena), | | |
| 756 | .{ .name = name, .rendered = rendered }, | | |
| 757 | ); | | |
| 758 | }, | 829 | }, |
| 759 | .Enum => { | 830 | .Enum => { |
| 760 | // For enums, we simply use the integer tag type. | 831 | // For enums, we simply use the integer tag type. |
| ... | @@ -763,12 +834,17 @@ pub const DeclGen = struct { | ... | @@ -763,12 +834,17 @@ pub const DeclGen = struct { |
| 763 | | 834 | |
| 764 | try dg.renderType(w, int_tag_ty); | 835 | try dg.renderType(w, int_tag_ty); |
| 765 | }, | 836 | }, |
| 766 | .Union => return dg.fail("TODO: C backend: implement type Union", .{}), | 837 | |
| | 838 | .Union, |
| | 839 | .Frame, |
| | 840 | .AnyFrame, |
| | 841 | .Vector, |
| | 842 | .Opaque, |
| | 843 | => |tag| return dg.fail("TODO: C backend: implement value of type {s}", .{ |
| | 844 | @tagName(tag), |
| | 845 | }), |
| | 846 | |
| 767 | .Fn => unreachable, // This is a function body, not a function pointer. | 847 | .Fn => unreachable, // This is a function body, not a function pointer. |
| 768 | .Opaque => return dg.fail("TODO: C backend: implement type Opaque", .{}), | | |
| 769 | .Frame => return dg.fail("TODO: C backend: implement type Frame", .{}), | | |
| 770 | .AnyFrame => return dg.fail("TODO: C backend: implement type AnyFrame", .{}), | | |
| 771 | .Vector => return dg.fail("TODO: C backend: implement type Vector", .{}), | | |
| 772 | | 848 | |
| 773 | .Null, | 849 | .Null, |
| 774 | .Undefined, | 850 | .Undefined, |
| ... | @@ -800,100 +876,14 @@ pub const DeclGen = struct { | ... | @@ -800,100 +876,14 @@ pub const DeclGen = struct { |
| 800 | render_ty = render_ty.elemType(); | 876 | render_ty = render_ty.elemType(); |
| 801 | } | 877 | } |
| 802 | | 878 | |
| 803 | // TODO this is duplicated from the code below and does not handle | 879 | try dg.renderType(w, render_ty); |
| 804 | // arbitrary nesting of pointers. This renderTypeAndName function | | |
| 805 | // needs to be reworked by someone who understands C's insane type syntax. That | | |
| 806 | // person might be future me but it is certainly not present me. | | |
| 807 | if (render_ty.zigTypeTag() == .Pointer and | | |
| 808 | render_ty.childType().zigTypeTag() == .Pointer and | | |
| 809 | render_ty.childType().childType().zigTypeTag() == .Fn) | | |
| 810 | { | | |
| 811 | const ptr2_ty = render_ty.childType(); | | |
| 812 | const fn_info = ptr2_ty.childType().fnInfo(); | | |
| 813 | const ret_ty = fn_info.return_type; | | |
| 814 | if (ret_ty.zigTypeTag() == .NoReturn) { | | |
| 815 | // noreturn attribute is not allowed here. | | |
| 816 | try w.writeAll("void"); | | |
| 817 | } else { | | |
| 818 | try dg.renderType(w, ret_ty); | | |
| 819 | } | | |
| 820 | try w.writeAll(" (*"); | | |
| 821 | switch (mutability) { | | |
| 822 | .Const => try w.writeAll("const "), | | |
| 823 | .Mut => {}, | | |
| 824 | } | | |
| 825 | if (!ptr2_ty.ptrIsMutable()) { | | |
| 826 | try w.writeAll("*const "); | | |
| 827 | } else { | | |
| 828 | try w.writeAll("*"); | | |
| 829 | } | | |
| 830 | try dg.writeCValue(w, name); | | |
| 831 | try w.writeAll(")("); | | |
| 832 | const param_len = fn_info.param_types.len; | | |
| 833 | const is_var_args = fn_info.is_var_args; | | |
| 834 | if (param_len == 0 and !is_var_args) | | |
| 835 | try w.writeAll("void") | | |
| 836 | else { | | |
| 837 | var index: usize = 0; | | |
| 838 | while (index < param_len) : (index += 1) { | | |
| 839 | if (index > 0) { | | |
| 840 | try w.writeAll(", "); | | |
| 841 | } | | |
| 842 | try dg.renderType(w, fn_info.param_types[index]); | | |
| 843 | } | | |
| 844 | } | | |
| 845 | if (is_var_args) { | | |
| 846 | if (param_len != 0) try w.writeAll(", "); | | |
| 847 | try w.writeAll("..."); | | |
| 848 | } | | |
| 849 | try w.writeByte(')'); | | |
| 850 | return; | | |
| 851 | } | | |
| 852 | | 880 | |
| 853 | if (render_ty.castPtrToFn()) |fn_ty| { | 881 | const const_prefix = switch (mutability) { |
| 854 | const fn_info = fn_ty.fnInfo(); | 882 | .Const => "const ", |
| 855 | const ret_ty = fn_info.return_type; | 883 | .Mut => "", |
| 856 | if (ret_ty.zigTypeTag() == .NoReturn) { | 884 | }; |
| 857 | // noreturn attribute is not allowed here. | 885 | try w.print(" {s}", .{const_prefix}); |
| 858 | try w.writeAll("void"); | 886 | try dg.writeCValue(w, name); |
| 859 | } else { | | |
| 860 | try dg.renderType(w, ret_ty); | | |
| 861 | } | | |
| 862 | try w.writeAll(" (*"); | | |
| 863 | switch (mutability) { | | |
| 864 | .Const => try w.writeAll("const "), | | |
| 865 | .Mut => {}, | | |
| 866 | } | | |
| 867 | try dg.writeCValue(w, name); | | |
| 868 | try w.writeAll(")("); | | |
| 869 | const param_len = fn_info.param_types.len; | | |
| 870 | const is_var_args = fn_info.is_var_args; | | |
| 871 | if (param_len == 0 and !is_var_args) | | |
| 872 | try w.writeAll("void") | | |
| 873 | else { | | |
| 874 | var index: usize = 0; | | |
| 875 | while (index < param_len) : (index += 1) { | | |
| 876 | if (index > 0) { | | |
| 877 | try w.writeAll(", "); | | |
| 878 | } | | |
| 879 | try dg.renderType(w, fn_info.param_types[index]); | | |
| 880 | } | | |
| 881 | } | | |
| 882 | if (is_var_args) { | | |
| 883 | if (param_len != 0) try w.writeAll(", "); | | |
| 884 | try w.writeAll("..."); | | |
| 885 | } | | |
| 886 | try w.writeByte(')'); | | |
| 887 | } else { | | |
| 888 | try dg.renderType(w, render_ty); | | |
| 889 | | | |
| 890 | const const_prefix = switch (mutability) { | | |
| 891 | .Const => "const ", | | |
| 892 | .Mut => "", | | |
| 893 | }; | | |
| 894 | try w.print(" {s}", .{const_prefix}); | | |
| 895 | try dg.writeCValue(w, name); | | |
| 896 | } | | |
| 897 | try w.writeAll(suffix.items); | 887 | try w.writeAll(suffix.items); |
| 898 | } | 888 | } |
| 899 | | 889 | |
| ... | @@ -1224,10 +1214,11 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO | ... | @@ -1224,10 +1214,11 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 1224 | fn airSliceField(f: *Function, inst: Air.Inst.Index, suffix: []const u8) !CValue { | 1214 | fn airSliceField(f: *Function, inst: Air.Inst.Index, suffix: []const u8) !CValue { |
| 1225 | if (f.liveness.isUnused(inst)) return CValue.none; | 1215 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 1226 | | 1216 | |
| | 1217 | const inst_ty = f.air.typeOfIndex(inst); |
| 1227 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 1218 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 1228 | const operand = try f.resolveInst(ty_op.operand); | 1219 | const operand = try f.resolveInst(ty_op.operand); |
| 1229 | const writer = f.object.writer(); | 1220 | const writer = f.object.writer(); |
| 1230 | const local = try f.allocLocal(Type.initTag(.usize), .Const); | 1221 | const local = try f.allocLocal(inst_ty, .Const); |
| 1231 | try writer.writeAll(" = "); | 1222 | try writer.writeAll(" = "); |
| 1232 | try f.writeCValue(writer, operand); | 1223 | try f.writeCValue(writer, operand); |
| 1233 | try writer.writeAll(suffix); | 1224 | try writer.writeAll(suffix); |