c: hacks to fix incompatible redeclaration of library function warnings

This commit is contained in:
Jacob Young 2022-10-06 03:59:07 -04:00
parent f8a8197caa
commit f81651932a
2 changed files with 67 additions and 11 deletions

View File

@ -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 {

View File

@ -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;
}