diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2023-09-27 21:47:35 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2023-10-03 12:12:51 -0700 |
| commit | 9d069d98e3e3773d76bfa4fb07cf4bcbf06e2b67 (patch) | |
| tree | 7c5fb8542a016e8a5b8054986d005b324d5f11bc /src/codegen/c.zig | |
| parent | c0b55125443cab63945205b2f7c66bf12cae71e1 (diff) | |
| download | zig-9d069d98e3e3773d76bfa4fb07cf4bcbf06e2b67.tar.gz zig-9d069d98e3e3773d76bfa4fb07cf4bcbf06e2b67.zip | |
C backend: start handling anonymous decls
Start keeping track of dependencies on anon decls for dependency
ordering during flush()
Currently this causes use of undefined symbols because these
dependencies need to get rendered into the output.
Diffstat (limited to 'src/codegen/c.zig')
| -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); |
