diff --git a/src/Module.zig b/src/Module.zig index f0b3701e6e..1f394a0833 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -4734,6 +4734,10 @@ pub fn populateTestFunctions(mod: *Module) !void { }), .val = try Value.Tag.array.create(arena, test_fn_vals), }); + + // Add a dependency on each test name and function pointer. + try array_decl.dependencies.ensureUnusedCapacity(gpa, test_fn_vals.len * 2); + for (mod.test_functions.keys()) |test_decl, i| { const test_name_slice = mem.sliceTo(test_decl.name, 0); const test_name_decl = n: { @@ -4747,6 +4751,8 @@ pub fn populateTestFunctions(mod: *Module) !void { try test_name_decl.finalizeNewArena(&name_decl_arena); break :n test_name_decl; }; + array_decl.dependencies.putAssumeCapacityNoClobber(test_decl, {}); + array_decl.dependencies.putAssumeCapacityNoClobber(test_name_decl, {}); try mod.linkerUpdateDecl(test_name_decl); const field_vals = try arena.create([3]Value); diff --git a/src/codegen/c.zig b/src/codegen/c.zig index dd71590566..139809aac2 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -397,8 +397,9 @@ pub const DeclGen = struct { .Struct => { const field_vals = val.castTag(.@"struct").?.data; + try writer.writeAll("("); try dg.renderType(writer, ty); - try writer.writeAll("{"); + try writer.writeAll("){"); for (field_vals) |field_val, i| { const field_ty = ty.structFieldType(i); @@ -529,9 +530,9 @@ pub const DeclGen = struct { const elem_type = t.elemType(); try dg.renderType(bw, elem_type); try bw.writeAll(" *"); - if (t.isConstPtr()) { - try bw.writeAll("const "); - } + // We skip the const qualifier because C's type system + // would not allow a local mutable variable which is this slice type + // to be overwritten with a new slice type. if (t.isVolatilePtr()) { try bw.writeAll("volatile "); } @@ -549,15 +550,40 @@ pub const DeclGen = struct { try t.copy(dg.typedefs_arena), .{ .name = name, .rendered = rendered }, ); - } else { - try dg.renderType(w, t.elemType()); - try w.writeAll(" *"); - if (t.isConstPtr()) { - try w.writeAll("const "); + return; + } + if (t.castPtrToFn()) |fn_ty| { + const fn_info = fn_ty.fnInfo(); + try dg.renderType(w, fn_info.return_type); + try w.writeAll(" (*)("); + const param_len = fn_info.param_types.len; + const is_var_args = fn_info.is_var_args; + if (param_len == 0 and !is_var_args) + try w.writeAll("void") + else { + var index: usize = 0; + while (index < param_len) : (index += 1) { + if (index > 0) { + try w.writeAll(", "); + } + try dg.renderType(w, fn_info.param_types[index]); + } } - if (t.isVolatilePtr()) { - try w.writeAll("volatile "); + if (is_var_args) { + if (param_len != 0) try w.writeAll(", "); + try w.writeAll("..."); } + try w.writeByte(')'); + return; + } + + try dg.renderType(w, t.elemType()); + try w.writeAll(" *"); + if (t.isConstPtr()) { + try w.writeAll("const "); + } + if (t.isVolatilePtr()) { + try w.writeAll("volatile "); } }, .Array => { @@ -685,28 +711,7 @@ pub const DeclGen = struct { try dg.renderType(w, int_tag_ty); }, .Union => return dg.fail("TODO: C backend: implement type Union", .{}), - .Fn => { - try dg.renderType(w, t.fnReturnType()); - try w.writeAll(" (*)("); - const param_len = t.fnParamLen(); - const is_var_args = t.fnIsVarArgs(); - if (param_len == 0 and !is_var_args) - try w.writeAll("void") - else { - var index: usize = 0; - while (index < param_len) : (index += 1) { - if (index > 0) { - try w.writeAll(", "); - } - try dg.renderType(w, t.fnParamType(index)); - } - } - if (is_var_args) { - if (param_len != 0) try w.writeAll(", "); - try w.writeAll("..."); - } - try w.writeByte(')'); - }, + .Fn => unreachable, // This is a function body, not a function pointer. .Opaque => return dg.fail("TODO: C backend: implement type Opaque", .{}), .Frame => return dg.fail("TODO: C backend: implement type Frame", .{}), .AnyFrame => return dg.fail("TODO: C backend: implement type AnyFrame", .{}), @@ -742,8 +747,59 @@ pub const DeclGen = struct { render_ty = render_ty.elemType(); } - if (render_ty.zigTypeTag() == .Fn) { - const ret_ty = render_ty.fnReturnType(); + // TODO this is duplicated from the code below and does not handle + // arbitrary nesting of pointers. This renderTypeAndName function + // needs to be reworked by someone who understands C's insane type syntax. That + // person might be future me but it is certainly not present me. + if (render_ty.zigTypeTag() == .Pointer and + render_ty.childType().zigTypeTag() == .Pointer and + render_ty.childType().childType().zigTypeTag() == .Fn) + { + const ptr2_ty = render_ty.childType(); + const fn_info = ptr2_ty.childType().fnInfo(); + const ret_ty = fn_info.return_type; + if (ret_ty.zigTypeTag() == .NoReturn) { + // noreturn attribute is not allowed here. + try w.writeAll("void"); + } else { + try dg.renderType(w, ret_ty); + } + try w.writeAll(" (*"); + switch (mutability) { + .Const => try w.writeAll("const "), + .Mut => {}, + } + if (!ptr2_ty.ptrIsMutable()) { + try w.writeAll("*const "); + } else { + try w.writeAll("*"); + } + try dg.writeCValue(w, name); + try w.writeAll(")("); + const param_len = fn_info.param_types.len; + const is_var_args = fn_info.is_var_args; + if (param_len == 0 and !is_var_args) + try w.writeAll("void") + else { + var index: usize = 0; + while (index < param_len) : (index += 1) { + if (index > 0) { + try w.writeAll(", "); + } + try dg.renderType(w, fn_info.param_types[index]); + } + } + if (is_var_args) { + if (param_len != 0) try w.writeAll(", "); + try w.writeAll("..."); + } + try w.writeByte(')'); + return; + } + + if (render_ty.castPtrToFn()) |fn_ty| { + const fn_info = fn_ty.fnInfo(); + const ret_ty = fn_info.return_type; if (ret_ty.zigTypeTag() == .NoReturn) { // noreturn attribute is not allowed here. try w.writeAll("void"); @@ -757,8 +813,8 @@ pub const DeclGen = struct { } try dg.writeCValue(w, name); try w.writeAll(")("); - const param_len = render_ty.fnParamLen(); - const is_var_args = render_ty.fnIsVarArgs(); + const param_len = fn_info.param_types.len; + const is_var_args = fn_info.is_var_args; if (param_len == 0 and !is_var_args) try w.writeAll("void") else { @@ -767,7 +823,7 @@ pub const DeclGen = struct { if (index > 0) { try w.writeAll(", "); } - try dg.renderType(w, render_ty.fnParamType(index)); + try dg.renderType(w, fn_info.param_types[index]); } } if (is_var_args) { @@ -1083,7 +1139,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO .ptr_elem_val => try airPtrElemVal(f, inst, "["), .ptr_elem_ptr => try airPtrElemPtr(f, inst), - .slice_elem_val => try airSliceElemVal(f, inst, "["), + .slice_elem_val => try airSliceElemVal(f, inst), .slice_elem_ptr => try airSliceElemPtr(f, inst), .array_elem_val => try airArrayElemVal(f, inst), @@ -1149,27 +1205,26 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { return f.fail("TODO: C backend: airPtrElemPtr", .{}); } -fn airSliceElemVal(f: *Function, inst: Air.Inst.Index, prefix: []const u8) !CValue { - const is_volatile = false; // TODO - if (!is_volatile and f.liveness.isUnused(inst)) - return CValue.none; - +fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue { const bin_op = f.air.instructions.items(.data)[inst].bin_op; + const slice_ty = f.air.typeOf(bin_op.lhs); + if (!slice_ty.isVolatilePtr() and f.liveness.isUnused(inst)) return CValue.none; + const slice = try f.resolveInst(bin_op.lhs); const index = try f.resolveInst(bin_op.rhs); const writer = f.object.writer(); const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); try writer.writeAll(" = "); try f.writeCValue(writer, slice); - try writer.writeAll(prefix); + try writer.writeAll(".ptr["); try f.writeCValue(writer, index); try writer.writeAll("];\n"); return local; } fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { - if (f.liveness.isUnused(inst)) - return CValue.none; + if (f.liveness.isUnused(inst)) return CValue.none; + const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data; @@ -1179,7 +1234,7 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); try writer.writeAll(" = &"); try f.writeCValue(writer, slice); - try writer.writeByte('['); + try writer.writeAll(".ptr["); try f.writeCValue(writer, index); try writer.writeAll("];\n"); return local; diff --git a/src/type.zig b/src/type.zig index e1a407011b..a43c80cb2e 100644 --- a/src/type.zig +++ b/src/type.zig @@ -252,6 +252,14 @@ pub const Type = extern union { }; } + /// If it is a function pointer, returns the function type. Otherwise returns null. + pub fn castPtrToFn(ty: Type) ?Type { + if (ty.zigTypeTag() != .Pointer) return null; + const elem_ty = ty.childType(); + if (elem_ty.zigTypeTag() != .Fn) return null; + return elem_ty; + } + pub fn ptrIsMutable(ty: Type) bool { return switch (ty.tag()) { .single_const_pointer_to_comptime_int,