| ... | @@ -1309,6 +1309,33 @@ pub const DeclGen = struct { | ... | @@ -1309,6 +1309,33 @@ pub const DeclGen = struct { |
| 1309 | return name; | 1309 | return name; |
| 1310 | } | 1310 | } |
| 1311 | | 1311 | |
| | 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 typedefs | 1339 | /// 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 | } |
| 1389 | | 1416 | |
| 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 { |
| 1456 | | 1492 | |
| 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 | }, |
| 1460 | | 1505 | |
| 1461 | .Frame, | 1506 | .Frame, |
| 1462 | .AnyFrame, | 1507 | .AnyFrame, |
| ... | @@ -2830,12 +2875,16 @@ fn airCall( | ... | @@ -2830,12 +2875,16 @@ fn airCall( |
| 2830 | } | 2875 | } |
| 2831 | }; | 2876 | }; |
| 2832 | | 2877 | |
| | 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 { |