aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/c.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2023-09-27 21:47:35 -0700
committerAndrew Kelley <andrew@ziglang.org>2023-10-03 12:12:51 -0700
commit9d069d98e3e3773d76bfa4fb07cf4bcbf06e2b67 (patch)
tree7c5fb8542a016e8a5b8054986d005b324d5f11bc /src/codegen/c.zig
parentc0b55125443cab63945205b2f7c66bf12cae71e1 (diff)
downloadzig-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.zig84
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);