| ... | @@ -397,8 +397,9 @@ pub const DeclGen = struct { | ... | @@ -397,8 +397,9 @@ pub const DeclGen = struct { |
| 397 | .Struct => { | 397 | .Struct => { |
| 398 | const field_vals = val.castTag(.@"struct").?.data; | 398 | const field_vals = val.castTag(.@"struct").?.data; |
| 399 | | 399 | |
| | 400 | try writer.writeAll("("); |
| 400 | try dg.renderType(writer, ty); | 401 | try dg.renderType(writer, ty); |
| 401 | try writer.writeAll("{"); | 402 | try writer.writeAll("){"); |
| 402 | | 403 | |
| 403 | for (field_vals) |field_val, i| { | 404 | for (field_vals) |field_val, i| { |
| 404 | const field_ty = ty.structFieldType(i); | 405 | const field_ty = ty.structFieldType(i); |
| ... | @@ -529,9 +530,9 @@ pub const DeclGen = struct { | ... | @@ -529,9 +530,9 @@ pub const DeclGen = struct { |
| 529 | const elem_type = t.elemType(); | 530 | const elem_type = t.elemType(); |
| 530 | try dg.renderType(bw, elem_type); | 531 | try dg.renderType(bw, elem_type); |
| 531 | try bw.writeAll(" *"); | 532 | try bw.writeAll(" *"); |
| 532 | if (t.isConstPtr()) { | 533 | // We skip the const qualifier because C's type system |
| 533 | try bw.writeAll("const "); | 534 | // would not allow a local mutable variable which is this slice type |
| 534 | } | 535 | // to be overwritten with a new slice type. |
| 535 | if (t.isVolatilePtr()) { | 536 | if (t.isVolatilePtr()) { |
| 536 | try bw.writeAll("volatile "); | 537 | try bw.writeAll("volatile "); |
| 537 | } | 538 | } |
| ... | @@ -549,15 +550,40 @@ pub const DeclGen = struct { | ... | @@ -549,15 +550,40 @@ pub const DeclGen = struct { |
| 549 | try t.copy(dg.typedefs_arena), | 550 | try t.copy(dg.typedefs_arena), |
| 550 | .{ .name = name, .rendered = rendered }, | 551 | .{ .name = name, .rendered = rendered }, |
| 551 | ); | 552 | ); |
| 552 | } else { | 553 | return; |
| 553 | try dg.renderType(w, t.elemType()); | 554 | } |
| 554 | try w.writeAll(" *"); | 555 | if (t.castPtrToFn()) |fn_ty| { |
| 555 | if (t.isConstPtr()) { | 556 | const fn_info = fn_ty.fnInfo(); |
| 556 | try w.writeAll("const "); | 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()) { | 572 | if (is_var_args) { |
| 559 | try w.writeAll("volatile "); | 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 | .Array => { | 589 | .Array => { |
| ... | @@ -685,28 +711,7 @@ pub const DeclGen = struct { | ... | @@ -685,28 +711,7 @@ pub const DeclGen = struct { |
| 685 | try dg.renderType(w, int_tag_ty); | 711 | try dg.renderType(w, int_tag_ty); |
| 686 | }, | 712 | }, |
| 687 | .Union => return dg.fail("TODO: C backend: implement type Union", .{}), | 713 | .Union => return dg.fail("TODO: C backend: implement type Union", .{}), |
| 688 | .Fn => { | 714 | .Fn => unreachable, // This is a function body, not a function pointer. |
| 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 | }, | | |
| 710 | .Opaque => return dg.fail("TODO: C backend: implement type Opaque", .{}), | 715 | .Opaque => return dg.fail("TODO: C backend: implement type Opaque", .{}), |
| 711 | .Frame => return dg.fail("TODO: C backend: implement type Frame", .{}), | 716 | .Frame => return dg.fail("TODO: C backend: implement type Frame", .{}), |
| 712 | .AnyFrame => return dg.fail("TODO: C backend: implement type AnyFrame", .{}), | 717 | .AnyFrame => return dg.fail("TODO: C backend: implement type AnyFrame", .{}), |
| ... | @@ -742,8 +747,59 @@ pub const DeclGen = struct { | ... | @@ -742,8 +747,59 @@ pub const DeclGen = struct { |
| 742 | render_ty = render_ty.elemType(); | 747 | render_ty = render_ty.elemType(); |
| 743 | } | 748 | } |
| 744 | | 749 | |
| 745 | if (render_ty.zigTypeTag() == .Fn) { | 750 | // TODO this is duplicated from the code below and does not handle |
| 746 | const ret_ty = render_ty.fnReturnType(); | 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 | if (ret_ty.zigTypeTag() == .NoReturn) { | 803 | if (ret_ty.zigTypeTag() == .NoReturn) { |
| 748 | // noreturn attribute is not allowed here. | 804 | // noreturn attribute is not allowed here. |
| 749 | try w.writeAll("void"); | 805 | try w.writeAll("void"); |
| ... | @@ -757,8 +813,8 @@ pub const DeclGen = struct { | ... | @@ -757,8 +813,8 @@ pub const DeclGen = struct { |
| 757 | } | 813 | } |
| 758 | try dg.writeCValue(w, name); | 814 | try dg.writeCValue(w, name); |
| 759 | try w.writeAll(")("); | 815 | try w.writeAll(")("); |
| 760 | const param_len = render_ty.fnParamLen(); | 816 | const param_len = fn_info.param_types.len; |
| 761 | const is_var_args = render_ty.fnIsVarArgs(); | 817 | const is_var_args = fn_info.is_var_args; |
| 762 | if (param_len == 0 and !is_var_args) | 818 | if (param_len == 0 and !is_var_args) |
| 763 | try w.writeAll("void") | 819 | try w.writeAll("void") |
| 764 | else { | 820 | else { |
| ... | @@ -767,7 +823,7 @@ pub const DeclGen = struct { | ... | @@ -767,7 +823,7 @@ pub const DeclGen = struct { |
| 767 | if (index > 0) { | 823 | if (index > 0) { |
| 768 | try w.writeAll(", "); | 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 | if (is_var_args) { | 829 | if (is_var_args) { |
| ... | @@ -1083,7 +1139,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO | ... | @@ -1083,7 +1139,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 1083 | | 1139 | |
| 1084 | .ptr_elem_val => try airPtrElemVal(f, inst, "["), | 1140 | .ptr_elem_val => try airPtrElemVal(f, inst, "["), |
| 1085 | .ptr_elem_ptr => try airPtrElemPtr(f, inst), | 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 | .slice_elem_ptr => try airSliceElemPtr(f, inst), | 1143 | .slice_elem_ptr => try airSliceElemPtr(f, inst), |
| 1088 | .array_elem_val => try airArrayElemVal(f, inst), | 1144 | .array_elem_val => try airArrayElemVal(f, inst), |
| 1089 | | 1145 | |
| ... | @@ -1149,27 +1205,26 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -1149,27 +1205,26 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1149 | return f.fail("TODO: C backend: airPtrElemPtr", .{}); | 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 { | 1208 | fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1153 | const is_volatile = false; // TODO | | |
| 1154 | if (!is_volatile and f.liveness.isUnused(inst)) | | |
| 1155 | return CValue.none; | | |
| 1156 | | | |
| 1157 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 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 | const slice = try f.resolveInst(bin_op.lhs); | 1213 | const slice = try f.resolveInst(bin_op.lhs); |
| 1159 | const index = try f.resolveInst(bin_op.rhs); | 1214 | const index = try f.resolveInst(bin_op.rhs); |
| 1160 | const writer = f.object.writer(); | 1215 | const writer = f.object.writer(); |
| 1161 | const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); | 1216 | const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); |
| 1162 | try writer.writeAll(" = "); | 1217 | try writer.writeAll(" = "); |
| 1163 | try f.writeCValue(writer, slice); | 1218 | try f.writeCValue(writer, slice); |
| 1164 | try writer.writeAll(prefix); | 1219 | try writer.writeAll(".ptr["); |
| 1165 | try f.writeCValue(writer, index); | 1220 | try f.writeCValue(writer, index); |
| 1166 | try writer.writeAll("];\n"); | 1221 | try writer.writeAll("];\n"); |
| 1167 | return local; | 1222 | return local; |
| 1168 | } | 1223 | } |
| 1169 | | 1224 | |
| 1170 | fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { | 1225 | fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1171 | if (f.liveness.isUnused(inst)) | 1226 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 1172 | return CValue.none; | 1227 | |
| 1173 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | 1228 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 1174 | const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data; | 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,7 +1234,7 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1179 | const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); | 1234 | const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); |
| 1180 | try writer.writeAll(" = &"); | 1235 | try writer.writeAll(" = &"); |
| 1181 | try f.writeCValue(writer, slice); | 1236 | try f.writeCValue(writer, slice); |
| 1182 | try writer.writeByte('['); | 1237 | try writer.writeAll(".ptr["); |
| 1183 | try f.writeCValue(writer, index); | 1238 | try f.writeCValue(writer, index); |
| 1184 | try writer.writeAll("];\n"); | 1239 | try writer.writeAll("];\n"); |
| 1185 | return local; | 1240 | return local; |