authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2022-10-06 03:59:07-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2022-10-25 05:11:28-04:00
logf81651932af18938fc88dc536806f3adbe5c11c4
tree789db8b86b9c94f7615ad017f515192eb1b4e827
parentf8a8197caae9306b3f69a7af3445c76eea172f0f

c: hacks to fix incompatible redeclaration of library function warnings


2 files changed, 67 insertions(+), 11 deletions(-)

src/codegen/c.zig+59-3
......@@ -1309,6 +1309,33 @@ pub const DeclGen = struct {
13091309 return name;
13101310 }
13111311
1312 fn renderOpaqueTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1313 const opaque_ty = t.cast(Type.Payload.Opaque).?.data;
1314 const unqualified_name = dg.module.declPtr(opaque_ty.owner_decl).name;
1315 const fqn = try opaque_ty.getFullyQualifiedName(dg.module);
1316 defer dg.typedefs.allocator.free(fqn);
1317
1318 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1319 defer buffer.deinit();
1320
1321 try buffer.writer().print("typedef struct {} ", .{fmtIdent(std.mem.span(unqualified_name))});
1322
1323 const name_start = buffer.items.len;
1324 try buffer.writer().print("zig_O_{};\n", .{fmtIdent(fqn)});
1325
1326 const rendered = buffer.toOwnedSlice();
1327 errdefer dg.typedefs.allocator.free(rendered);
1328 const name = rendered[name_start .. rendered.len - 2];
1329
1330 try dg.typedefs.ensureUnusedCapacity(1);
1331 dg.typedefs.putAssumeCapacityNoClobber(
1332 try t.copy(dg.typedefs_arena),
1333 .{ .name = name, .rendered = rendered },
1334 );
1335
1336 return name;
1337 }
1338
13121339 /// Renders a type as a single identifier, generating intermediate typedefs
13131340 /// if necessary.
13141341 ///
......@@ -1387,7 +1414,16 @@ pub const DeclGen = struct {
13871414 return w.writeAll(name);
13881415 }
13891416
1390 try dg.renderType(w, t.elemType());
1417 const child_ty = t.childType();
1418 if (t.isCPtr() and child_ty.eql(Type.u8, dg.module) and dg.decl.val.tag() == .extern_fn) {
1419 // This is a hack, since the c compiler expects a lot of external
1420 // library functions to have char pointers in their signatures, but
1421 // u8 and i8 produce unsigned char and signed char respectively,
1422 // which in C are not very usefully different than char.
1423 try w.writeAll("char");
1424 } else {
1425 try dg.renderType(w, child_ty);
1426 }
13911427 if (t.isConstPtr()) {
13921428 try w.writeAll(" const");
13931429 }
......@@ -1456,7 +1492,16 @@ pub const DeclGen = struct {
14561492
14571493 try dg.renderType(w, int_tag_ty);
14581494 },
1459 .Opaque => return w.writeAll("void"),
1495 .Opaque => switch (t.tag()) {
1496 .anyopaque => try w.writeAll("void"),
1497 .@"opaque" => {
1498 const name = dg.getTypedefName(t) orelse
1499 try dg.renderOpaqueTypedef(t);
1500
1501 try w.writeAll(name);
1502 },
1503 else => unreachable,
1504 },
14601505
14611506 .Frame,
14621507 .AnyFrame,
......@@ -2830,12 +2875,16 @@ fn airCall(
28302875 }
28312876 };
28322877
2878 var is_extern = false;
28332879 callee: {
28342880 known: {
28352881 const fn_decl = fn_decl: {
28362882 const callee_val = f.air.value(pl_op.operand) orelse break :known;
28372883 break :fn_decl switch (callee_val.tag()) {
2838 .extern_fn => callee_val.castTag(.extern_fn).?.data.owner_decl,
2884 .extern_fn => blk: {
2885 is_extern = true;
2886 break :blk callee_val.castTag(.extern_fn).?.data.owner_decl;
2887 },
28392888 .function => callee_val.castTag(.function).?.data.owner_decl,
28402889 .decl_ref => callee_val.castTag(.decl_ref).?.data,
28412890 else => break :known,
......@@ -2857,6 +2906,13 @@ fn airCall(
28572906 if (args_written != 0) {
28582907 try writer.writeAll(", ");
28592908 }
2909 if (is_extern and ty.isCPtr() and ty.childType().tag() == .u8) {
2910 // Corresponds with hack in renderType .Pointer case.
2911 try writer.writeAll("(char");
2912 if (ty.isConstPtr()) try writer.writeAll(" const");
2913 if (ty.isVolatilePtr()) try writer.writeAll(" volatile");
2914 try writer.writeAll(" *)");
2915 }
28602916 if (f.air.value(arg)) |val| {
28612917 try f.object.dg.renderValue(writer, f.air.typeOf(arg), val, .FunctionArgument);
28622918 } else {
test/behavior/bugs/4328.zig+8-8
......@@ -5,10 +5,10 @@ const FILE = extern struct {
55 dummy_field: u8,
66};
77
8extern fn printf([*c]const u8, ...) c_int;
9extern fn fputs([*c]const u8, noalias [*c]FILE) c_int;
10extern fn ftell([*c]FILE) c_long;
11extern fn fopen([*c]const u8, [*c]const u8) [*c]FILE;
8extern fn c_printf([*c]const u8, ...) c_int;
9extern fn c_fputs([*c]const u8, noalias [*c]FILE) c_int;
10extern fn c_ftell([*c]FILE) c_long;
11extern fn c_fopen([*c]const u8, [*c]const u8) [*c]FILE;
1212
1313const S = extern struct {
1414 state: c_short,
......@@ -18,7 +18,7 @@ const S = extern struct {
1818
1919test "Extern function calls in @TypeOf" {
2020 const Test = struct {
21 fn test_fn_1(a: anytype, b: anytype) @TypeOf(printf("%d %s\n", a, b)) {
21 fn test_fn_1(a: anytype, b: anytype) @TypeOf(c_printf("%d %s\n", a, b)) {
2222 return 0;
2323 }
2424
......@@ -38,7 +38,7 @@ test "Extern function calls in @TypeOf" {
3838
3939test "Peer resolution of extern function calls in @TypeOf" {
4040 const Test = struct {
41 fn test_fn() @TypeOf(ftell(null), fputs(null, null)) {
41 fn test_fn() @TypeOf(c_ftell(null), c_fputs(null, null)) {
4242 return 0;
4343 }
4444
......@@ -55,12 +55,12 @@ test "Extern function calls, dereferences and field access in @TypeOf" {
5555 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5656
5757 const Test = struct {
58 fn test_fn_1(a: c_long) @TypeOf(fopen("test", "r").*) {
58 fn test_fn_1(a: c_long) @TypeOf(c_fopen("test", "r").*) {
5959 _ = a;
6060 return .{ .dummy_field = 0 };
6161 }
6262
63 fn test_fn_2(a: anytype) @TypeOf(fopen("test", "r").*.dummy_field) {
63 fn test_fn_2(a: anytype) @TypeOf(c_fopen("test", "r").*.dummy_field) {
6464 _ = a;
6565 return 255;
6666 }