Skip to content

Commit 82219b1

Browse files
committed
translate-c: better handling of restore points
1 parent 2933d6b commit 82219b1

File tree

2 files changed

+62
-84
lines changed

2 files changed

+62
-84
lines changed

src-self-hosted/translate_c.zig

Lines changed: 48 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -208,14 +208,14 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void {
208208

209209
fn 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,56 +242,62 @@ fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void {
242242
try c.tree.root_node.decls.push(decl_node);
243243
}
244244

245-
fn transQualType(c: *Context, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) !*ast.Node {
246-
return transType(c, ZigClangQualType_getTypePtr(qt), source_loc);
245+
fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) Error!*ast.Node {
246+
return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc);
247+
}
248+
249+
fn qualTypeCanon(qt: ZigClangQualType) *const ZigClangType {
250+
const canon = ZigClangQualType_getCanonicalType(qt);
251+
return ZigClangQualType_getTypePtr(canon);
247252
}
248253

249254
const 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

260265
fn 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

268-
fn transType(c: *Context, ty: *const ZigClangType, source_loc: ZigClangSourceLocation) !*ast.Node {
269-
const rp = makeRestorePoint(c);
270-
273+
fn 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);
274277
switch (ZigClangBuiltinType_getKind(builtin_ty)) {
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

286293
fn 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

398400
fn 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

Lines changed: 14 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,26 @@ const tests = @import("tests.zig");
22
const builtin = @import("builtin");
33

44
pub 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
}

0 commit comments

Comments
 (0)