authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-07-31 18:53:05-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-07-31 18:53:05-07:00
log7c5ee3efde6d948205c6f6eaa7ab52bda3715fea
tree8e43dfb45e509857ea980344577db96dd4bc4afb
parentc08effc20abe2595ba5c83e25b78c274ec9c58ec
parent1cc74f3cae32bc5c002868d7d53af4e14f5a9ce6
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #20883 from ehaas/aro-translate-c-no-panic

aro-translate-c improvements

8 files changed, 234 insertions(+), 88 deletions(-)

lib/compiler/aro_translate_c.zig+186-49
......@@ -78,6 +78,17 @@ fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: ZigNode) !void {
7878 }
7979}
8080
81fn fail(
82 c: *Context,
83 err: anytype,
84 source_loc: TokenIndex,
85 comptime format: []const u8,
86 args: anytype,
87) (@TypeOf(err) || error{OutOfMemory}) {
88 try warn(c, &c.global_scope.base, source_loc, format, args);
89 return err;
90}
91
8192fn failDecl(c: *Context, loc: TokenIndex, name: []const u8, comptime format: []const u8, args: anytype) Error!void {
8293 // location
8394 // pub const name = @compileError(msg);
......@@ -185,7 +196,7 @@ fn prepopulateGlobalNameTable(c: *Context) !void {
185196 for (c.tree.root_decls) |node| {
186197 const data = node_data[@intFromEnum(node)];
187198 switch (node_tags[@intFromEnum(node)]) {
188 .typedef => @panic("TODO"),
199 .typedef => {},
189200
190201 .struct_decl_two,
191202 .union_decl_two,
......@@ -243,6 +254,7 @@ fn transTopLevelDecls(c: *Context) !void {
243254fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {
244255 const node_tags = c.tree.nodes.items(.tag);
245256 const node_data = c.tree.nodes.items(.data);
257 const node_ty = c.tree.nodes.items(.ty);
246258 const data = node_data[@intFromEnum(decl)];
247259 switch (node_tags[@intFromEnum(decl)]) {
248260 .typedef => {
......@@ -252,17 +264,12 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {
252264 .struct_decl_two,
253265 .union_decl_two,
254266 => {
255 var fields = [2]NodeIndex{ data.bin.lhs, data.bin.rhs };
256 var field_count: u2 = 0;
257 if (fields[0] != .none) field_count += 1;
258 if (fields[1] != .none) field_count += 1;
259 try transRecordDecl(c, scope, decl, fields[0..field_count]);
267 try transRecordDecl(c, scope, node_ty[@intFromEnum(decl)]);
260268 },
261269 .struct_decl,
262270 .union_decl,
263271 => {
264 const fields = c.tree.data[data.range.start..data.range.end];
265 try transRecordDecl(c, scope, decl, fields);
272 try transRecordDecl(c, scope, node_ty[@intFromEnum(decl)]);
266273 },
267274
268275 .enum_decl_two => {
......@@ -270,11 +277,13 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {
270277 var field_count: u8 = 0;
271278 if (fields[0] != .none) field_count += 1;
272279 if (fields[1] != .none) field_count += 1;
273 try transEnumDecl(c, scope, decl, fields[0..field_count]);
280 const enum_decl = node_ty[@intFromEnum(decl)].canonicalize(.standard).data.@"enum";
281 try transEnumDecl(c, scope, enum_decl, fields[0..field_count]);
274282 },
275283 .enum_decl => {
276284 const fields = c.tree.data[data.range.start..data.range.end];
277 try transEnumDecl(c, scope, decl, fields);
285 const enum_decl = node_ty[@intFromEnum(decl)].canonicalize(.standard).data.@"enum";
286 try transEnumDecl(c, scope, enum_decl, fields);
278287 },
279288
280289 .enum_field_decl,
......@@ -294,7 +303,7 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {
294303 .inline_fn_def,
295304 .inline_static_fn_def,
296305 => {
297 try transFnDecl(c, decl);
306 try transFnDecl(c, decl, true);
298307 },
299308
300309 .@"var",
......@@ -304,15 +313,51 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {
304313 .threadlocal_extern_var,
305314 .threadlocal_static_var,
306315 => {
307 try transVarDecl(c, decl, null);
316 try transVarDecl(c, decl);
308317 },
309318 .static_assert => try warn(c, &c.global_scope.base, 0, "ignoring _Static_assert declaration", .{}),
310319 else => unreachable,
311320 }
312321}
313322
314fn transTypeDef(_: *Context, _: *Scope, _: NodeIndex) Error!void {
315 @panic("TODO");
323fn transTypeDef(c: *Context, scope: *Scope, typedef_decl: NodeIndex) Error!void {
324 const ty = c.tree.nodes.items(.ty)[@intFromEnum(typedef_decl)];
325 const data = c.tree.nodes.items(.data)[@intFromEnum(typedef_decl)];
326
327 const toplevel = scope.id == .root;
328 const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined;
329
330 var name: []const u8 = c.tree.tokSlice(data.decl.name);
331 try c.typedefs.put(c.gpa, name, {});
332
333 if (!toplevel) name = try bs.makeMangledName(c, name);
334
335 const typedef_loc = data.decl.name;
336 const init_node = transType(c, scope, ty, .standard, typedef_loc) catch |err| switch (err) {
337 error.UnsupportedType => {
338 return failDecl(c, typedef_loc, name, "unable to resolve typedef child type", .{});
339 },
340 error.OutOfMemory => |e| return e,
341 };
342
343 const payload = try c.arena.create(ast.Payload.SimpleVarDecl);
344 payload.* = .{
345 .base = .{ .tag = ([2]ZigTag{ .var_simple, .pub_var_simple })[@intFromBool(toplevel)] },
346 .data = .{
347 .name = name,
348 .init = init_node,
349 },
350 };
351 const node = ZigNode.initPayload(&payload.base);
352
353 if (toplevel) {
354 try addTopLevelDecl(c, name, node);
355 } else {
356 try scope.appendNode(node);
357 if (node.tag() != .pub_var_simple) {
358 try bs.discardVariable(c, name);
359 }
360 }
316361}
317362
318363fn mangleWeakGlobalName(c: *Context, want_name: []const u8) ![]const u8 {
......@@ -330,16 +375,14 @@ fn mangleWeakGlobalName(c: *Context, want_name: []const u8) ![]const u8 {
330375 return cur_name;
331376}
332377
333fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nodes: []const NodeIndex) Error!void {
334 const node_types = c.tree.nodes.items(.ty);
335 const raw_record_ty = node_types[@intFromEnum(record_node)];
336 const record_decl = raw_record_ty.getRecord().?;
378fn transRecordDecl(c: *Context, scope: *Scope, record_ty: Type) Error!void {
379 const record_decl = record_ty.getRecord().?;
337380 if (c.decl_table.get(@intFromPtr(record_decl))) |_|
338381 return; // Avoid processing this decl twice
339382 const toplevel = scope.id == .root;
340383 const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined;
341384
342 const container_kind: ZigTag = if (raw_record_ty.is(.@"union")) .@"union" else .@"struct";
385 const container_kind: ZigTag = if (record_ty.is(.@"union")) .@"union" else .@"struct";
343386 const container_kind_name: []const u8 = @tagName(container_kind);
344387
345388 var is_unnamed = false;
......@@ -350,7 +393,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod
350393 bare_name = typedef_name;
351394 name = typedef_name;
352395 } else {
353 if (raw_record_ty.isAnonymousRecord(c.comp)) {
396 if (record_ty.isAnonymousRecord(c.comp)) {
354397 bare_name = try std.fmt.allocPrint(c.arena, "unnamed_{d}", .{c.getMangle()});
355398 is_unnamed = true;
356399 }
......@@ -364,6 +407,11 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod
364407
365408 const is_pub = toplevel and !is_unnamed;
366409 const init_node = blk: {
410 if (record_decl.isIncomplete()) {
411 try c.opaque_demotes.put(c.gpa, @intFromPtr(record_decl), {});
412 break :blk ZigTag.opaque_literal.init();
413 }
414
367415 var fields = try std.ArrayList(ast.Payload.Record.Field).initCapacity(c.gpa, record_decl.fields.len);
368416 defer fields.deinit();
369417
......@@ -377,17 +425,10 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod
377425 // layout, then we can just use a simple `extern` type. If it does have attributes,
378426 // then we need to inspect the layout and assign an `align` value for each field.
379427 const has_alignment_attributes = record_decl.field_attributes != null or
380 raw_record_ty.hasAttribute(.@"packed") or
381 raw_record_ty.hasAttribute(.aligned);
428 record_ty.hasAttribute(.@"packed") or
429 record_ty.hasAttribute(.aligned);
382430 const head_field_alignment: ?c_uint = if (has_alignment_attributes) headFieldAlignment(record_decl) else null;
383431
384 // Iterate over field nodes so that we translate any type decls included in this record decl.
385 // TODO: Move this logic into `fn transType()` instead of handling decl translation here.
386 for (field_nodes) |field_node| {
387 const field_raw_ty = node_types[@intFromEnum(field_node)];
388 if (field_raw_ty.isEnumOrRecord()) try transDecl(c, scope, field_node);
389 }
390
391432 for (record_decl.fields, 0..) |field, field_index| {
392433 const field_loc = field.name_tok;
393434
......@@ -473,7 +514,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod
473514 }
474515}
475516
476fn transFnDecl(c: *Context, fn_decl: NodeIndex) Error!void {
517fn transFnDecl(c: *Context, fn_decl: NodeIndex, is_pub: bool) Error!void {
477518 const raw_ty = c.tree.nodes.items(.ty)[@intFromEnum(fn_decl)];
478519 const fn_ty = raw_ty.canonicalize(.standard);
479520 const node_data = c.tree.nodes.items(.data)[@intFromEnum(fn_decl)];
......@@ -498,6 +539,7 @@ fn transFnDecl(c: *Context, fn_decl: NodeIndex) Error!void {
498539
499540 else => unreachable,
500541 },
542 .is_pub = is_pub,
501543 };
502544
503545 const proto_node = transFnType(c, &c.global_scope.base, raw_ty, fn_ty, fn_decl_loc, proto_ctx) catch |err| switch (err) {
......@@ -566,22 +608,22 @@ fn transFnDecl(c: *Context, fn_decl: NodeIndex) Error!void {
566608 return addTopLevelDecl(c, fn_name, proto_node);
567609}
568610
569fn transVarDecl(_: *Context, _: NodeIndex, _: ?usize) Error!void {
570 @panic("TODO");
611fn transVarDecl(c: *Context, node: NodeIndex) Error!void {
612 const data = c.tree.nodes.items(.data)[@intFromEnum(node)];
613 const name = c.tree.tokSlice(data.decl.name);
614 return failDecl(c, data.decl.name, name, "unable to translate variable declaration", .{});
571615}
572616
573fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes: []const NodeIndex) Error!void {
574 const node_types = c.tree.nodes.items(.ty);
575 const ty = node_types[@intFromEnum(enum_decl)];
576 if (c.decl_table.get(@intFromPtr(ty.data.@"enum"))) |_|
617fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const Type.Enum, field_nodes: []const NodeIndex) Error!void {
618 if (c.decl_table.get(@intFromPtr(enum_decl))) |_|
577619 return; // Avoid processing this decl twice
578620 const toplevel = scope.id == .root;
579621 const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined;
580622
581623 var is_unnamed = false;
582 var bare_name: []const u8 = c.mapper.lookup(ty.data.@"enum".name);
624 var bare_name: []const u8 = c.mapper.lookup(enum_decl.name);
583625 var name = bare_name;
584 if (c.unnamed_typedefs.get(@intFromPtr(ty.data.@"enum"))) |typedef_name| {
626 if (c.unnamed_typedefs.get(@intFromPtr(enum_decl))) |typedef_name| {
585627 bare_name = typedef_name;
586628 name = typedef_name;
587629 } else {
......@@ -592,10 +634,10 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes:
592634 name = try std.fmt.allocPrint(c.arena, "enum_{s}", .{bare_name});
593635 }
594636 if (!toplevel) name = try bs.makeMangledName(c, name);
595 try c.decl_table.putNoClobber(c.gpa, @intFromPtr(ty.data.@"enum"), name);
637 try c.decl_table.putNoClobber(c.gpa, @intFromPtr(enum_decl), name);
596638
597 const enum_type_node = if (!ty.data.@"enum".isIncomplete()) blk: {
598 for (ty.data.@"enum".fields, field_nodes) |field, field_node| {
639 const enum_type_node = if (!enum_decl.isIncomplete()) blk: {
640 for (enum_decl.fields, field_nodes) |field, field_node| {
599641 var enum_val_name: []const u8 = c.mapper.lookup(field.name);
600642 if (!toplevel) {
601643 enum_val_name = try bs.makeMangledName(c, enum_val_name);
......@@ -621,14 +663,14 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes:
621663 }
622664 }
623665
624 break :blk transType(c, scope, ty.data.@"enum".tag_ty, .standard, 0) catch |err| switch (err) {
666 break :blk transType(c, scope, enum_decl.tag_ty, .standard, 0) catch |err| switch (err) {
625667 error.UnsupportedType => {
626668 return failDecl(c, 0, name, "unable to translate enum integer type", .{});
627669 },
628670 else => |e| return e,
629671 };
630672 } else blk: {
631 try c.opaque_demotes.put(c.gpa, @intFromPtr(ty.data.@"enum"), {});
673 try c.opaque_demotes.put(c.gpa, @intFromPtr(enum_decl), {});
632674 break :blk ZigTag.opaque_literal.init();
633675 };
634676
......@@ -654,8 +696,21 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes:
654696 }
655697}
656698
699fn getTypeStr(c: *Context, ty: Type) ![]const u8 {
700 var buf: std.ArrayListUnmanaged(u8) = .{};
701 defer buf.deinit(c.gpa);
702 const w = buf.writer(c.gpa);
703 try ty.print(c.mapper, c.comp.langopts, w);
704 return c.arena.dupe(u8, buf.items);
705}
706
657707fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualHandling, source_loc: TokenIndex) TypeError!ZigNode {
658708 const ty = raw_ty.canonicalize(qual_handling);
709 if (ty.qual.atomic) {
710 const type_name = try getTypeStr(c, ty);
711 return fail(c, error.UnsupportedType, source_loc, "unsupported type: '{s}'", .{type_name});
712 }
713
659714 switch (ty.specifier) {
660715 .void => return ZigTag.type.create(c.arena, "anyopaque"),
661716 .bool => return ZigTag.type.create(c.arena, "bool"),
......@@ -678,13 +733,53 @@ fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualH
678733 .long_double => return ZigTag.type.create(c.arena, "c_longdouble"),
679734 .float80 => return ZigTag.type.create(c.arena, "f80"),
680735 .float128 => return ZigTag.type.create(c.arena, "f128"),
681 .@"enum" => @panic("TODO"),
682 .pointer,
683 .unspecified_variable_len_array,
736 .@"enum" => {
737 const enum_decl = ty.data.@"enum";
738 var trans_scope = scope;
739 if (enum_decl.name != .empty) {
740 const decl_name = c.mapper.lookup(enum_decl.name);
741 if (c.weak_global_names.contains(decl_name)) trans_scope = &c.global_scope.base;
742 }
743 try transEnumDecl(c, trans_scope, enum_decl, &.{});
744 return ZigTag.identifier.create(c.arena, c.decl_table.get(@intFromPtr(enum_decl)).?);
745 },
746 .pointer => {
747 const child_type = ty.elemType();
748
749 const is_fn_proto = child_type.isFunc();
750 const is_const = is_fn_proto or child_type.isConst();
751 const is_volatile = child_type.qual.@"volatile";
752 const elem_type = try transType(c, scope, child_type, qual_handling, source_loc);
753 const ptr_info = .{
754 .is_const = is_const,
755 .is_volatile = is_volatile,
756 .elem_type = elem_type,
757 };
758 if (is_fn_proto or
759 typeIsOpaque(c, child_type) or
760 typeWasDemotedToOpaque(c, child_type))
761 {
762 const ptr = try ZigTag.single_pointer.create(c.arena, ptr_info);
763 return ZigTag.optional_type.create(c.arena, ptr);
764 }
765
766 return ZigTag.c_pointer.create(c.arena, ptr_info);
767 },
768 .unspecified_variable_len_array, .incomplete_array => {
769 const child_type = ty.elemType();
770 const is_const = child_type.qual.@"const";
771 const is_volatile = child_type.qual.@"volatile";
772 const elem_type = try transType(c, scope, child_type, qual_handling, source_loc);
773
774 return ZigTag.c_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type });
775 },
684776 .array,
685777 .static_array,
686 .incomplete_array,
687 => @panic("TODO"),
778 => {
779 const size = ty.arrayLen().?;
780 const elem_type = try transType(c, scope, ty.elemType(), qual_handling, source_loc);
781 return ZigTag.array_type.create(c.arena, .{ .len = size, .elem_type = elem_type });
782 },
688783 .func,
689784 .var_args_func,
690785 .old_style_func,
......@@ -698,6 +793,7 @@ fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualH
698793 const name_id = c.mapper.lookup(record_decl.name);
699794 if (c.weak_global_names.contains(name_id)) trans_scope = &c.global_scope.base;
700795 }
796 try transRecordDecl(c, trans_scope, ty);
701797 const name = c.decl_table.get(@intFromPtr(ty.data.record)).?;
702798 return ZigTag.identifier.create(c.arena, name);
703799 },
......@@ -927,7 +1023,9 @@ fn transFnType(
9271023}
9281024
9291025fn transStmt(c: *Context, node: NodeIndex) TransError!ZigNode {
930 return transExpr(c, node, .unused);
1026 _ = c;
1027 _ = node;
1028 return error.UnsupportedTranslation;
9311029}
9321030
9331031fn transCompoundStmtInline(c: *Context, compound: NodeIndex, block: *Scope.Block) TransError!void {
......@@ -952,6 +1050,45 @@ fn transCompoundStmtInline(c: *Context, compound: NodeIndex, block: *Scope.Block
9521050 }
9531051}
9541052
1053fn recordHasBitfield(record: *const Type.Record) bool {
1054 if (record.isIncomplete()) return false;
1055 for (record.fields) |field| {
1056 if (!field.isRegularField()) return true;
1057 }
1058 return false;
1059}
1060
1061fn typeIsOpaque(c: *Context, ty: Type) bool {
1062 return switch (ty.specifier) {
1063 .void => true,
1064 .@"struct", .@"union" => recordHasBitfield(ty.getRecord().?),
1065 .typeof_type => typeIsOpaque(c, ty.data.sub_type.*),
1066 .typeof_expr => typeIsOpaque(c, ty.data.expr.ty),
1067 .attributed => typeIsOpaque(c, ty.data.attributed.base),
1068 else => false,
1069 };
1070}
1071
1072fn typeWasDemotedToOpaque(c: *Context, ty: Type) bool {
1073 switch (ty.specifier) {
1074 .@"struct", .@"union" => {
1075 const record = ty.getRecord().?;
1076 if (c.opaque_demotes.contains(@intFromPtr(record))) return true;
1077 for (record.fields) |field| {
1078 if (typeWasDemotedToOpaque(c, field.ty)) return true;
1079 }
1080 return false;
1081 },
1082
1083 .@"enum" => return c.opaque_demotes.contains(@intFromPtr(ty.data.@"enum")),
1084
1085 .typeof_type => return typeWasDemotedToOpaque(c, ty.data.sub_type.*),
1086 .typeof_expr => return typeWasDemotedToOpaque(c, ty.data.expr.ty),
1087 .attributed => return typeWasDemotedToOpaque(c, ty.data.attributed.base),
1088 else => return false,
1089 }
1090}
1091
9551092fn transCompoundStmt(c: *Context, scope: *Scope, compound: NodeIndex) TransError!ZigNode {
9561093 var block_scope = try Scope.Block.init(c, scope, false);
9571094 defer block_scope.deinit();
test/cases/translate_c/atomic types.c created+8
......@@ -0,0 +1,8 @@
1typedef _Atomic(int) AtomicInt;
2
3// translate-c
4// target=x86_64-linux
5// c_frontend=aro
6//
7// tmp.c:1:22: warning: unsupported type: '_Atomic(int)'
8// pub const AtomicInt = @compileError("unable to resolve typedef child type");
test/cases/translate_c/empty declaration.c created+6
......@@ -0,0 +1,6 @@
1;
2
3// translate-c
4// c_frontend=clang,aro
5//
6//
\ No newline at end of file
test/cases/translate_c/function prototype with parenthesis.c created+10
......@@ -0,0 +1,10 @@
1void (f0) (void *L);
2void ((f1)) (void *L);
3void (((f2))) (void *L);
4
5// translate-c
6// c_frontend=clang,aro
7//
8// pub extern fn f0(L: ?*anyopaque) void;
9// pub extern fn f1(L: ?*anyopaque) void;
10// pub extern fn f2(L: ?*anyopaque) void;
test/cases/translate_c/noreturn attribute.c created+6
......@@ -0,0 +1,6 @@
1void foo(void) __attribute__((noreturn));
2
3// translate-c
4// c_frontend=aro,clang
5//
6// pub extern fn foo() noreturn;
test/cases/translate_c/simple function prototypes.c created+8
......@@ -0,0 +1,8 @@
1void __attribute__((noreturn)) foo(void);
2int bar(void);
3
4// translate-c
5// c_frontend=clang,aro
6//
7// pub extern fn foo() noreturn;
8// pub extern fn bar() c_int;
test/cases/translate_c/struct prototype used in func.c created+10
......@@ -0,0 +1,10 @@
1struct Foo;
2struct Foo *some_func(struct Foo *foo, int x);
3
4// translate-c
5// c_frontend=clang,aro
6//
7// pub const struct_Foo = opaque {};
8// pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo;
9//
10// pub const Foo = struct_Foo;
test/translate_c.zig-39
......@@ -494,16 +494,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
494494 \\};
495495 });
496496
497 cases.add("function prototype with parenthesis",
498 \\void (f0) (void *L);
499 \\void ((f1)) (void *L);
500 \\void (((f2))) (void *L);
501 , &[_][]const u8{
502 \\pub extern fn f0(L: ?*anyopaque) void;
503 \\pub extern fn f1(L: ?*anyopaque) void;
504 \\pub extern fn f2(L: ?*anyopaque) void;
505 });
506
507497 cases.add("array initializer w/ typedef",
508498 \\typedef unsigned char uuid_t[16];
509499 \\static const uuid_t UUID_NULL __attribute__ ((unused)) = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
......@@ -529,10 +519,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
529519 \\};
530520 });
531521
532 cases.add("empty declaration",
533 \\;
534 , &[_][]const u8{""});
535
536522 cases.add("#define hex literal with capital X",
537523 \\#define VAL 0XF00D
538524 , &[_][]const u8{
......@@ -658,14 +644,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
658644 \\pub export fn my_fn() linksection("NEAR,.data") void {}
659645 });
660646
661 cases.add("simple function prototypes",
662 \\void __attribute__((noreturn)) foo(void);
663 \\int bar(void);
664 , &[_][]const u8{
665 \\pub extern fn foo() noreturn;
666 \\pub extern fn bar() c_int;
667 });
668
669647 cases.add("simple var decls",
670648 \\void foo(void) {
671649 \\ int a;
......@@ -796,12 +774,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
796774 \\}
797775 });
798776
799 cases.add("noreturn attribute",
800 \\void foo(void) __attribute__((noreturn));
801 , &[_][]const u8{
802 \\pub extern fn foo() noreturn;
803 });
804
805777 cases.add("always_inline attribute",
806778 \\__attribute__((always_inline)) int foo() {
807779 \\ return 5;
......@@ -901,17 +873,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
901873 \\pub const Foo = struct_Foo;
902874 });
903875
904 cases.add("struct prototype used in func",
905 \\struct Foo;
906 \\struct Foo *some_func(struct Foo *foo, int x);
907 , &[_][]const u8{
908 \\pub const struct_Foo = opaque {};
909 ,
910 \\pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo;
911 ,
912 \\pub const Foo = struct_Foo;
913 });
914
915876 cases.add("#define an unsigned integer literal",
916877 \\#define CHANNEL_COUNT 24
917878 , &[_][]const u8{