authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-12-14 13:12:39-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2019-12-14 13:12:39-05:00
log33d9dda5584a6c21df1a4d14ab1a251772f76d4d
treeeb638d75d3f4934639e63c8d58c0bee83c626ce3
parent21a85d4fb643cf14cf4afbcfc7ecfd359b910097
parent4dae70e702f10c385be1dea552f3d6e815dc93c9
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #3906 from Vexu/translate-c-2

Translate-c-2 structs and unions

3 files changed, 424 insertions(+), 34 deletions(-)

src-self-hosted/clang.zig+14-1
...@@ -709,6 +709,10 @@ pub const ZigClangStringLiteral_StringKind = extern enum {...@@ -709,6 +709,10 @@ pub const ZigClangStringLiteral_StringKind = extern enum {
709 UTF32,709 UTF32,
710};710};
711711
712pub const ZigClangRecordDecl_field_iterator = extern struct {
713 opaque: *c_void,
714};
715
712pub extern fn ZigClangSourceManager_getSpellingLoc(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) struct_ZigClangSourceLocation;716pub extern fn ZigClangSourceManager_getSpellingLoc(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) struct_ZigClangSourceLocation;
713pub extern fn ZigClangSourceManager_getFilename(self: *const struct_ZigClangSourceManager, SpellingLoc: struct_ZigClangSourceLocation) ?[*:0]const u8;717pub extern fn ZigClangSourceManager_getFilename(self: *const struct_ZigClangSourceManager, SpellingLoc: struct_ZigClangSourceLocation) ?[*:0]const u8;
714pub extern fn ZigClangSourceManager_getSpellingLineNumber(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint;718pub extern fn ZigClangSourceManager_getSpellingLineNumber(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint;
...@@ -718,7 +722,7 @@ pub extern fn ZigClangASTContext_getPointerType(self: ?*const struct_ZigClangAST...@@ -718,7 +722,7 @@ pub extern fn ZigClangASTContext_getPointerType(self: ?*const struct_ZigClangAST
718pub extern fn ZigClangASTUnit_getASTContext(self: ?*struct_ZigClangASTUnit) ?*struct_ZigClangASTContext;722pub extern fn ZigClangASTUnit_getASTContext(self: ?*struct_ZigClangASTUnit) ?*struct_ZigClangASTContext;
719pub extern fn ZigClangASTUnit_getSourceManager(self: *struct_ZigClangASTUnit) *struct_ZigClangSourceManager;723pub extern fn ZigClangASTUnit_getSourceManager(self: *struct_ZigClangASTUnit) *struct_ZigClangSourceManager;
720pub extern fn ZigClangASTUnit_visitLocalTopLevelDecls(self: *struct_ZigClangASTUnit, context: ?*c_void, Fn: ?extern fn (?*c_void, *const struct_ZigClangDecl) bool) bool;724pub extern fn ZigClangASTUnit_visitLocalTopLevelDecls(self: *struct_ZigClangASTUnit, context: ?*c_void, Fn: ?extern fn (?*c_void, *const struct_ZigClangDecl) bool) bool;
721pub extern fn ZigClangRecordType_getDecl(record_ty: ?*const struct_ZigClangRecordType) ?*const struct_ZigClangRecordDecl;725pub extern fn ZigClangRecordType_getDecl(record_ty: ?*const struct_ZigClangRecordType) *const struct_ZigClangRecordDecl;
722pub extern fn ZigClangEnumType_getDecl(record_ty: ?*const struct_ZigClangEnumType) ?*const struct_ZigClangEnumDecl;726pub extern fn ZigClangEnumType_getDecl(record_ty: ?*const struct_ZigClangEnumType) ?*const struct_ZigClangEnumDecl;
723pub extern fn ZigClangRecordDecl_getCanonicalDecl(record_decl: ?*const struct_ZigClangRecordDecl) ?*const struct_ZigClangTagDecl;727pub extern fn ZigClangRecordDecl_getCanonicalDecl(record_decl: ?*const struct_ZigClangRecordDecl) ?*const struct_ZigClangTagDecl;
724pub extern fn ZigClangEnumDecl_getCanonicalDecl(self: ?*const struct_ZigClangEnumDecl) ?*const struct_ZigClangTagDecl;728pub extern fn ZigClangEnumDecl_getCanonicalDecl(self: ?*const struct_ZigClangEnumDecl) ?*const struct_ZigClangTagDecl;
...@@ -732,6 +736,11 @@ pub extern fn ZigClangDecl_getLocation(self: *const ZigClangDecl) ZigClangSource...@@ -732,6 +736,11 @@ pub extern fn ZigClangDecl_getLocation(self: *const ZigClangDecl) ZigClangSource
732pub extern fn ZigClangRecordDecl_isUnion(record_decl: ?*const struct_ZigClangRecordDecl) bool;736pub extern fn ZigClangRecordDecl_isUnion(record_decl: ?*const struct_ZigClangRecordDecl) bool;
733pub extern fn ZigClangRecordDecl_isStruct(record_decl: ?*const struct_ZigClangRecordDecl) bool;737pub extern fn ZigClangRecordDecl_isStruct(record_decl: ?*const struct_ZigClangRecordDecl) bool;
734pub extern fn ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl: ?*const struct_ZigClangRecordDecl) bool;738pub extern fn ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl: ?*const struct_ZigClangRecordDecl) bool;
739pub extern fn ZigClangRecordDecl_field_begin(*const struct_ZigClangRecordDecl) ZigClangRecordDecl_field_iterator;
740pub extern fn ZigClangRecordDecl_field_end(*const struct_ZigClangRecordDecl) ZigClangRecordDecl_field_iterator;
741pub extern fn ZigClangRecordDecl_field_iterator_next(ZigClangRecordDecl_field_iterator) ZigClangRecordDecl_field_iterator;
742pub extern fn ZigClangRecordDecl_field_iterator_deref(ZigClangRecordDecl_field_iterator) *const struct_ZigClangFieldDecl;
743pub extern fn ZigClangRecordDecl_field_iterator_neq(ZigClangRecordDecl_field_iterator, ZigClangRecordDecl_field_iterator) bool;
735pub extern fn ZigClangEnumDecl_getIntegerType(self: ?*const struct_ZigClangEnumDecl) struct_ZigClangQualType;744pub extern fn ZigClangEnumDecl_getIntegerType(self: ?*const struct_ZigClangEnumDecl) struct_ZigClangQualType;
736pub extern fn ZigClangDecl_getName_bytes_begin(decl: ?*const struct_ZigClangDecl) [*c]const u8;745pub extern fn ZigClangDecl_getName_bytes_begin(decl: ?*const struct_ZigClangDecl) [*c]const u8;
737pub extern fn ZigClangSourceLocation_eq(a: struct_ZigClangSourceLocation, b: struct_ZigClangSourceLocation) bool;746pub extern fn ZigClangSourceLocation_eq(a: struct_ZigClangSourceLocation, b: struct_ZigClangSourceLocation) bool;
...@@ -987,3 +996,7 @@ pub extern fn ZigClangStringLiteral_getKind(*const ZigClangStringLiteral) ZigCla...@@ -987,3 +996,7 @@ pub extern fn ZigClangStringLiteral_getKind(*const ZigClangStringLiteral) ZigCla
987pub extern fn ZigClangStringLiteral_getString_bytes_begin_size(*const ZigClangStringLiteral, *usize) [*c]const u8;996pub extern fn ZigClangStringLiteral_getString_bytes_begin_size(*const ZigClangStringLiteral, *usize) [*c]const u8;
988997
989pub extern fn ZigClangParenExpr_getSubExpr(*const ZigClangParenExpr) *const ZigClangExpr;998pub extern fn ZigClangParenExpr_getSubExpr(*const ZigClangParenExpr) *const ZigClangExpr;
999
1000pub extern fn ZigClangFieldDecl_isBitField(*const struct_ZigClangFieldDecl) bool;
1001pub extern fn ZigClangFieldDecl_getType(*const struct_ZigClangFieldDecl) struct_ZigClangQualType;
1002pub extern fn ZigClangFieldDecl_getLocation(*const struct_ZigClangFieldDecl) struct_ZigClangSourceLocation;
src-self-hosted/translate_c.zig+366-25
...@@ -31,6 +31,12 @@ fn addrEql(a: usize, b: usize) bool {...@@ -31,6 +31,12 @@ fn addrEql(a: usize, b: usize) bool {
31 return a == b;31 return a == b;
32}32}
3333
34const SymbolTable = std.StringHashMap(void);
35const AliasList = std.SegmentedList(struct {
36 alias: []const u8,
37 name: []const u8,
38}, 4);
39
34const Scope = struct {40const Scope = struct {
35 id: Id,41 id: Id,
36 parent: ?*Scope,42 parent: ?*Scope,
...@@ -98,6 +104,8 @@ const Context = struct {...@@ -98,6 +104,8 @@ const Context = struct {
98 err: Error,104 err: Error,
99 source_manager: *ZigClangSourceManager,105 source_manager: *ZigClangSourceManager,
100 decl_table: DeclTable,106 decl_table: DeclTable,
107 alias_list: AliasList,
108 sym_table: SymbolTable,
101 global_scope: *Scope.Root,109 global_scope: *Scope.Root,
102 ptr_params: std.BufSet,110 ptr_params: std.BufSet,
103 clang_context: *ZigClangASTContext,111 clang_context: *ZigClangASTContext,
...@@ -177,6 +185,8 @@ pub fn translate(...@@ -177,6 +185,8 @@ pub fn translate(
177 .source_manager = ZigClangASTUnit_getSourceManager(ast_unit),185 .source_manager = ZigClangASTUnit_getSourceManager(ast_unit),
178 .err = undefined,186 .err = undefined,
179 .decl_table = DeclTable.init(arena),187 .decl_table = DeclTable.init(arena),
188 .alias_list = AliasList.init(arena),
189 .sym_table = SymbolTable.init(arena),
180 .global_scope = try arena.create(Scope.Root),190 .global_scope = try arena.create(Scope.Root),
181 .ptr_params = std.BufSet.init(arena),191 .ptr_params = std.BufSet.init(arena),
182 .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?,192 .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?,
...@@ -191,6 +201,12 @@ pub fn translate(...@@ -191,6 +201,12 @@ pub fn translate(
191 if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorC)) {201 if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorC)) {
192 return context.err;202 return context.err;
193 }203 }
204 var it = context.alias_list.iterator(0);
205 while (it.next()) |alias| {
206 if (!context.sym_table.contains(alias.alias)) {
207 try createAlias(&context, alias);
208 }
209 }
194210
195 tree.root_node.eof_token = try appendToken(&context, .Eof, "");211 tree.root_node.eof_token = try appendToken(&context, .Eof, "");
196 tree.source = source_buffer.toOwnedSlice();212 tree.source = source_buffer.toOwnedSlice();
...@@ -220,13 +236,13 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void {...@@ -220,13 +236,13 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void {
220 return visitFnDecl(c, @ptrCast(*const ZigClangFunctionDecl, decl));236 return visitFnDecl(c, @ptrCast(*const ZigClangFunctionDecl, decl));
221 },237 },
222 .Typedef => {238 .Typedef => {
223 try resolveTypeDef(c, @ptrCast(*const ZigClangTypedefNameDecl, decl));239 return resolveTypeDef(c, @ptrCast(*const ZigClangTypedefNameDecl, decl));
224 },240 },
225 .Enum => {241 .Enum => {
226 try emitWarning(c, ZigClangDecl_getLocation(decl), "TODO implement translate-c for enums", .{});242 try emitWarning(c, ZigClangDecl_getLocation(decl), "TODO implement translate-c for enums", .{});
227 },243 },
228 .Record => {244 .Record => {
229 try emitWarning(c, ZigClangDecl_getLocation(decl), "TODO implement translate-c for structs", .{});245 return resolveRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl));
230 },246 },
231 .Var => {247 .Var => {
232 return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl));248 return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl));
...@@ -398,9 +414,7 @@ fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Err...@@ -398,9 +414,7 @@ fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Err
398 const typedef_loc = ZigClangTypedefNameDecl_getLocation(typedef_decl);414 const typedef_loc = ZigClangTypedefNameDecl_getLocation(typedef_decl);
399 const type_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) {415 const type_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) {
400 error.UnsupportedType => {416 error.UnsupportedType => {
401 const node = try failDecl(c, typedef_loc, typedef_name, "unable to resolve typedef child type", .{});417 return failDecl(c, typedef_loc, typedef_name, "unable to resolve typedef child type", .{});
402 _ = try c.decl_table.put(@ptrToInt(typedef_decl), node);
403 return node;
404 },418 },
405 error.OutOfMemory => |e| return e,419 error.OutOfMemory => |e| return e,
406 };420 };
...@@ -426,6 +440,89 @@ fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Err...@@ -426,6 +440,89 @@ fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Err
426 try addTopLevelDecl(c, typedef_name, &node.base);440 try addTopLevelDecl(c, typedef_name, &node.base);
427}441}
428442
443fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!void {
444 if (try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), {})) |_| return; // Avoid processing this decl twice
445 const rp = makeRestorePoint(c);
446
447 const bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl)));
448
449 const container_kind_name = if (ZigClangRecordDecl_isUnion(record_decl))
450 "union"
451 else if (ZigClangRecordDecl_isStruct(record_decl))
452 "struct"
453 else
454 return failDecl(c, ZigClangRecordDecl_getLocation(record_decl), bare_name, "record {} is not a struct or union", .{bare_name});
455
456 if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0)
457 return;
458
459 const visib_tok = try appendToken(c, .Keyword_pub, "pub");
460 const const_tok = try appendToken(c, .Keyword_const, "const");
461
462 const name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name });
463 const name_tok = try appendToken(c, .Identifier, name);
464
465 const eq_tok = try appendToken(c, .Equal, "=");
466 const init_node = transRecordDecl(c, record_decl) catch |err| switch (err) {
467 error.UnsupportedType => {
468 return failDecl(c, ZigClangRecordDecl_getLocation(record_decl), name, "unable to resolve record type", .{});
469 },
470 error.OutOfMemory => |e| return e,
471 };
472 const semicolon_token = try appendToken(c, .Semicolon, ";");
473
474 const node = try c.a().create(ast.Node.VarDecl);
475 node.* = ast.Node.VarDecl{
476 .base = ast.Node{ .id = .VarDecl },
477 .doc_comments = null,
478 .visib_token = visib_tok,
479 .thread_local_token = null,
480 .name_token = name_tok,
481 .eq_token = eq_tok,
482 .mut_token = const_tok,
483 .comptime_token = null,
484 .extern_export_token = null,
485 .lib_name = null,
486 .type_node = null,
487 .align_node = null,
488 .section_node = null,
489 .init_node = init_node,
490 .semicolon_token = semicolon_token,
491 };
492
493 try addTopLevelDecl(c, name, &node.base);
494 try c.alias_list.push(.{ .alias = bare_name, .name = name });
495}
496
497fn createAlias(c: *Context, alias: var) !void {
498 const visib_tok = try appendToken(c, .Keyword_pub, "pub");
499 const mut_tok = try appendToken(c, .Keyword_const, "const");
500 const name_tok = try appendToken(c, .Identifier, alias.alias);
501
502 const eq_tok = try appendToken(c, .Equal, "=");
503 const init_node = try appendIdentifier(c, alias.name);
504
505 const node = try c.a().create(ast.Node.VarDecl);
506 node.* = ast.Node.VarDecl{
507 .base = ast.Node{ .id = .VarDecl },
508 .doc_comments = null,
509 .visib_token = visib_tok,
510 .thread_local_token = null,
511 .name_token = name_tok,
512 .eq_token = eq_tok,
513 .mut_token = mut_tok,
514 .comptime_token = null,
515 .extern_export_token = null,
516 .lib_name = null,
517 .type_node = null,
518 .align_node = null,
519 .section_node = null,
520 .init_node = init_node,
521 .semicolon_token = try appendToken(c, .Semicolon, ";"),
522 };
523 return addTopLevelDecl(c, alias.alias, &node.base);
524}
525
429const ResultUsed = enum {526const ResultUsed = enum {
430 used,527 used,
431 unused,528 unused,
...@@ -442,7 +539,7 @@ fn transStmt(...@@ -442,7 +539,7 @@ fn transStmt(
442 stmt: *const ZigClangStmt,539 stmt: *const ZigClangStmt,
443 result_used: ResultUsed,540 result_used: ResultUsed,
444 lrvalue: LRValue,541 lrvalue: LRValue,
445) !TransResult {542) TransError!TransResult {
446 const sc = ZigClangStmt_getStmtClass(stmt);543 const sc = ZigClangStmt_getStmtClass(stmt);
447 switch (sc) {544 switch (sc) {
448 .BinaryOperatorClass => return transBinaryOperator(rp, scope, @ptrCast(*const ZigClangBinaryOperator, stmt), result_used),545 .BinaryOperatorClass => return transBinaryOperator(rp, scope, @ptrCast(*const ZigClangBinaryOperator, stmt), result_used),
...@@ -456,6 +553,7 @@ fn transStmt(...@@ -456,6 +553,7 @@ fn transStmt(
456 .StringLiteralClass => return transStringLiteral(rp, scope, @ptrCast(*const ZigClangStringLiteral, stmt), result_used),553 .StringLiteralClass => return transStringLiteral(rp, scope, @ptrCast(*const ZigClangStringLiteral, stmt), result_used),
457 .ParenExprClass => return transExpr(rp, scope, ZigClangParenExpr_getSubExpr(@ptrCast(*const ZigClangParenExpr, stmt)), result_used, lrvalue),554 .ParenExprClass => return transExpr(rp, scope, ZigClangParenExpr_getSubExpr(@ptrCast(*const ZigClangParenExpr, stmt)), result_used, lrvalue),
458 .InitListExprClass => return transInitListExpr(rp, scope, @ptrCast(*const ZigClangInitListExpr, stmt), result_used),555 .InitListExprClass => return transInitListExpr(rp, scope, @ptrCast(*const ZigClangInitListExpr, stmt), result_used),
556 .ImplicitValueInitExprClass => return transImplicitValueInitExpr(rp, scope, @ptrCast(*const ZigClangExpr, stmt), result_used),
459 else => {557 else => {
460 return revertAndWarn(558 return revertAndWarn(
461 rp,559 rp,
...@@ -800,6 +898,13 @@ fn transImplicitCastExpr(...@@ -800,6 +898,13 @@ fn transImplicitCastExpr(
800 .LValueToRValue, .NoOp => {898 .LValueToRValue, .NoOp => {
801 return transExpr(rp, scope, sub_expr, .used, .r_value);899 return transExpr(rp, scope, sub_expr, .used, .r_value);
802 },900 },
901 .NullToPointer => {
902 return TransResult{
903 .node = try transCreateNodeNullLiteral(rp.c),
904 .node_scope = scope,
905 .child_scope = scope,
906 };
907 },
803 else => |kind| return revertAndWarn(908 else => |kind| return revertAndWarn(
804 rp,909 rp,
805 error.UnsupportedTranslation,910 error.UnsupportedTranslation,
...@@ -984,21 +1089,33 @@ fn transInitListExpr(...@@ -984,21 +1089,33 @@ fn transInitListExpr(
984 expr: *const ZigClangInitListExpr,1089 expr: *const ZigClangInitListExpr,
985 used: ResultUsed,1090 used: ResultUsed,
986) TransError!TransResult {1091) TransError!TransResult {
987 // TODO use anon literals once they work properly
988 const qt = getExprQualType(rp.c, @ptrCast(*const ZigClangExpr, expr));1092 const qt = getExprQualType(rp.c, @ptrCast(*const ZigClangExpr, expr));
989 const qual_type = ZigClangQualType_getTypePtr(qt);1093 const qual_type = ZigClangQualType_getTypePtr(qt);
990 const source_loc = ZigClangExpr_getBeginLoc(@ptrCast(*const ZigClangExpr, expr));1094 const source_loc = ZigClangExpr_getBeginLoc(@ptrCast(*const ZigClangExpr, expr));
1095 switch (ZigClangType_getTypeClass(qual_type)) {
1096 .ConstantArray => {},
1097 .Record, .Elaborated => {
1098 return revertAndWarn(rp, error.UnsupportedType, source_loc, "TODO initListExpr for structs", .{});
1099 },
1100 else => {
1101 const type_name = rp.c.str(ZigClangType_getTypeClassName(qual_type));
1102 return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported initlist type: '{}'", .{type_name});
1103 },
1104 }
1105
991 const arr_type = ZigClangType_getAsArrayTypeUnsafe(qual_type);1106 const arr_type = ZigClangType_getAsArrayTypeUnsafe(qual_type);
992 const child_qt = ZigClangArrayType_getElementType(arr_type);1107 const child_qt = ZigClangArrayType_getElementType(arr_type);
993 const init_count = ZigClangInitListExpr_getNumInits(expr);1108 const init_count = ZigClangInitListExpr_getNumInits(expr);
994 const all_count = 200; //ZigClangArrayType_getSize(arr_type);1109 const const_arr_ty = @ptrCast(*const ZigClangConstantArrayType, qual_type);
1110 const size_ap_int = ZigClangConstantArrayType_getSize(const_arr_ty);
1111 const all_count = ZigClangAPInt_getLimitedValue(size_ap_int, std.math.maxInt(usize));
995 const leftover_count = all_count - init_count;1112 const leftover_count = all_count - init_count;
9961113
997 var init_node: *ast.Node.SuffixOp = undefined;1114 var init_node: *ast.Node.SuffixOp = undefined;
998 var cat_tok: ast.TokenIndex = undefined;1115 var cat_tok: ast.TokenIndex = undefined;
999 if (init_count != 0) {1116 if (init_count != 0) {
1000 var type_node = try transQualType(rp, qt, source_loc);1117 const dot_tok = try appendToken(rp.c, .Period, ".");
1001 init_node = try transCreateNodeArrayInitializer(rp.c, type_node);1118 init_node = try transCreateNodeArrayInitializer(rp.c, dot_tok);
1002 var i: c_uint = 0;1119 var i: c_uint = 0;
1003 while (i < init_count) : (i += 1) {1120 while (i < init_count) : (i += 1) {
1004 const elem_expr = ZigClangInitListExpr_getInit(expr, i);1121 const elem_expr = ZigClangInitListExpr_getInit(expr, i);
...@@ -1016,8 +1133,8 @@ fn transInitListExpr(...@@ -1016,8 +1133,8 @@ fn transInitListExpr(
1016 cat_tok = try appendToken(rp.c, .PlusPlus, "++");1133 cat_tok = try appendToken(rp.c, .PlusPlus, "++");
1017 }1134 }
10181135
1019 var filler_type_node = try transQualType(rp, qt, source_loc);1136 const dot_tok = try appendToken(rp.c, .Period, ".");
1020 var filler_init_node = try transCreateNodeArrayInitializer(rp.c, filler_type_node);1137 var filler_init_node = try transCreateNodeArrayInitializer(rp.c, dot_tok);
1021 const filler_val_expr = ZigClangInitListExpr_getArrayFiller(expr);1138 const filler_val_expr = ZigClangInitListExpr_getArrayFiller(expr);
1022 try filler_init_node.op.ArrayInitializer.push((try transExpr(rp, scope, filler_val_expr, .used, .r_value)).node);1139 try filler_init_node.op.ArrayInitializer.push((try transExpr(rp, scope, filler_val_expr, .used, .r_value)).node);
1023 filler_init_node.rtoken = try appendToken(rp.c, .RBrace, "}");1140 filler_init_node.rtoken = try appendToken(rp.c, .RBrace, "}");
...@@ -1060,6 +1177,58 @@ fn transInitListExpr(...@@ -1060,6 +1177,58 @@ fn transInitListExpr(
1060 };1177 };
1061}1178}
10621179
1180fn transImplicitValueInitExpr(
1181 rp: RestorePoint,
1182 scope: *Scope,
1183 expr: *const ZigClangExpr,
1184 used: ResultUsed,
1185) TransError!TransResult {
1186 const source_loc = ZigClangExpr_getBeginLoc(expr);
1187 const qt = getExprQualType(rp.c, expr);
1188 const ty = ZigClangQualType_getTypePtr(qt);
1189 const node = switch (ZigClangType_getTypeClass(ty)) {
1190 .Builtin => blk: {
1191 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
1192 switch (ZigClangBuiltinType_getKind(builtin_ty)) {
1193 .Bool => {
1194 break :blk try transCreateNodeBoolLiteral(rp.c, false);
1195 },
1196 .Char_U,
1197 .UChar,
1198 .Char_S,
1199 .Char8,
1200 .SChar,
1201 .UShort,
1202 .UInt,
1203 .ULong,
1204 .ULongLong,
1205 .Short,
1206 .Int,
1207 .Long,
1208 .LongLong,
1209 .UInt128,
1210 .Int128,
1211 .Float,
1212 .Double,
1213 .Float128,
1214 .Float16,
1215 .LongDouble,
1216 => {
1217 break :blk try transCreateNodeInt(rp.c, 0);
1218 },
1219 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),
1220 }
1221 },
1222 .Pointer => try transCreateNodeNullLiteral(rp.c),
1223 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "type does not have an implicit init value", .{}),
1224 };
1225 return TransResult{
1226 .node = node,
1227 .child_scope = scope,
1228 .node_scope = scope,
1229 };
1230}
1231
1063fn findBlockScope(inner: *Scope) *Scope.Block {1232fn findBlockScope(inner: *Scope) *Scope.Block {
1064 var scope = inner;1233 var scope = inner;
1065 while (true) : (scope = scope.parent orelse unreachable) {1234 while (true) : (scope = scope.parent orelse unreachable) {
...@@ -1142,28 +1311,120 @@ fn maybeSuppressResult(...@@ -1142,28 +1311,120 @@ fn maybeSuppressResult(
11421311
1143fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void {1312fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void {
1144 try c.tree.root_node.decls.push(decl_node);1313 try c.tree.root_node.decls.push(decl_node);
1314 _ = try c.sym_table.put(name, {});
1145}1315}
11461316
1147fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) TypeError!*ast.Node {1317fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) TypeError!*ast.Node {
1148 return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc);1318 return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc);
1149}1319}
11501320
1321fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) TypeError!*ast.Node {
1322 const rp = makeRestorePoint(c);
1323
1324 const record_loc = ZigClangRecordDecl_getLocation(record_decl);
1325
1326 var container_kind_name: []const u8 = undefined;
1327 var container_kind: std.zig.Token.Id = undefined;
1328
1329 if (ZigClangRecordDecl_isUnion(record_decl)) {
1330 container_kind_name = "union";
1331 container_kind = .Keyword_union;
1332 } else if (ZigClangRecordDecl_isStruct(record_decl)) {
1333 container_kind_name = "struct";
1334 container_kind = .Keyword_struct;
1335 } else {
1336 return revertAndWarn(
1337 rp,
1338 error.UnsupportedType,
1339 record_loc,
1340 "unsupported record type",
1341 .{},
1342 );
1343 }
1344
1345 const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse {
1346 return transCreateNodeOpaqueType(c);
1347 };
1348
1349 const extern_tok = try appendToken(c, .Keyword_extern, "extern");
1350 const container_tok = try appendToken(c, container_kind, container_kind_name);
1351 const lbrace_token = try appendToken(c, .LBrace, "{");
1352
1353 const container_node = try c.a().create(ast.Node.ContainerDecl);
1354 container_node.* = .{
1355 .base = ast.Node{ .id = .ContainerDecl },
1356 .layout_token = extern_tok,
1357 .kind_token = container_tok,
1358 .init_arg_expr = .None,
1359 .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()),
1360 .lbrace_token = lbrace_token,
1361 .rbrace_token = undefined,
1362 };
1363
1364 var it = ZigClangRecordDecl_field_begin(record_def);
1365 const end_it = ZigClangRecordDecl_field_end(record_def);
1366 while (ZigClangRecordDecl_field_iterator_neq(it, end_it)) : (it = ZigClangRecordDecl_field_iterator_next(it)) {
1367 const field_decl = ZigClangRecordDecl_field_iterator_deref(it);
1368 const field_loc = ZigClangFieldDecl_getLocation(field_decl);
1369
1370 if (ZigClangFieldDecl_isBitField(field_decl)) {
1371 rp.activate();
1372 const node = try transCreateNodeOpaqueType(c);
1373 try emitWarning(c, field_loc, "{} demoted to opaque type - has bitfield", .{container_kind_name});
1374 return node;
1375 }
1376
1377 const field_name = try appendToken(c, .Identifier, try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl))));
1378 _ = try appendToken(c, .Colon, ":");
1379 const field_type = try transQualType(rp, ZigClangFieldDecl_getType(field_decl), field_loc);
1380
1381 const field_node = try c.a().create(ast.Node.ContainerField);
1382 field_node.* = .{
1383 .doc_comments = null,
1384 .comptime_token = null,
1385 .name_token = field_name,
1386 .type_expr = field_type,
1387 .value_expr = null,
1388 .align_expr = null,
1389 };
1390
1391 try container_node.fields_and_decls.push(&field_node.base);
1392 _ = try appendToken(c, .Comma, ",");
1393 }
1394
1395 container_node.rbrace_token = try appendToken(c, .RBrace, "}");
1396 return &container_node.base;
1397}
1398
1151fn qualTypeIsPtr(qt: ZigClangQualType) bool {1399fn qualTypeIsPtr(qt: ZigClangQualType) bool {
1152 return ZigClangType_getTypeClass(qualTypeCanon(qt)) == .Pointer;1400 return ZigClangType_getTypeClass(qualTypeCanon(qt)) == .Pointer;
1153}1401}
11541402
1155fn qualTypeChildIsFnProto(qt: ZigClangQualType) bool {1403fn qualTypeChildIsFnProto(qt: ZigClangQualType) bool {
1156 const ty = ZigClangQualType_getTypePtr(qt);1404 const ty = ZigClangQualType_getTypePtr(qt);
1157 if (ZigClangType_getTypeClass(ty) == .Paren) {1405
1158 const paren_type = @ptrCast(*const ZigClangParenType, ty);1406 switch (ZigClangType_getTypeClass(ty)) {
1159 const inner_type = ZigClangParenType_getInnerType(paren_type);1407 .FunctionProto, .FunctionNoProto => return true,
1160 return ZigClangQualType_getTypeClass(inner_type) == .FunctionProto;1408 .Elaborated => {
1161 }1409 const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ty);
1162 if (ZigClangType_getTypeClass(ty) == .Attributed) {1410 return qualTypeChildIsFnProto(ZigClangElaboratedType_getNamedType(elaborated_ty));
1163 const attr_type = @ptrCast(*const ZigClangAttributedType, ty);1411 },
1164 return qualTypeChildIsFnProto(ZigClangAttributedType_getEquivalentType(attr_type));1412 .Typedef => {
1413 const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty);
1414 const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty);
1415 return qualTypeChildIsFnProto(ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl));
1416 },
1417 .Paren => {
1418 const paren_type = @ptrCast(*const ZigClangParenType, ty);
1419 const inner_type = ZigClangParenType_getInnerType(paren_type);
1420 return ZigClangQualType_getTypeClass(inner_type) == .FunctionProto;
1421 },
1422 .Attributed => {
1423 const attr_type = @ptrCast(*const ZigClangAttributedType, ty);
1424 return qualTypeChildIsFnProto(ZigClangAttributedType_getEquivalentType(attr_type));
1425 },
1426 else => return false,
1165 }1427 }
1166 return false;
1167}1428}
11681429
1169fn qualTypeCanon(qt: ZigClangQualType) *const ZigClangType {1430fn qualTypeCanon(qt: ZigClangQualType) *const ZigClangType {
...@@ -1197,7 +1458,18 @@ fn typeIsOpaque(c: *Context, ty: *const ZigClangType, loc: ZigClangSourceLocatio...@@ -1197,7 +1458,18 @@ fn typeIsOpaque(c: *Context, ty: *const ZigClangType, loc: ZigClangSourceLocatio
1197 .Record => {1458 .Record => {
1198 const record_ty = @ptrCast(*const ZigClangRecordType, ty);1459 const record_ty = @ptrCast(*const ZigClangRecordType, ty);
1199 const record_decl = ZigClangRecordType_getDecl(record_ty);1460 const record_decl = ZigClangRecordType_getDecl(record_ty);
1200 return (ZigClangRecordDecl_getDefinition(record_decl) == null);1461 const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse
1462 return true;
1463 var it = ZigClangRecordDecl_field_begin(record_def);
1464 const end_it = ZigClangRecordDecl_field_end(record_def);
1465 while (ZigClangRecordDecl_field_iterator_neq(it, end_it)) : (it = ZigClangRecordDecl_field_iterator_next(it)) {
1466 const field_decl = ZigClangRecordDecl_field_iterator_deref(it);
1467
1468 if (ZigClangFieldDecl_isBitField(field_decl)) {
1469 return true;
1470 }
1471 }
1472 return false;
1201 },1473 },
1202 .Elaborated => {1474 .Elaborated => {
1203 const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ty);1475 const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ty);
...@@ -1435,12 +1707,35 @@ fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {...@@ -1435,12 +1707,35 @@ fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {
1435 return &node.base;1707 return &node.base;
1436}1708}
14371709
1438fn transCreateNodeArrayInitializer(c: *Context, type_node: *ast.Node) !*ast.Node.SuffixOp {1710fn transCreateNodeNullLiteral(c: *Context) !*ast.Node {
1711 const token = try appendToken(c, .Keyword_null, "null");
1712 const node = try c.a().create(ast.Node.NullLiteral);
1713 node.* = ast.Node.NullLiteral{
1714 .base = ast.Node{ .id = .NullLiteral },
1715 .token = token,
1716 };
1717 return &node.base;
1718}
1719
1720fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node {
1721 const token = if (value)
1722 try appendToken(c, .Keyword_true, "true")
1723 else
1724 try appendToken(c, .Keyword_false, "false");
1725 const node = try c.a().create(ast.Node.BoolLiteral);
1726 node.* = ast.Node.BoolLiteral{
1727 .base = ast.Node{ .id = .BoolLiteral },
1728 .token = token,
1729 };
1730 return &node.base;
1731}
1732
1733fn transCreateNodeArrayInitializer(c: *Context, dot_tok: ast.TokenIndex) !*ast.Node.SuffixOp {
1439 _ = try appendToken(c, .LBrace, "{");1734 _ = try appendToken(c, .LBrace, "{");
1440 const node = try c.a().create(ast.Node.SuffixOp);1735 const node = try c.a().create(ast.Node.SuffixOp);
1441 node.* = ast.Node.SuffixOp{1736 node.* = ast.Node.SuffixOp{
1442 .base = ast.Node{ .id = .SuffixOp },1737 .base = ast.Node{ .id = .SuffixOp },
1443 .lhs = .{ .node = type_node },1738 .lhs = .{ .dot = dot_tok },
1444 .op = .{1739 .op = .{
1445 .ArrayInitializer = ast.Node.SuffixOp.Op.InitList.init(c.a()),1740 .ArrayInitializer = ast.Node.SuffixOp.Op.InitList.init(c.a()),
1446 },1741 },
...@@ -1450,7 +1745,7 @@ fn transCreateNodeArrayInitializer(c: *Context, type_node: *ast.Node) !*ast.Node...@@ -1450,7 +1745,7 @@ fn transCreateNodeArrayInitializer(c: *Context, type_node: *ast.Node) !*ast.Node
1450}1745}
14511746
1452fn transCreateNodeInt(c: *Context, int: var) !*ast.Node {1747fn transCreateNodeInt(c: *Context, int: var) !*ast.Node {
1453 const token = try appendToken(c, .IntegerLiteral, try std.fmt.allocPrint(c.a(), "{}", .{int}));1748 const token = try appendTokenFmt(c, .IntegerLiteral, "{}", .{int});
1454 const node = try c.a().create(ast.Node.IntegerLiteral);1749 const node = try c.a().create(ast.Node.IntegerLiteral);
1455 node.* = ast.Node.IntegerLiteral{1750 node.* = ast.Node.IntegerLiteral{
1456 .base = ast.Node{ .id = .IntegerLiteral },1751 .base = ast.Node{ .id = .IntegerLiteral },
...@@ -1459,6 +1754,21 @@ fn transCreateNodeInt(c: *Context, int: var) !*ast.Node {...@@ -1459,6 +1754,21 @@ fn transCreateNodeInt(c: *Context, int: var) !*ast.Node {
1459 return &node.base;1754 return &node.base;
1460}1755}
14611756
1757fn transCreateNodeOpaqueType(c: *Context) !*ast.Node {
1758 const builtin_tok = try appendToken(c, .Builtin, "@OpaqueType");
1759 _ = try appendToken(c, .LParen, "(");
1760 const rparen_tok = try appendToken(c, .RParen, ")");
1761
1762 const call_node = try c.a().create(ast.Node.BuiltinCall);
1763 call_node.* = ast.Node.BuiltinCall{
1764 .base = ast.Node{ .id = ast.Node.Id.BuiltinCall },
1765 .builtin_token = builtin_tok,
1766 .params = ast.Node.BuiltinCall.ParamList.init(c.a()),
1767 .rparen_token = rparen_tok,
1768 };
1769 return &call_node.base;
1770}
1771
1462const RestorePoint = struct {1772const RestorePoint = struct {
1463 c: *Context,1773 c: *Context,
1464 token_index: ast.TokenIndex,1774 token_index: ast.TokenIndex,
...@@ -1583,6 +1893,19 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour...@@ -1583,6 +1893,19 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
1583 const typedef_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl)));1893 const typedef_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl)));
1584 return appendIdentifier(rp.c, typedef_name);1894 return appendIdentifier(rp.c, typedef_name);
1585 },1895 },
1896 .Record => {
1897 const record_ty = @ptrCast(*const ZigClangRecordType, ty);
1898
1899 const record_decl = ZigClangRecordType_getDecl(record_ty);
1900 if (try getContainerName(rp.c, record_decl)) |name|
1901 return appendIdentifier(rp.c, name)
1902 else
1903 return transRecordDecl(rp.c, record_decl);
1904 },
1905 .Elaborated => {
1906 const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ty);
1907 return transQualType(rp, ZigClangElaboratedType_getNamedType(elaborated_ty), source_loc);
1908 },
1586 else => {1909 else => {
1587 const type_name = rp.c.str(ZigClangType_getTypeClassName(ty));1910 const type_name = rp.c.str(ZigClangType_getTypeClassName(ty));
1588 return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{}'", .{type_name});1911 return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{}'", .{type_name});
...@@ -1590,6 +1913,24 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour...@@ -1590,6 +1913,24 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
1590 }1913 }
1591}1914}
15921915
1916fn getContainerName(c: *Context, record_decl: *const ZigClangRecordDecl) !?[]const u8 {
1917 const bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl)));
1918
1919 const container_kind_name = if (ZigClangRecordDecl_isUnion(record_decl))
1920 "union"
1921 else if (ZigClangRecordDecl_isStruct(record_decl))
1922 "struct"
1923 else {
1924 try emitWarning(c, ZigClangRecordDecl_getLocation(record_decl), "record {} is not a struct or union", .{bare_name});
1925 return null;
1926 };
1927
1928 if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0)
1929 return null;
1930
1931 return try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name });
1932}
1933
1593fn isCVoid(qt: ZigClangQualType) bool {1934fn isCVoid(qt: ZigClangQualType) bool {
1594 const ty = ZigClangQualType_getTypePtr(qt);1935 const ty = ZigClangQualType_getTypePtr(qt);
1595 if (ZigClangType_getTypeClass(ty) == .Builtin) {1936 if (ZigClangType_getTypeClass(ty) == .Builtin) {
test/translate_c.zig+44-8
...@@ -186,9 +186,40 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -186,9 +186,40 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
186 \\pub export var arr2: [*c]u8 = "hello";186 \\pub export var arr2: [*c]u8 = "hello";
187 });187 });
188188
189 cases.add_2("array initializer expr",
190 \\static void foo(void){
191 \\ char arr[10] ={1};
192 \\ char *arr1[10] ={0};
193 \\}
194 , &[_][]const u8{
195 \\pub fn foo() void {
196 \\ var arr: [10]u8 = .{
197 \\ @as(u8, 1),
198 \\ } ++ .{0} ** 9;
199 \\ var arr1: [10][*c]u8 = .{
200 \\ null,
201 \\ } ++ .{null} ** 9;
202 \\}
203 });
204
205 cases.add_2("field struct",
206 \\union OpenGLProcs {
207 \\ struct {
208 \\ int Clear;
209 \\ } gl;
210 \\};
211 , &[_][]const u8{
212 \\pub const union_OpenGLProcs = extern union {
213 \\ gl: extern struct {
214 \\ Clear: c_int,
215 \\ },
216 \\};
217 \\pub const OpenGLProcs = union_OpenGLProcs;
218 });
219
189 /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////220 /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
190221
191 cases.add("typedef of function in struct field",222 cases.add_both("typedef of function in struct field",
192 \\typedef void lws_callback_function(void);223 \\typedef void lws_callback_function(void);
193 \\struct Foo {224 \\struct Foo {
194 \\ void (*func)(void);225 \\ void (*func)(void);
...@@ -202,7 +233,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -202,7 +233,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
202 \\};233 \\};
203 });234 });
204235
205 cases.add("pointer to struct demoted to opaque due to bit fields",236 cases.add_both("pointer to struct demoted to opaque due to bit fields",
206 \\struct Foo {237 \\struct Foo {
207 \\ unsigned int: 1;238 \\ unsigned int: 1;
208 \\};239 \\};
...@@ -210,7 +241,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -210,7 +241,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
210 \\ struct Foo *foo;241 \\ struct Foo *foo;
211 \\};242 \\};
212 , &[_][]const u8{243 , &[_][]const u8{
213 \\pub const struct_Foo = @OpaqueType();244 \\pub const struct_Foo = @OpaqueType()
245 ,
214 \\pub const struct_Bar = extern struct {246 \\pub const struct_Bar = extern struct {
215 \\ foo: ?*struct_Foo,247 \\ foo: ?*struct_Foo,
216 \\};248 \\};
...@@ -359,7 +391,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -359,7 +391,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
359 \\}391 \\}
360 });392 });
361393
362 cases.add("double define struct",394 cases.add_both("double define struct",
363 \\typedef struct Bar Bar;395 \\typedef struct Bar Bar;
364 \\typedef struct Foo Foo;396 \\typedef struct Foo Foo;
365 \\397 \\
...@@ -374,10 +406,14 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -374,10 +406,14 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
374 \\pub const struct_Foo = extern struct {406 \\pub const struct_Foo = extern struct {
375 \\ a: [*c]Foo,407 \\ a: [*c]Foo,
376 \\};408 \\};
409 ,
377 \\pub const Foo = struct_Foo;410 \\pub const Foo = struct_Foo;
411 ,
378 \\pub const struct_Bar = extern struct {412 \\pub const struct_Bar = extern struct {
379 \\ a: [*c]Foo,413 \\ a: [*c]Foo,
380 \\};414 \\};
415 ,
416 \\pub const Bar = struct_Bar;
381 });417 });
382418
383 cases.addAllowWarnings("simple data types",419 cases.addAllowWarnings("simple data types",
...@@ -454,7 +490,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -454,7 +490,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
454 \\pub extern fn foo(noalias bar: ?*c_void, noalias arg1: ?*c_void) void;490 \\pub extern fn foo(noalias bar: ?*c_void, noalias arg1: ?*c_void) void;
455 });491 });
456492
457 cases.add("simple struct",493 cases.add_both("simple struct",
458 \\struct Foo {494 \\struct Foo {
459 \\ int x;495 \\ int x;
460 \\ char *y;496 \\ char *y;
...@@ -506,7 +542,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -506,7 +542,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
506 \\pub extern fn func(array: [*c]c_int) void;542 \\pub extern fn func(array: [*c]c_int) void;
507 });543 });
508544
509 cases.add("self referential struct with function pointer",545 cases.add_both("self referential struct with function pointer",
510 \\struct Foo {546 \\struct Foo {
511 \\ void (*derp)(struct Foo *foo);547 \\ void (*derp)(struct Foo *foo);
512 \\};548 \\};
...@@ -518,7 +554,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -518,7 +554,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
518 \\pub const Foo = struct_Foo;554 \\pub const Foo = struct_Foo;
519 });555 });
520556
521 cases.add("struct prototype used in func",557 cases.add_both("struct prototype used in func",
522 \\struct Foo;558 \\struct Foo;
523 \\struct Foo *some_func(struct Foo *foo, int x);559 \\struct Foo *some_func(struct Foo *foo, int x);
524 , &[_][]const u8{560 , &[_][]const u8{
...@@ -550,7 +586,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -550,7 +586,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
550 \\pub const THING2 = THING1;586 \\pub const THING2 = THING1;
551 });587 });
552588
553 cases.add("circular struct definitions",589 cases.add_both("circular struct definitions",
554 \\struct Bar;590 \\struct Bar;
555 \\591 \\
556 \\struct Foo {592 \\struct Foo {