authorgravatar for jhc@dismail.deJimmi Holst Christensen <jhc@dismail.de> 2019-05-11 18:49:23+02:00
committergravatar for jhc@dismail.deJimmi Holst Christensen <jhc@dismail.de> 2019-05-11 18:49:23+02:00
logb2a196e01dce9856eb43ae92a43d1a5b260d11d4
treefe46421244952509fc93eeac237c0965ca3eddbc
parentc051904903e65f6bd2cb9d71f52688ce9d17d52d
parent10e9d47b499752f5c40e8ded1bf50385d84912ff

Merge branch 'master' of github.com:ziglang/zig


4 files changed, 142 insertions(+), 64 deletions(-)

src-self-hosted/translate_c.zig+74-38
...@@ -254,11 +254,20 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {...@@ -254,11 +254,20 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
254 const fn_qt = ZigClangFunctionDecl_getType(fn_decl);254 const fn_qt = ZigClangFunctionDecl_getType(fn_decl);
255 const fn_type = ZigClangQualType_getTypePtr(fn_qt);255 const fn_type = ZigClangQualType_getTypePtr(fn_qt);
256 var scope = &c.global_scope.base;256 var scope = &c.global_scope.base;
257 const has_body = ZigClangFunctionDecl_hasBody(fn_decl);
258 const storage_class = ZigClangFunctionDecl_getStorageClass(fn_decl);
257 const decl_ctx = FnDeclContext{259 const decl_ctx = FnDeclContext{
258 .fn_name = fn_name,260 .fn_name = fn_name,
259 .has_body = ZigClangFunctionDecl_hasBody(fn_decl),261 .has_body = has_body,
260 .storage_class = ZigClangFunctionDecl_getStorageClass(fn_decl),262 .storage_class = storage_class,
261 .scope = &scope,263 .scope = &scope,
264 .is_export = switch (storage_class) {
265 .None => has_body,
266 .Extern, .Static => false,
267 .PrivateExtern => return failDecl(c, fn_decl_loc, fn_name, "unsupported storage class: private extern"),
268 .Auto => unreachable, // Not legal on functions
269 .Register => unreachable, // Not legal on functions
270 },
262 };271 };
263 const proto_node = switch (ZigClangType_getTypeClass(fn_type)) {272 const proto_node = switch (ZigClangType_getTypeClass(fn_type)) {
264 .FunctionProto => blk: {273 .FunctionProto => blk: {
...@@ -270,7 +279,15 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {...@@ -270,7 +279,15 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
270 error.OutOfMemory => return error.OutOfMemory,279 error.OutOfMemory => return error.OutOfMemory,
271 };280 };
272 },281 },
273 .FunctionNoProto => return failDecl(c, fn_decl_loc, fn_name, "TODO support functions with no prototype"),282 .FunctionNoProto => blk: {
283 const fn_no_proto_type = @ptrCast(*const ZigClangFunctionType, fn_type);
284 break :blk transFnNoProto(rp, fn_no_proto_type, fn_decl_loc, decl_ctx) catch |err| switch (err) {
285 error.UnsupportedType => {
286 return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function");
287 },
288 error.OutOfMemory => return error.OutOfMemory,
289 };
290 },
274 else => unreachable,291 else => unreachable,
275 };292 };
276293
...@@ -432,8 +449,22 @@ const FnDeclContext = struct {...@@ -432,8 +449,22 @@ const FnDeclContext = struct {
432 has_body: bool,449 has_body: bool,
433 storage_class: ZigClangStorageClass,450 storage_class: ZigClangStorageClass,
434 scope: **Scope,451 scope: **Scope,
452 is_export: bool,
435};453};
436454
455fn transCC(
456 rp: RestorePoint,
457 fn_ty: *const ZigClangFunctionType,
458 source_loc: ZigClangSourceLocation,
459) !CallingConvention {
460 const clang_cc = ZigClangFunctionType_getCallConv(fn_ty);
461 switch (clang_cc) {
462 .C => return CallingConvention.C,
463 .X86StdCall => return CallingConvention.Stdcall,
464 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: {}", @tagName(clang_cc)),
465 }
466}
467
437fn transFnProto(468fn transFnProto(
438 rp: RestorePoint,469 rp: RestorePoint,
439 fn_proto_ty: *const ZigClangFunctionProtoType,470 fn_proto_ty: *const ZigClangFunctionProtoType,
...@@ -441,52 +472,44 @@ fn transFnProto(...@@ -441,52 +472,44 @@ fn transFnProto(
441 fn_decl_context: ?FnDeclContext,472 fn_decl_context: ?FnDeclContext,
442) !*ast.Node.FnProto {473) !*ast.Node.FnProto {
443 const fn_ty = @ptrCast(*const ZigClangFunctionType, fn_proto_ty);474 const fn_ty = @ptrCast(*const ZigClangFunctionType, fn_proto_ty);
444 const cc = switch (ZigClangFunctionType_getCallConv(fn_ty)) {475 const cc = try transCC(rp, fn_ty, source_loc);
445 .C => CallingConvention.C,
446 .X86StdCall => CallingConvention.Stdcall,
447 .X86FastCall => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: x86 fastcall"),
448 .X86ThisCall => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: x86 thiscall"),
449 .X86VectorCall => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: x86 vectorcall"),
450 .X86Pascal => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: x86 pascal"),
451 .Win64 => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: win64"),
452 .X86_64SysV => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: x86 64sysv"),
453 .X86RegCall => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: x86 reg"),
454 .AAPCS => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: aapcs"),
455 .AAPCS_VFP => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: aapcs-vfp"),
456 .IntelOclBicc => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: intel_ocl_bicc"),
457 .SpirFunction => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: SPIR function"),
458 .OpenCLKernel => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: OpenCLKernel"),
459 .Swift => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: Swift"),
460 .PreserveMost => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: PreserveMost"),
461 .PreserveAll => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: PreserveAll"),
462 .AArch64VectorCall => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: AArch64VectorCall"),
463 };
464
465 const is_var_args = ZigClangFunctionProtoType_isVariadic(fn_proto_ty);476 const is_var_args = ZigClangFunctionProtoType_isVariadic(fn_proto_ty);
466 const param_count: usize = ZigClangFunctionProtoType_getNumParams(fn_proto_ty);477 const param_count: usize = ZigClangFunctionProtoType_getNumParams(fn_proto_ty);
467 var i: usize = 0;478 var i: usize = 0;
468 while (i < param_count) : (i += 1) {479 while (i < param_count) : (i += 1) {
469 return revertAndWarn(rp, error.UnsupportedType, source_loc, "TODO: implement parameters for FunctionProto in transType");480 return revertAndWarn(rp, error.UnsupportedType, source_loc, "TODO: implement parameters for FunctionProto in transType");
470 }481 }
482
483 return finishTransFnProto(rp, fn_ty, source_loc, fn_decl_context, is_var_args, cc);
484}
485
486fn transFnNoProto(
487 rp: RestorePoint,
488 fn_ty: *const ZigClangFunctionType,
489 source_loc: ZigClangSourceLocation,
490 fn_decl_context: ?FnDeclContext,
491) !*ast.Node.FnProto {
492 const cc = try transCC(rp, fn_ty, source_loc);
493 const is_var_args = if (fn_decl_context) |ctx| !ctx.is_export else true;
494 return finishTransFnProto(rp, fn_ty, source_loc, fn_decl_context, is_var_args, cc);
495}
496
497fn finishTransFnProto(
498 rp: RestorePoint,
499 fn_ty: *const ZigClangFunctionType,
500 source_loc: ZigClangSourceLocation,
501 fn_decl_context: ?FnDeclContext,
502 is_var_args: bool,
503 cc: CallingConvention,
504) !*ast.Node.FnProto {
505 const is_export = if (fn_decl_context) |ctx| ctx.is_export else false;
506
471 // TODO check for always_inline attribute507 // TODO check for always_inline attribute
472 // TODO check for align attribute508 // TODO check for align attribute
473509
474 // pub extern fn name(...) T510 // pub extern fn name(...) T
475 const pub_tok = try appendToken(rp.c, .Keyword_pub, "pub");511 const pub_tok = try appendToken(rp.c, .Keyword_pub, "pub");
476 const cc_tok = if (cc == .Stdcall) try appendToken(rp.c, .Keyword_stdcallcc, "stdcallcc") else null;512 const cc_tok = if (cc == .Stdcall) try appendToken(rp.c, .Keyword_stdcallcc, "stdcallcc") else null;
477 const is_export = exp: {
478 const decl_ctx = fn_decl_context orelse break :exp false;
479 break :exp switch (decl_ctx.storage_class) {
480 .None => switch (rp.c.mode) {
481 .import => false,
482 .translate => decl_ctx.has_body,
483 },
484 .Extern, .Static => false,
485 .PrivateExtern => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported storage class: private extern"),
486 .Auto => unreachable, // Not legal on functions
487 .Register => unreachable, // Not legal on functions
488 };
489 };
490 const extern_export_inline_tok = if (is_export)513 const extern_export_inline_tok = if (is_export)
491 try appendToken(rp.c, .Keyword_export, "export")514 try appendToken(rp.c, .Keyword_export, "export")
492 else if (cc == .C)515 else if (cc == .C)
...@@ -527,7 +550,7 @@ fn transFnProto(...@@ -527,7 +550,7 @@ fn transFnProto(
527 .name_token = name_tok,550 .name_token = name_tok,
528 .params = ast.Node.FnProto.ParamList.init(rp.c.a()),551 .params = ast.Node.FnProto.ParamList.init(rp.c.a()),
529 .return_type = ast.Node.FnProto.ReturnType{ .Explicit = return_type_node },552 .return_type = ast.Node.FnProto.ReturnType{ .Explicit = return_type_node },
530 .var_args_token = var_args_tok,553 .var_args_token = null, // TODO this field is broken in the AST data model
531 .extern_export_inline_token = extern_export_inline_tok,554 .extern_export_inline_token = extern_export_inline_tok,
532 .cc_token = cc_tok,555 .cc_token = cc_tok,
533 .async_attr = null,556 .async_attr = null,
...@@ -536,6 +559,19 @@ fn transFnProto(...@@ -536,6 +559,19 @@ fn transFnProto(
536 .align_expr = null,559 .align_expr = null,
537 .section_expr = null,560 .section_expr = null,
538 };561 };
562 if (is_var_args) {
563 const var_arg_node = try rp.c.a().create(ast.Node.ParamDecl);
564 var_arg_node.* = ast.Node.ParamDecl{
565 .base = ast.Node{ .id = ast.Node.Id.ParamDecl },
566 .doc_comments = null,
567 .comptime_token = null,
568 .noalias_token = null,
569 .name_token = null,
570 .type_node = undefined,
571 .var_args_token = var_args_tok,
572 };
573 try fn_proto.params.push(&var_arg_node.base);
574 }
539 return fn_proto;575 return fn_proto;
540}576}
541577
std/os/linux.zig+27-13
...@@ -959,10 +959,13 @@ pub fn waitpid(pid: i32, status: *i32, options: i32) usize {...@@ -959,10 +959,13 @@ pub fn waitpid(pid: i32, status: *i32, options: i32) usize {
959 return syscall4(SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0);959 return syscall4(SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0);
960}960}
961961
962var vdso_clock_gettime = @ptrCast(?*const c_void, init_vdso_clock_gettime);
963
962pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {964pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
963 if (VDSO_CGT_SYM.len != 0) {965 if (VDSO_CGT_SYM.len != 0) {
964 const f = @atomicLoad(@typeOf(init_vdso_clock_gettime), &vdso_clock_gettime, builtin.AtomicOrder.Unordered);966 const ptr = @atomicLoad(?*const c_void, &vdso_clock_gettime, .Unordered);
965 if (@ptrToInt(f) != 0) {967 if (ptr) |fn_ptr| {
968 const f = @ptrCast(@typeOf(clock_gettime), fn_ptr);
966 const rc = f(clk_id, tp);969 const rc = f(clk_id, tp);
967 switch (rc) {970 switch (rc) {
968 0, @bitCast(usize, isize(-EINVAL)) => return rc,971 0, @bitCast(usize, isize(-EINVAL)) => return rc,
...@@ -972,13 +975,18 @@ pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {...@@ -972,13 +975,18 @@ pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
972 }975 }
973 return syscall2(SYS_clock_gettime, @bitCast(usize, isize(clk_id)), @ptrToInt(tp));976 return syscall2(SYS_clock_gettime, @bitCast(usize, isize(clk_id)), @ptrToInt(tp));
974}977}
975var vdso_clock_gettime = init_vdso_clock_gettime;978
976extern fn init_vdso_clock_gettime(clk: i32, ts: *timespec) usize {979extern fn init_vdso_clock_gettime(clk: i32, ts: *timespec) usize {
977 const addr = vdso.lookup(VDSO_CGT_VER, VDSO_CGT_SYM);980 const ptr = @intToPtr(?*const c_void, vdso.lookup(VDSO_CGT_VER, VDSO_CGT_SYM));
978 var f = @intToPtr(@typeOf(init_vdso_clock_gettime), addr);981 // Note that we may not have a VDSO at all, update the stub address anyway
979 _ = @cmpxchgStrong(@typeOf(init_vdso_clock_gettime), &vdso_clock_gettime, init_vdso_clock_gettime, f, builtin.AtomicOrder.Monotonic, builtin.AtomicOrder.Monotonic);982 // so that clock_gettime will fall back on the good old (and slow) syscall
980 if (@ptrToInt(f) == 0) return @bitCast(usize, isize(-ENOSYS));983 _ = @cmpxchgStrong(?*const c_void, &vdso_clock_gettime, &init_vdso_clock_gettime, ptr, .Monotonic, .Monotonic);
981 return f(clk, ts);984 // Call into the VDSO if available
985 if (ptr) |fn_ptr| {
986 const f = @ptrCast(@typeOf(clock_gettime), fn_ptr);
987 return f(clk, ts);
988 }
989 return @bitCast(usize, isize(-ENOSYS));
982}990}
983991
984pub fn clock_getres(clk_id: i32, tp: *timespec) usize {992pub fn clock_getres(clk_id: i32, tp: *timespec) usize {
...@@ -1104,8 +1112,8 @@ pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigacti...@@ -1104,8 +1112,8 @@ pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigacti
11041112
1105const NSIG = 65;1113const NSIG = 65;
1106const sigset_t = [128 / @sizeOf(usize)]usize;1114const sigset_t = [128 / @sizeOf(usize)]usize;
1107const all_mask = []u32{0xffffffff, 0xffffffff};1115const all_mask = []u32{ 0xffffffff, 0xffffffff };
1108const app_mask = []u32{0xfffffffc, 0x7fffffff};1116const app_mask = []u32{ 0xfffffffc, 0x7fffffff };
11091117
1110const k_sigaction = extern struct {1118const k_sigaction = extern struct {
1111 handler: extern fn (i32) void,1119 handler: extern fn (i32) void,
...@@ -1403,9 +1411,15 @@ pub const epoll_data = extern union {...@@ -1403,9 +1411,15 @@ pub const epoll_data = extern union {
1403// On x86_64 the structure is packed so that it matches the definition of its1411// On x86_64 the structure is packed so that it matches the definition of its
1404// 32bit counterpart1412// 32bit counterpart
1405pub const epoll_event = if (builtin.arch != .x86_64)1413pub const epoll_event = if (builtin.arch != .x86_64)
1406 extern struct { events: u32, data: epoll_data }1414 extern struct {
1407 else1415 events: u32,
1408 packed struct { events: u32, data: epoll_data };1416 data: epoll_data,
1417 }
1418else
1419 packed struct {
1420 events: u32,
1421 data: epoll_data,
1422 };
14091423
1410pub fn epoll_create() usize {1424pub fn epoll_create() usize {
1411 return epoll_create1(0);1425 return epoll_create1(0);
test/tests.zig+9-1
...@@ -1076,6 +1076,14 @@ pub const TranslateCContext = struct {...@@ -1076,6 +1076,14 @@ pub const TranslateCContext = struct {
1076 }1076 }
10771077
1078 pub fn add_both(self: *TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) void {1078 pub fn add_both(self: *TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) void {
1079 for ([]bool{ false, true }) |stage2| {
1080 const tc = self.create(false, "source.h", name, source, expected_lines);
1081 tc.stage2 = stage2;
1082 self.addCase(tc);
1083 }
1084 }
1085
1086 pub fn addC_both(self: *TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) void {
1079 for ([]bool{ false, true }) |stage2| {1087 for ([]bool{ false, true }) |stage2| {
1080 const tc = self.create(false, "source.c", name, source, expected_lines);1088 const tc = self.create(false, "source.c", name, source, expected_lines);
1081 tc.stage2 = stage2;1089 tc.stage2 = stage2;
...@@ -1084,7 +1092,7 @@ pub const TranslateCContext = struct {...@@ -1084,7 +1092,7 @@ pub const TranslateCContext = struct {
1084 }1092 }
10851093
1086 pub fn add_2(self: *TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) void {1094 pub fn add_2(self: *TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) void {
1087 const tc = self.create(false, "source.c", name, source, expected_lines);1095 const tc = self.create(false, "source.h", name, source, expected_lines);
1088 tc.stage2 = true;1096 tc.stage2 = true;
1089 self.addCase(tc);1097 self.addCase(tc);
1090 }1098 }
test/translate_c.zig+32-12
...@@ -1,6 +1,13 @@...@@ -1,6 +1,13 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4// add_both - test for stage1 and stage2, in #include mode
5// add - test stage1 only, in #include mode
6// add_2 - test stage2 only, in #include mode
7// addC_both - test for stage1 and stage2, in -c mode
8// addC - test stage1 only, in -c mode
9// addC_2 - test stage2 only, in -c mode
10
4pub fn addCases(cases: *tests.TranslateCContext) void {11pub fn addCases(cases: *tests.TranslateCContext) void {
5 /////////////// Cases that pass for both stage1/stage2 ////////////////12 /////////////// Cases that pass for both stage1/stage2 ////////////////
6 cases.add_both("simple function prototypes",13 cases.add_both("simple function prototypes",
...@@ -11,25 +18,29 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -11,25 +18,29 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
11 \\pub extern fn bar() c_int;18 \\pub extern fn bar() c_int;
12 );19 );
1320
14 cases.add_both("simple function definition",21 /////////////// Cases that pass for only stage2 ////////////////
15 \\void foo(void) {};22 cases.add_2("Parameterless function prototypes",
23 \\void a() {}
24 \\void b(void) {}
25 \\void c();
26 \\void d(void);
16 ,27 ,
17 \\pub export fn foo() void {}28 \\pub export fn a() void {}
29 \\pub export fn b() void {}
30 \\pub extern fn c(...) void;
31 \\pub extern fn d() void;
18 );32 );
1933
20 /////////////// Cases that pass for only stage2 ////////////////34 cases.add_2("simple function definition",
21 // (none)35 \\void foo(void) {}
2236 \\static void bar(void) {}
23 /////////////// Cases that pass for only stage1 ////////////////
24
25 cases.addC("Parameterless function prototypes",
26 \\void foo() {}
27 \\void bar(void) {}
28 ,37 ,
29 \\pub export fn foo() void {}38 \\pub export fn foo() void {}
30 \\pub export fn bar() void {}39 \\pub extern fn bar() void {}
31 );40 );
3241
42 /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
43
33 cases.add("macro with left shift",44 cases.add("macro with left shift",
34 \\#define REDISMODULE_READ (1<<0)45 \\#define REDISMODULE_READ (1<<0)
35 ,46 ,
...@@ -1681,4 +1692,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1681,4 +1692,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1681 \\ }1692 \\ }
1682 \\}1693 \\}
1683 );1694 );
1695
1696 /////////////// Cases for only stage1 because stage2 behavior is better ////////////////
1697 cases.addC("Parameterless function prototypes",
1698 \\void foo() {}
1699 \\void bar(void) {}
1700 ,
1701 \\pub export fn foo() void {}
1702 \\pub export fn bar() void {}
1703 );
1684}1704}