diff options
Diffstat (limited to 'src/codegen')
| -rw-r--r-- | src/codegen/c.zig | 84 |
1 files changed, 60 insertions, 24 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig index a16096fa18..440d838f91 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -528,6 +528,9 @@ pub const DeclGen = struct { fwd_decl: std.ArrayList(u8), error_msg: ?*Module.ErrorMsg, ctypes: CType.Store, + /// Keeps track of anonymous decls that need to be rendered before this + /// (named) Decl in the output C code. + anon_decl_deps: std.AutoArrayHashMapUnmanaged(InternPool.Index, void), fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } { @setCold(true); @@ -540,6 +543,57 @@ pub const DeclGen = struct { return error.AnalysisFail; } + fn renderAnonDeclValue( + dg: *DeclGen, + writer: anytype, + ty: Type, + ptr_val: Value, + decl_val: InternPool.Index, + location: ValueRenderLocation, + ) error{ OutOfMemory, AnalysisFail }!void { + const mod = dg.module; + const ip = &mod.intern_pool; + const decl_ty = ip.typeOf(decl_val).toType(); + + // Render an undefined pointer if we have a pointer to a zero-bit or comptime type. + if (ty.isPtrAtRuntime(mod) and !decl_ty.isFnOrHasRuntimeBits(mod)) { + return dg.writeCValue(writer, .{ .undef = ty }); + } + + // Chase function values in order to be able to reference the original function. + if (decl_val.toValue().getFunction(mod)) |func| { + _ = func; + _ = ptr_val; + _ = location; + @panic("TODO"); + } + if (decl_val.toValue().getExternFunc(mod)) |extern_func| { + _ = extern_func; + _ = ptr_val; + _ = location; + @panic("TODO"); + } + + assert(decl_val.toValue().getVariable(mod) == null); + + // We shouldn't cast C function pointers as this is UB (when you call + // them). The analysis until now should ensure that the C function + // pointers are compatible. If they are not, then there is a bug + // somewhere and we should let the C compiler tell us about it. + const need_typecast = if (ty.castPtrToFn(mod)) |_| false else !ty.childType(mod).eql(decl_ty, mod); + if (need_typecast) { + try writer.writeAll("(("); + try dg.renderType(writer, ty); + try writer.writeByte(')'); + } + try writer.print("&__anon_{d}", .{@intFromEnum(decl_val)}); + if (need_typecast) try writer.writeByte(')'); + + // Indicate that the anon decl should be rendered to the output so that + // our reference above is not undefined. + try dg.anon_decl_deps.put(dg.gpa, decl_val, {}); + } + fn renderDeclValue( dg: *DeclGen, writer: anytype, @@ -593,18 +647,9 @@ pub const DeclGen = struct { const ptr_cty = try dg.typeToIndex(ptr_ty, .complete); const ptr = mod.intern_pool.indexToKey(ptr_val).ptr; switch (ptr.addr) { - .decl, .mut_decl => try dg.renderDeclValue( - writer, - ptr_ty, - ptr_val.toValue(), - switch (ptr.addr) { - .decl => |decl| decl, - .mut_decl => |mut_decl| mut_decl.decl, - else => unreachable, - }, - location, - ), - .anon_decl => @panic("TODO"), + .decl => |d| try dg.renderDeclValue(writer, ptr_ty, ptr_val.toValue(), d, location), + .mut_decl => |md| try dg.renderDeclValue(writer, ptr_ty, ptr_val.toValue(), md.decl, location), + .anon_decl => |decl_val| try dg.renderAnonDeclValue(writer, ptr_ty, ptr_val.toValue(), decl_val, location), .int => |int| { try writer.writeByte('('); try dg.renderCType(writer, ptr_cty); @@ -1145,18 +1190,9 @@ pub const DeclGen = struct { else => val.slicePtr(mod), }; switch (ptr.addr) { - .decl, .mut_decl => try dg.renderDeclValue( - writer, - ptr_ty, - ptr_val, - switch (ptr.addr) { - .decl => |decl| decl, - .mut_decl => |mut_decl| mut_decl.decl, - else => unreachable, - }, - ptr_location, - ), - .anon_decl => @panic("TODO"), + .decl => |d| try dg.renderDeclValue(writer, ptr_ty, ptr_val, d, ptr_location), + .mut_decl => |md| try dg.renderDeclValue(writer, ptr_ty, ptr_val, md.decl, ptr_location), + .anon_decl => |decl_val| try dg.renderAnonDeclValue(writer, ptr_ty, ptr_val, decl_val, ptr_location), .int => |int| { try writer.writeAll("(("); try dg.renderType(writer, ptr_ty); |
