From a38704d0122d5dd91011541d187d1fc115265a7c Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 28 Dec 2019 00:50:17 +0100 Subject: [PATCH 1/2] Fix crash in translate-c w/ parameterless fn --- src-self-hosted/translate_c.zig | 33 ++++++++++++++++++++++++++++----- test/translate_c.zig | 12 ++++++++++-- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 478232b20a2b9f63cf242332b4c72e4690b41016..d5de3cdb935e8711f87716aedfbc4aafe5241edd 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -2145,7 +2145,7 @@ fn transCallExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCallExpr, node.rtoken = try appendToken(rp.c, .RParen, ")"); if (fn_ty) |ty| { - const canon = ZigClangQualType_getCanonicalType(ZigClangFunctionProtoType_getReturnType(ty)); + const canon = ZigClangQualType_getCanonicalType(ty.getReturnType()); const ret_ty = ZigClangQualType_getTypePtr(canon); if (ZigClangType_isVoidType(ret_ty)) { _ = try appendToken(rp.c, .Semicolon, ";"); @@ -2156,7 +2156,19 @@ fn transCallExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCallExpr, return maybeSuppressResult(rp, scope, result_used, &node.base); } -fn qualTypeGetFnProto(qt: ZigClangQualType, is_ptr: *bool) ?*const ZigClangFunctionProtoType { +const ClangFunctionType = union(enum) { + Proto: *const ZigClangFunctionProtoType, + NoProto: *const ZigClangFunctionType, + + fn getReturnType(self: @This()) ZigClangQualType { + switch (@as(@TagType(@This()), self)) { + .Proto => return ZigClangFunctionProtoType_getReturnType(self.Proto), + .NoProto => return ZigClangFunctionType_getReturnType(self.NoProto), + } + } +}; + +fn qualTypeGetFnProto(qt: ZigClangQualType, is_ptr: *bool) ?ClangFunctionType { const canon = ZigClangQualType_getCanonicalType(qt); var ty = ZigClangQualType_getTypePtr(canon); is_ptr.* = false; @@ -2167,7 +2179,10 @@ fn qualTypeGetFnProto(qt: ZigClangQualType, is_ptr: *bool) ?*const ZigClangFunct ty = ZigClangQualType_getTypePtr(child_qt); } if (ZigClangType_getTypeClass(ty) == .FunctionProto) { - return @ptrCast(*const ZigClangFunctionProtoType, ty); + return ClangFunctionType{ .Proto = @ptrCast(*const ZigClangFunctionProtoType, ty) }; + } + if (ZigClangType_getTypeClass(ty) == .FunctionNoProto) { + return ClangFunctionType{ .NoProto = @ptrCast(*const ZigClangFunctionType, ty) }; } return null; } @@ -2771,7 +2786,10 @@ fn qualTypeChildIsFnProto(qt: ZigClangQualType) bool { .Paren => { const paren_type = @ptrCast(*const ZigClangParenType, ty); const inner_type = ZigClangParenType_getInnerType(paren_type); - return ZigClangQualType_getTypeClass(inner_type) == .FunctionProto; + switch (ZigClangQualType_getTypeClass(inner_type)) { + .FunctionProto, .FunctionNoProto => return true, + else => return false, + } }, .Attributed => { const attr_type = @ptrCast(*const ZigClangAttributedType, ty); @@ -3571,11 +3589,16 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}), }); }, - .FunctionProto, .FunctionNoProto => { + .FunctionProto => { const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty); const fn_proto = try transFnProto(rp, null, fn_proto_ty, source_loc, null, false); return &fn_proto.base; }, + .FunctionNoProto => { + const fn_no_proto_ty = @ptrCast(*const ZigClangFunctionType, ty); + const fn_proto = try transFnNoProto(rp, fn_no_proto_ty, source_loc, null, false); + return &fn_proto.base; + }, .Paren => { const paren_ty = @ptrCast(*const ZigClangParenType, ty); return transQualType(rp, ZigClangParenType_getInnerType(paren_ty), source_loc); diff --git a/test/translate_c.zig b/test/translate_c.zig index 917bd98d09c02daee88ee8081cfa5721c1a4f364..304c290be903eb3653a76711f93cdee822532e17 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -814,6 +814,14 @@ pub fn addCases(cases: *tests.TranslateCContext) void { /////////////// Cases that pass for only stage2 //////////////// + cases.add_2("Parameterless function pointers", + \\typedef void (*fn0)(); + \\typedef void (*fn1)(char); + , &[_][]const u8{ + \\pub const fn0 = ?extern fn (...) void; + \\pub const fn1 = ?extern fn (u8) void; + }); + cases.add_2("Parameterless function prototypes", \\void a() {} \\void b(void) {} @@ -1024,7 +1032,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub inline fn glClearUnion(arg_2: GLbitfield) void { \\ return glProcs.gl.Clear.?(arg_2); \\} - , + , \\pub const OpenGLProcs = union_OpenGLProcs; }); @@ -2166,7 +2174,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { }); cases.add_2("macro cast", - \\#define FOO(bar) baz((void *)(baz)) + \\#define FOO(bar) baz((void *)(baz)) , &[_][]const u8{ \\pub inline fn FOO(bar: var) @TypeOf(baz(if (@typeId(@TypeOf(baz)) == .Pointer) @ptrCast([*c]void, baz) else if (@typeId(@TypeOf(baz)) == .Int) @intToPtr([*c]void, baz) else @as([*c]void, baz))) { \\ return baz(if (@typeId(@TypeOf(baz)) == .Pointer) @ptrCast([*c]void, baz) else if (@typeId(@TypeOf(baz)) == .Int) @intToPtr([*c]void, baz) else @as([*c]void, baz)); -- 2.54.0 From 6070ffc28ea8aa64894d62df699fa6def6fc6d8a Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 28 Dec 2019 00:57:37 +0100 Subject: [PATCH 2/2] Fix crash with forward-declared enums Closes #3754 --- src-self-hosted/translate_c.zig | 9 ++++++--- test/translate_c.zig | 11 +++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index d5de3cdb935e8711f87716aedfbc4aafe5241edd..e1d6c9a81433cbf5d46ea669da3741fe506aadfe 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -725,11 +725,15 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No }; const int_type = ZigClangEnumDecl_getIntegerType(enum_decl); + // The underlying type may be null in case of forward-declared enum + // types, while that's not ISO-C compliant many compilers allow this and + // default to the usual integer type used for all the enums. // TODO only emit this tag type if the enum tag type is not the default. // I don't know what the default is, need to figure out how clang is deciding. // it appears to at least be different across gcc/msvc - if (!isCBuiltinType(int_type, .UInt) and + if (int_type.ptr != null and + !isCBuiltinType(int_type, .UInt) and !isCBuiltinType(int_type, .Int)) { _ = try appendToken(c, .LParen, "("); @@ -1555,8 +1559,7 @@ fn transCCast( const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ZigClangQualType_getTypePtr(dst_type)); return transCCast(rp, scope, loc, ZigClangElaboratedType_getNamedType(elaborated_ty), src_type, expr); } - if (ZigClangQualType_getTypeClass(dst_type) == .Enum) - { + if (ZigClangQualType_getTypeClass(dst_type) == .Enum) { const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToEnum"); try builtin_node.params.push(try transQualType(rp, dst_type, loc)); _ = try appendToken(rp.c, .Comma, ","); diff --git a/test/translate_c.zig b/test/translate_c.zig index 304c290be903eb3653a76711f93cdee822532e17..452898b1be6281303d516d724176d3c4a9d51323 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -814,6 +814,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void { /////////////// Cases that pass for only stage2 //////////////// + cases.add_2("Forward-declared enum", + \\extern enum enum_ty my_enum; + \\enum enum_ty { FOO }; + , &[_][]const u8{ + \\pub const FOO = 0; + \\pub const enum_enum_ty = extern enum { + \\ FOO, + \\}; + \\pub extern var my_enum: enum_enum_ty; + }); + cases.add_2("Parameterless function pointers", \\typedef void (*fn0)(); \\typedef void (*fn1)(char); -- 2.54.0