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 {...@@ -1309,6 +1309,33 @@ pub const DeclGen = struct {
1309 return name;1309 return name;
1310 }1310 }
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
1312 /// Renders a type as a single identifier, generating intermediate typedefs1339 /// Renders a type as a single identifier, generating intermediate typedefs
1313 /// if necessary.1340 /// if necessary.
1314 ///1341 ///
...@@ -1387,7 +1414,16 @@ pub const DeclGen = struct {...@@ -1387,7 +1414,16 @@ pub const DeclGen = struct {
1387 return w.writeAll(name);1414 return w.writeAll(name);
1388 }1415 }
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 }
1391 if (t.isConstPtr()) {1427 if (t.isConstPtr()) {
1392 try w.writeAll(" const");1428 try w.writeAll(" const");
1393 }1429 }
...@@ -1456,7 +1492,16 @@ pub const DeclGen = struct {...@@ -1456,7 +1492,16 @@ pub const DeclGen = struct {
14561492
1457 try dg.renderType(w, int_tag_ty);1493 try dg.renderType(w, int_tag_ty);
1458 },1494 },
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
1461 .Frame,1506 .Frame,
1462 .AnyFrame,1507 .AnyFrame,
...@@ -2830,12 +2875,16 @@ fn airCall(...@@ -2830,12 +2875,16 @@ fn airCall(
2830 }2875 }
2831 };2876 };
28322877
2878 var is_extern = false;
2833 callee: {2879 callee: {
2834 known: {2880 known: {
2835 const fn_decl = fn_decl: {2881 const fn_decl = fn_decl: {
2836 const callee_val = f.air.value(pl_op.operand) orelse break :known;2882 const callee_val = f.air.value(pl_op.operand) orelse break :known;
2837 break :fn_decl switch (callee_val.tag()) {2883 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 },
2839 .function => callee_val.castTag(.function).?.data.owner_decl,2888 .function => callee_val.castTag(.function).?.data.owner_decl,
2840 .decl_ref => callee_val.castTag(.decl_ref).?.data,2889 .decl_ref => callee_val.castTag(.decl_ref).?.data,
2841 else => break :known,2890 else => break :known,
...@@ -2857,6 +2906,13 @@ fn airCall(...@@ -2857,6 +2906,13 @@ fn airCall(
2857 if (args_written != 0) {2906 if (args_written != 0) {
2858 try writer.writeAll(", ");2907 try writer.writeAll(", ");
2859 }2908 }
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 }
2860 if (f.air.value(arg)) |val| {2916 if (f.air.value(arg)) |val| {
2861 try f.object.dg.renderValue(writer, f.air.typeOf(arg), val, .FunctionArgument);2917 try f.object.dg.renderValue(writer, f.air.typeOf(arg), val, .FunctionArgument);
2862 } else {2918 } else {
test/behavior/bugs/4328.zig+8-8
...@@ -5,10 +5,10 @@ const FILE = extern struct {...@@ -5,10 +5,10 @@ const FILE = extern struct {
5 dummy_field: u8,5 dummy_field: u8,
6};6};
77
8extern fn printf([*c]const u8, ...) c_int;8extern fn c_printf([*c]const u8, ...) c_int;
9extern fn fputs([*c]const u8, noalias [*c]FILE) c_int;9extern fn c_fputs([*c]const u8, noalias [*c]FILE) c_int;
10extern fn ftell([*c]FILE) c_long;10extern fn c_ftell([*c]FILE) c_long;
11extern fn fopen([*c]const u8, [*c]const u8) [*c]FILE;11extern fn c_fopen([*c]const u8, [*c]const u8) [*c]FILE;
1212
13const S = extern struct {13const S = extern struct {
14 state: c_short,14 state: c_short,
...@@ -18,7 +18,7 @@ const S = extern struct {...@@ -18,7 +18,7 @@ const S = extern struct {
1818
19test "Extern function calls in @TypeOf" {19test "Extern function calls in @TypeOf" {
20 const Test = struct {20 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)) {
22 return 0;22 return 0;
23 }23 }
2424
...@@ -38,7 +38,7 @@ test "Extern function calls in @TypeOf" {...@@ -38,7 +38,7 @@ test "Extern function calls in @TypeOf" {
3838
39test "Peer resolution of extern function calls in @TypeOf" {39test "Peer resolution of extern function calls in @TypeOf" {
40 const Test = struct {40 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)) {
42 return 0;42 return 0;
43 }43 }
4444
...@@ -55,12 +55,12 @@ test "Extern function calls, dereferences and field access in @TypeOf" {...@@ -55,12 +55,12 @@ test "Extern function calls, dereferences and field access in @TypeOf" {
55 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;55 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5656
57 const Test = struct {57 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").*) {
59 _ = a;59 _ = a;
60 return .{ .dummy_field = 0 };60 return .{ .dummy_field = 0 };
61 }61 }
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) {
64 _ = a;64 _ = a;
65 return 255;65 return 255;
66 }66 }