authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-05-10 17:44:47-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-05-10 17:44:47-04:00
log82219b1fd5018a961726847bf42dfc1d33ec3aeb
tree9f9059ca462b8c71dfe4a07d8a424d9f9152f36b
parent2933d6b8489b8dc5c07bfb503578b12d0d783350
signaturelock-open Commit is signed but in an unrecognized format.

translate-c: better handling of restore points


2 files changed, 62 insertions(+), 84 deletions(-)

src-self-hosted/translate_c.zig+48-46
......@@ -208,14 +208,14 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void {
208208
209209fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
210210 if (try c.decl_table.put(@ptrToInt(fn_decl), {})) |_| return; // Avoid processing this decl twice
211
211 const rp = makeRestorePoint(c);
212212 const fn_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, fn_decl)));
213213 const fn_decl_loc = ZigClangFunctionDecl_getLocation(fn_decl);
214214 const fn_qt = ZigClangFunctionDecl_getType(fn_decl);
215215 const fn_type = ZigClangQualType_getTypePtr(fn_qt);
216216 const proto_node = switch (ZigClangType_getTypeClass(fn_type)) {
217217 .FunctionProto => transFnProto(
218 c,
218 rp,
219219 @ptrCast(*const ZigClangFunctionProtoType, fn_type),
220220 fn_decl_loc,
221221 fn_decl,
......@@ -242,32 +242,35 @@ fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void {
242242 try c.tree.root_node.decls.push(decl_node);
243243}
244244
245fn transQualType(c: *Context, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) !*ast.Node {
246 return transType(c, ZigClangQualType_getTypePtr(qt), source_loc);
245fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) Error!*ast.Node {
246 return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc);
247}
248
249fn qualTypeCanon(qt: ZigClangQualType) *const ZigClangType {
250 const canon = ZigClangQualType_getCanonicalType(qt);
251 return ZigClangQualType_getTypePtr(canon);
247252}
248253
249254const RestorePoint = struct {
250 context: *Context,
255 c: *Context,
251256 token_index: ast.TokenIndex,
252257 src_buf_index: usize,
253258
254259 fn activate(self: RestorePoint) void {
255 self.context.tree.tokens.shrink(self.token_index);
256 self.context.source_buffer.shrink(self.src_buf_index);
260 self.c.tree.tokens.shrink(self.token_index);
261 self.c.source_buffer.shrink(self.src_buf_index);
257262 }
258263};
259264
260265fn makeRestorePoint(c: *Context) RestorePoint {
261266 return RestorePoint{
262 .context = c,
267 .c = c,
263268 .token_index = c.tree.tokens.len,
264269 .src_buf_index = c.source_buffer.len(),
265270 };
266271}
267272
268fn transType(c: *Context, ty: *const ZigClangType, source_loc: ZigClangSourceLocation) !*ast.Node {
269 const rp = makeRestorePoint(c);
270
273fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSourceLocation) Error!*ast.Node {
271274 switch (ZigClangType_getTypeClass(ty)) {
272275 .Builtin => {
273276 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
......@@ -275,23 +278,26 @@ fn transType(c: *Context, ty: *const ZigClangType, source_loc: ZigClangSourceLoc
275278 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type"),
276279 }
277280 },
278 .FunctionProto => return transFnProto(c, @ptrCast(*const ZigClangFunctionType, ty), source_loc, null, false),
281 .FunctionProto => {
282 const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty);
283 const fn_proto = try transFnProto(rp, fn_proto_ty, source_loc, null, null);
284 return &fn_proto.base;
285 },
279286 else => {
280 const type_name = c.str(ZigClangType_getTypeClassName(ty));
287 const type_name = rp.c.str(ZigClangType_getTypeClassName(ty));
281288 return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{}'", type_name);
282289 },
283290 }
284291}
285292
286293fn transFnProto(
287 c: *Context,
294 rp: RestorePoint,
288295 fn_proto_ty: *const ZigClangFunctionProtoType,
289296 source_loc: ZigClangSourceLocation,
290297 opt_fn_decl: ?*const ZigClangFunctionDecl,
291298 fn_name: ?[]const u8,
292299) !*ast.Node.FnProto {
293300 const fn_ty = @ptrCast(*const ZigClangFunctionType, fn_proto_ty);
294 const rp = makeRestorePoint(c);
295301 const cc = switch (ZigClangFunctionType_getCallConv(fn_ty)) {
296302 .C => CallingConvention.C,
297303 .X86StdCall => CallingConvention.Stdcall,
......@@ -323,13 +329,13 @@ fn transFnProto(
323329 // TODO check for align attribute
324330
325331 // extern fn name(...) T
326 const cc_tok = if (cc == .Stdcall) try appendToken(c, .Keyword_stdcallcc, "stdcallcc") else null;
332 const cc_tok = if (cc == .Stdcall) try appendToken(rp.c, .Keyword_stdcallcc, "stdcallcc") else null;
327333 const is_export = exp: {
328334 const fn_decl = opt_fn_decl orelse break :exp false;
329335 const has_body = ZigClangFunctionDecl_hasBody(fn_decl);
330336 const storage_class = ZigClangFunctionDecl_getStorageClass(fn_decl);
331337 break :exp switch (storage_class) {
332 .None => switch (c.mode) {
338 .None => switch (rp.c.mode) {
333339 .import => false,
334340 .translate => has_body,
335341 },
......@@ -340,48 +346,44 @@ fn transFnProto(
340346 };
341347 };
342348 const extern_export_inline_tok = if (is_export)
343 try appendToken(c, .Keyword_export, "export")
349 try appendToken(rp.c, .Keyword_export, "export")
344350 else if (cc == .C)
345 try appendToken(c, .Keyword_extern, "extern")
351 try appendToken(rp.c, .Keyword_extern, "extern")
346352 else
347353 null;
348 const fn_tok = try appendToken(c, .Keyword_fn, "fn");
349 const name_tok = if (fn_name) |n| try appendToken(c, .Identifier, "{}", n) else null;
350 const lparen_tok = try appendToken(c, .LParen, "(");
351 const var_args_tok = if (is_var_args) try appendToken(c, .Ellipsis3, "...") else null;
352 const rparen_tok = try appendToken(c, .RParen, ")");
354 const fn_tok = try appendToken(rp.c, .Keyword_fn, "fn");
355 const name_tok = if (fn_name) |n| try appendToken(rp.c, .Identifier, "{}", n) else null;
356 const lparen_tok = try appendToken(rp.c, .LParen, "(");
357 const var_args_tok = if (is_var_args) try appendToken(rp.c, .Ellipsis3, "...") else null;
358 const rparen_tok = try appendToken(rp.c, .RParen, ")");
353359
354360 const return_type_node = blk: {
355361 if (ZigClangFunctionType_getNoReturnAttr(fn_ty)) {
356 break :blk try appendIdentifier(c, "noreturn");
362 break :blk try appendIdentifier(rp.c, "noreturn");
357363 } else {
358 return revertAndWarn(rp, error.UnsupportedType, source_loc, "TODO: non-noreturn FunctionProto return type");
359 //proto_node->data.fn_proto.return_type = trans_qual_type(c,
360 // ZigClangFunctionType_getReturnType(fn_ty), source_loc);
361 //if (proto_node->data.fn_proto.return_type == nullptr) {
362 // emit_warning(c, source_loc, "unsupported function proto return type");
363 // return nullptr;
364 //}
365 //// convert c_void to actual void (only for return type)
366 //// we do want to look at the AstNode instead of ZigClangQualType, because
367 //// if they do something like:
368 //// typedef Foo void;
369 //// void foo(void) -> Foo;
370 //// we want to keep the return type AST node.
371 //if (is_c_void_type(proto_node->data.fn_proto.return_type)) {
372 // proto_node->data.fn_proto.return_type = trans_create_node_symbol_str(c, "void");
373 //}
364 const return_qt = ZigClangFunctionType_getReturnType(fn_ty);
365 if (ZigClangType_isVoidType(qualTypeCanon(return_qt))) {
366 break :blk try appendIdentifier(rp.c, "void");
367 } else {
368 break :blk transQualType(rp, return_qt, source_loc) catch |err| switch (err) {
369 error.UnsupportedType => {
370 try emitWarning(rp.c, source_loc, "unsupported function proto return type");
371 return err;
372 },
373 else => return err,
374 };
375 }
374376 }
375377 };
376378
377 const fn_proto = try c.a().create(ast.Node.FnProto);
379 const fn_proto = try rp.c.a().create(ast.Node.FnProto);
378380 fn_proto.* = ast.Node.FnProto{
379381 .base = ast.Node{ .id = ast.Node.Id.FnProto },
380382 .doc_comments = null,
381383 .visib_token = null,
382384 .fn_token = fn_tok,
383385 .name_token = name_tok,
384 .params = ast.Node.FnProto.ParamList.init(c.a()),
386 .params = ast.Node.FnProto.ParamList.init(rp.c.a()),
385387 .return_type = ast.Node.FnProto.ReturnType{ .Explicit = return_type_node },
386388 .var_args_token = var_args_tok,
387389 .extern_export_inline_token = extern_export_inline_tok,
......@@ -396,14 +398,14 @@ fn transFnProto(
396398}
397399
398400fn revertAndWarn(
399 restore_point: RestorePoint,
401 rp: RestorePoint,
400402 err: var,
401403 source_loc: ZigClangSourceLocation,
402404 comptime format: []const u8,
403405 args: ...,
404406) (@typeOf(err) || error{OutOfMemory}) {
405 restore_point.activate();
406 try emitWarning(restore_point.context, source_loc, format, args);
407 rp.activate();
408 try emitWarning(rp.c, source_loc, format, args);
407409 return err;
408410}
409411
test/translate_c.zig+14-38
......@@ -2,12 +2,26 @@ const tests = @import("tests.zig");
22const builtin = @import("builtin");
33
44pub fn addCases(cases: *tests.TranslateCContext) void {
5 /////////////// Cases that pass for both stage1/stage2 ////////////////
56 cases.add_both("simple noreturn fn",
67 \\void __attribute__((noreturn)) foo(void);
78 ,
89 \\extern fn foo() noreturn;
910 );
1011
12 /////////////// Cases that pass for only stage2 ////////////////
13 // (none)
14
15 /////////////// Cases that pass for only stage1 ////////////////
16
17 cases.addC("Parameterless function prototypes",
18 \\void foo() {}
19 \\void bar(void) {}
20 ,
21 \\pub export fn foo() void {}
22 \\pub export fn bar() void {}
23 );
24
1125 cases.add("macro with left shift",
1226 \\#define REDISMODULE_READ (1<<0)
1327 ,
......@@ -1523,14 +1537,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
15231537 \\}
15241538 );
15251539
1526 cases.addC("Parameterless function prototypes",
1527 \\void foo() {}
1528 \\void bar(void) {}
1529 ,
1530 \\pub export fn foo() void {}
1531 \\pub export fn bar() void {}
1532 );
1533
15341540 cases.addC(
15351541 "u integer suffix after 0 (zero) in macro definition",
15361542 "#define ZERO 0U",
......@@ -1667,34 +1673,4 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
16671673 \\ }
16681674 \\}
16691675 );
1670
1671 // cases.add("empty array with initializer",
1672 // "int a[4] = {};"
1673 // ,
1674 // "pub var a: [4]c_int = [1]c_int{0} ** 4;"
1675 // );
1676
1677 // cases.add("array with initialization",
1678 // "int a[4] = {1, 2, 3, 4};"
1679 // ,
1680 // "pub var a: [4]c_int = [4]c_int{1, 2, 3, 4};"
1681 // );
1682
1683 // cases.add("array with incomplete initialization",
1684 // "int a[4] = {3, 4};"
1685 // ,
1686 // "pub var a: [4]c_int = [2]c_int{3, 4} ++ ([1]c_int{0} ** 2);"
1687 // );
1688
1689 // cases.add("2D array with initialization",
1690 // "int a[3][3] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };"
1691 // ,
1692 // "pub var a: [3][3]c_int = [3][3]c_int{[3]c_int{1, 2, 3}, [3]c_int{4, 5, 6}, [3]c_int{7, 8, 9}};"
1693 // );
1694
1695 // cases.add("2D array with incomplete initialization",
1696 // "int a[3][3] = { {1, 2}, {4, 5, 6} };"
1697 // ,
1698 // "pub var a: [3][3]c_int = [2][3]c_int{[2]c_int{1, 2} ++ [1]c_int{0}, [3]c_int{4, 5, 6}} ++ [1][3]c_int{[1]c_int{0} ** 3};"
1699 // );
17001676}