| ... | ... | @@ -397,8 +397,9 @@ pub const DeclGen = struct { |
| 397 | 397 | .Struct => { |
| 398 | 398 | const field_vals = val.castTag(.@"struct").?.data; |
| 399 | 399 | |
| 400 | try writer.writeAll("("); |
| 400 | 401 | try dg.renderType(writer, ty); |
| 401 | | try writer.writeAll("{"); |
| 402 | try writer.writeAll("){"); |
| 402 | 403 | |
| 403 | 404 | for (field_vals) |field_val, i| { |
| 404 | 405 | const field_ty = ty.structFieldType(i); |
| ... | ... | @@ -529,9 +530,9 @@ pub const DeclGen = struct { |
| 529 | 530 | const elem_type = t.elemType(); |
| 530 | 531 | try dg.renderType(bw, elem_type); |
| 531 | 532 | try bw.writeAll(" *"); |
| 532 | | if (t.isConstPtr()) { |
| 533 | | try bw.writeAll("const "); |
| 534 | | } |
| 533 | // We skip the const qualifier because C's type system |
| 534 | // would not allow a local mutable variable which is this slice type |
| 535 | // to be overwritten with a new slice type. |
| 535 | 536 | if (t.isVolatilePtr()) { |
| 536 | 537 | try bw.writeAll("volatile "); |
| 537 | 538 | } |
| ... | ... | @@ -549,15 +550,40 @@ pub const DeclGen = struct { |
| 549 | 550 | try t.copy(dg.typedefs_arena), |
| 550 | 551 | .{ .name = name, .rendered = rendered }, |
| 551 | 552 | ); |
| 552 | | } else { |
| 553 | | try dg.renderType(w, t.elemType()); |
| 554 | | try w.writeAll(" *"); |
| 555 | | if (t.isConstPtr()) { |
| 556 | | try w.writeAll("const "); |
| 553 | return; |
| 554 | } |
| 555 | if (t.castPtrToFn()) |fn_ty| { |
| 556 | const fn_info = fn_ty.fnInfo(); |
| 557 | try dg.renderType(w, fn_info.return_type); |
| 558 | try w.writeAll(" (*)("); |
| 559 | const param_len = fn_info.param_types.len; |
| 560 | const is_var_args = fn_info.is_var_args; |
| 561 | if (param_len == 0 and !is_var_args) |
| 562 | try w.writeAll("void") |
| 563 | else { |
| 564 | var index: usize = 0; |
| 565 | while (index < param_len) : (index += 1) { |
| 566 | if (index > 0) { |
| 567 | try w.writeAll(", "); |
| 568 | } |
| 569 | try dg.renderType(w, fn_info.param_types[index]); |
| 570 | } |
| 557 | 571 | } |
| 558 | | if (t.isVolatilePtr()) { |
| 559 | | try w.writeAll("volatile "); |
| 572 | if (is_var_args) { |
| 573 | if (param_len != 0) try w.writeAll(", "); |
| 574 | try w.writeAll("..."); |
| 560 | 575 | } |
| 576 | try w.writeByte(')'); |
| 577 | return; |
| 578 | } |
| 579 | |
| 580 | try dg.renderType(w, t.elemType()); |
| 581 | try w.writeAll(" *"); |
| 582 | if (t.isConstPtr()) { |
| 583 | try w.writeAll("const "); |
| 584 | } |
| 585 | if (t.isVolatilePtr()) { |
| 586 | try w.writeAll("volatile "); |
| 561 | 587 | } |
| 562 | 588 | }, |
| 563 | 589 | .Array => { |
| ... | ... | @@ -685,28 +711,7 @@ pub const DeclGen = struct { |
| 685 | 711 | try dg.renderType(w, int_tag_ty); |
| 686 | 712 | }, |
| 687 | 713 | .Union => return dg.fail("TODO: C backend: implement type Union", .{}), |
| 688 | | .Fn => { |
| 689 | | try dg.renderType(w, t.fnReturnType()); |
| 690 | | try w.writeAll(" (*)("); |
| 691 | | const param_len = t.fnParamLen(); |
| 692 | | const is_var_args = t.fnIsVarArgs(); |
| 693 | | if (param_len == 0 and !is_var_args) |
| 694 | | try w.writeAll("void") |
| 695 | | else { |
| 696 | | var index: usize = 0; |
| 697 | | while (index < param_len) : (index += 1) { |
| 698 | | if (index > 0) { |
| 699 | | try w.writeAll(", "); |
| 700 | | } |
| 701 | | try dg.renderType(w, t.fnParamType(index)); |
| 702 | | } |
| 703 | | } |
| 704 | | if (is_var_args) { |
| 705 | | if (param_len != 0) try w.writeAll(", "); |
| 706 | | try w.writeAll("..."); |
| 707 | | } |
| 708 | | try w.writeByte(')'); |
| 709 | | }, |
| 714 | .Fn => unreachable, // This is a function body, not a function pointer. |
| 710 | 715 | .Opaque => return dg.fail("TODO: C backend: implement type Opaque", .{}), |
| 711 | 716 | .Frame => return dg.fail("TODO: C backend: implement type Frame", .{}), |
| 712 | 717 | .AnyFrame => return dg.fail("TODO: C backend: implement type AnyFrame", .{}), |
| ... | ... | @@ -742,8 +747,59 @@ pub const DeclGen = struct { |
| 742 | 747 | render_ty = render_ty.elemType(); |
| 743 | 748 | } |
| 744 | 749 | |
| 745 | | if (render_ty.zigTypeTag() == .Fn) { |
| 746 | | const ret_ty = render_ty.fnReturnType(); |
| 750 | // TODO this is duplicated from the code below and does not handle |
| 751 | // arbitrary nesting of pointers. This renderTypeAndName function |
| 752 | // needs to be reworked by someone who understands C's insane type syntax. That |
| 753 | // person might be future me but it is certainly not present me. |
| 754 | if (render_ty.zigTypeTag() == .Pointer and |
| 755 | render_ty.childType().zigTypeTag() == .Pointer and |
| 756 | render_ty.childType().childType().zigTypeTag() == .Fn) |
| 757 | { |
| 758 | const ptr2_ty = render_ty.childType(); |
| 759 | const fn_info = ptr2_ty.childType().fnInfo(); |
| 760 | const ret_ty = fn_info.return_type; |
| 761 | if (ret_ty.zigTypeTag() == .NoReturn) { |
| 762 | // noreturn attribute is not allowed here. |
| 763 | try w.writeAll("void"); |
| 764 | } else { |
| 765 | try dg.renderType(w, ret_ty); |
| 766 | } |
| 767 | try w.writeAll(" (*"); |
| 768 | switch (mutability) { |
| 769 | .Const => try w.writeAll("const "), |
| 770 | .Mut => {}, |
| 771 | } |
| 772 | if (!ptr2_ty.ptrIsMutable()) { |
| 773 | try w.writeAll("*const "); |
| 774 | } else { |
| 775 | try w.writeAll("*"); |
| 776 | } |
| 777 | try dg.writeCValue(w, name); |
| 778 | try w.writeAll(")("); |
| 779 | const param_len = fn_info.param_types.len; |
| 780 | const is_var_args = fn_info.is_var_args; |
| 781 | if (param_len == 0 and !is_var_args) |
| 782 | try w.writeAll("void") |
| 783 | else { |
| 784 | var index: usize = 0; |
| 785 | while (index < param_len) : (index += 1) { |
| 786 | if (index > 0) { |
| 787 | try w.writeAll(", "); |
| 788 | } |
| 789 | try dg.renderType(w, fn_info.param_types[index]); |
| 790 | } |
| 791 | } |
| 792 | if (is_var_args) { |
| 793 | if (param_len != 0) try w.writeAll(", "); |
| 794 | try w.writeAll("..."); |
| 795 | } |
| 796 | try w.writeByte(')'); |
| 797 | return; |
| 798 | } |
| 799 | |
| 800 | if (render_ty.castPtrToFn()) |fn_ty| { |
| 801 | const fn_info = fn_ty.fnInfo(); |
| 802 | const ret_ty = fn_info.return_type; |
| 747 | 803 | if (ret_ty.zigTypeTag() == .NoReturn) { |
| 748 | 804 | // noreturn attribute is not allowed here. |
| 749 | 805 | try w.writeAll("void"); |
| ... | ... | @@ -757,8 +813,8 @@ pub const DeclGen = struct { |
| 757 | 813 | } |
| 758 | 814 | try dg.writeCValue(w, name); |
| 759 | 815 | try w.writeAll(")("); |
| 760 | | const param_len = render_ty.fnParamLen(); |
| 761 | | const is_var_args = render_ty.fnIsVarArgs(); |
| 816 | const param_len = fn_info.param_types.len; |
| 817 | const is_var_args = fn_info.is_var_args; |
| 762 | 818 | if (param_len == 0 and !is_var_args) |
| 763 | 819 | try w.writeAll("void") |
| 764 | 820 | else { |
| ... | ... | @@ -767,7 +823,7 @@ pub const DeclGen = struct { |
| 767 | 823 | if (index > 0) { |
| 768 | 824 | try w.writeAll(", "); |
| 769 | 825 | } |
| 770 | | try dg.renderType(w, render_ty.fnParamType(index)); |
| 826 | try dg.renderType(w, fn_info.param_types[index]); |
| 771 | 827 | } |
| 772 | 828 | } |
| 773 | 829 | if (is_var_args) { |
| ... | ... | @@ -1083,7 +1139,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 1083 | 1139 | |
| 1084 | 1140 | .ptr_elem_val => try airPtrElemVal(f, inst, "["), |
| 1085 | 1141 | .ptr_elem_ptr => try airPtrElemPtr(f, inst), |
| 1086 | | .slice_elem_val => try airSliceElemVal(f, inst, "["), |
| 1142 | .slice_elem_val => try airSliceElemVal(f, inst), |
| 1087 | 1143 | .slice_elem_ptr => try airSliceElemPtr(f, inst), |
| 1088 | 1144 | .array_elem_val => try airArrayElemVal(f, inst), |
| 1089 | 1145 | |
| ... | ... | @@ -1149,27 +1205,26 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1149 | 1205 | return f.fail("TODO: C backend: airPtrElemPtr", .{}); |
| 1150 | 1206 | } |
| 1151 | 1207 | |
| 1152 | | fn airSliceElemVal(f: *Function, inst: Air.Inst.Index, prefix: []const u8) !CValue { |
| 1153 | | const is_volatile = false; // TODO |
| 1154 | | if (!is_volatile and f.liveness.isUnused(inst)) |
| 1155 | | return CValue.none; |
| 1156 | | |
| 1208 | fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1157 | 1209 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 1210 | const slice_ty = f.air.typeOf(bin_op.lhs); |
| 1211 | if (!slice_ty.isVolatilePtr() and f.liveness.isUnused(inst)) return CValue.none; |
| 1212 | |
| 1158 | 1213 | const slice = try f.resolveInst(bin_op.lhs); |
| 1159 | 1214 | const index = try f.resolveInst(bin_op.rhs); |
| 1160 | 1215 | const writer = f.object.writer(); |
| 1161 | 1216 | const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); |
| 1162 | 1217 | try writer.writeAll(" = "); |
| 1163 | 1218 | try f.writeCValue(writer, slice); |
| 1164 | | try writer.writeAll(prefix); |
| 1219 | try writer.writeAll(".ptr["); |
| 1165 | 1220 | try f.writeCValue(writer, index); |
| 1166 | 1221 | try writer.writeAll("];\n"); |
| 1167 | 1222 | return local; |
| 1168 | 1223 | } |
| 1169 | 1224 | |
| 1170 | 1225 | fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1171 | | if (f.liveness.isUnused(inst)) |
| 1172 | | return CValue.none; |
| 1226 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 1227 | |
| 1173 | 1228 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 1174 | 1229 | const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1175 | 1230 | |
| ... | ... | @@ -1179,7 +1234,7 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1179 | 1234 | const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); |
| 1180 | 1235 | try writer.writeAll(" = &"); |
| 1181 | 1236 | try f.writeCValue(writer, slice); |
| 1182 | | try writer.writeByte('['); |
| 1237 | try writer.writeAll(".ptr["); |
| 1183 | 1238 | try f.writeCValue(writer, index); |
| 1184 | 1239 | try writer.writeAll("];\n"); |
| 1185 | 1240 | return local; |