Commit f81651932a
src/codegen/c.zig
@@ -1309,6 +1309,33 @@ pub const DeclGen = struct {
return name;
}
+ fn renderOpaqueTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
+ const opaque_ty = t.cast(Type.Payload.Opaque).?.data;
+ const unqualified_name = dg.module.declPtr(opaque_ty.owner_decl).name;
+ const fqn = try opaque_ty.getFullyQualifiedName(dg.module);
+ defer dg.typedefs.allocator.free(fqn);
+
+ var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
+ defer buffer.deinit();
+
+ try buffer.writer().print("typedef struct {} ", .{fmtIdent(std.mem.span(unqualified_name))});
+
+ const name_start = buffer.items.len;
+ try buffer.writer().print("zig_O_{};\n", .{fmtIdent(fqn)});
+
+ const rendered = buffer.toOwnedSlice();
+ errdefer dg.typedefs.allocator.free(rendered);
+ const name = rendered[name_start .. rendered.len - 2];
+
+ try dg.typedefs.ensureUnusedCapacity(1);
+ dg.typedefs.putAssumeCapacityNoClobber(
+ try t.copy(dg.typedefs_arena),
+ .{ .name = name, .rendered = rendered },
+ );
+
+ return name;
+ }
+
/// Renders a type as a single identifier, generating intermediate typedefs
/// if necessary.
///
@@ -1387,7 +1414,16 @@ pub const DeclGen = struct {
return w.writeAll(name);
}
- try dg.renderType(w, t.elemType());
+ const child_ty = t.childType();
+ if (t.isCPtr() and child_ty.eql(Type.u8, dg.module) and dg.decl.val.tag() == .extern_fn) {
+ // This is a hack, since the c compiler expects a lot of external
+ // library functions to have char pointers in their signatures, but
+ // u8 and i8 produce unsigned char and signed char respectively,
+ // which in C are not very usefully different than char.
+ try w.writeAll("char");
+ } else {
+ try dg.renderType(w, child_ty);
+ }
if (t.isConstPtr()) {
try w.writeAll(" const");
}
@@ -1456,7 +1492,16 @@ pub const DeclGen = struct {
try dg.renderType(w, int_tag_ty);
},
- .Opaque => return w.writeAll("void"),
+ .Opaque => switch (t.tag()) {
+ .anyopaque => try w.writeAll("void"),
+ .@"opaque" => {
+ const name = dg.getTypedefName(t) orelse
+ try dg.renderOpaqueTypedef(t);
+
+ try w.writeAll(name);
+ },
+ else => unreachable,
+ },
.Frame,
.AnyFrame,
@@ -2830,12 +2875,16 @@ fn airCall(
}
};
+ var is_extern = false;
callee: {
known: {
const fn_decl = fn_decl: {
const callee_val = f.air.value(pl_op.operand) orelse break :known;
break :fn_decl switch (callee_val.tag()) {
- .extern_fn => callee_val.castTag(.extern_fn).?.data.owner_decl,
+ .extern_fn => blk: {
+ is_extern = true;
+ break :blk callee_val.castTag(.extern_fn).?.data.owner_decl;
+ },
.function => callee_val.castTag(.function).?.data.owner_decl,
.decl_ref => callee_val.castTag(.decl_ref).?.data,
else => break :known,
@@ -2857,6 +2906,13 @@ fn airCall(
if (args_written != 0) {
try writer.writeAll(", ");
}
+ if (is_extern and ty.isCPtr() and ty.childType().tag() == .u8) {
+ // Corresponds with hack in renderType .Pointer case.
+ try writer.writeAll("(char");
+ if (ty.isConstPtr()) try writer.writeAll(" const");
+ if (ty.isVolatilePtr()) try writer.writeAll(" volatile");
+ try writer.writeAll(" *)");
+ }
if (f.air.value(arg)) |val| {
try f.object.dg.renderValue(writer, f.air.typeOf(arg), val, .FunctionArgument);
} else {
test/behavior/bugs/4328.zig
@@ -5,10 +5,10 @@ const FILE = extern struct {
dummy_field: u8,
};
-extern fn printf([*c]const u8, ...) c_int;
-extern fn fputs([*c]const u8, noalias [*c]FILE) c_int;
-extern fn ftell([*c]FILE) c_long;
-extern fn fopen([*c]const u8, [*c]const u8) [*c]FILE;
+extern fn c_printf([*c]const u8, ...) c_int;
+extern fn c_fputs([*c]const u8, noalias [*c]FILE) c_int;
+extern fn c_ftell([*c]FILE) c_long;
+extern fn c_fopen([*c]const u8, [*c]const u8) [*c]FILE;
const S = extern struct {
state: c_short,
@@ -18,7 +18,7 @@ const S = extern struct {
test "Extern function calls in @TypeOf" {
const Test = struct {
- fn test_fn_1(a: anytype, b: anytype) @TypeOf(printf("%d %s\n", a, b)) {
+ fn test_fn_1(a: anytype, b: anytype) @TypeOf(c_printf("%d %s\n", a, b)) {
return 0;
}
@@ -38,7 +38,7 @@ test "Extern function calls in @TypeOf" {
test "Peer resolution of extern function calls in @TypeOf" {
const Test = struct {
- fn test_fn() @TypeOf(ftell(null), fputs(null, null)) {
+ fn test_fn() @TypeOf(c_ftell(null), c_fputs(null, null)) {
return 0;
}
@@ -55,12 +55,12 @@ test "Extern function calls, dereferences and field access in @TypeOf" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
const Test = struct {
- fn test_fn_1(a: c_long) @TypeOf(fopen("test", "r").*) {
+ fn test_fn_1(a: c_long) @TypeOf(c_fopen("test", "r").*) {
_ = a;
return .{ .dummy_field = 0 };
}
- fn test_fn_2(a: anytype) @TypeOf(fopen("test", "r").*.dummy_field) {
+ fn test_fn_2(a: anytype) @TypeOf(c_fopen("test", "r").*.dummy_field) {
_ = a;
return 255;
}