Commit a38704d012

LemonBoy <thatlemon@gmail.com>
2019-12-28 00:50:17
Fix crash in translate-c w/ parameterless fn
1 parent 25e7121
Changed files (2)
src-self-hosted
test
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);
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));