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 {...@@ -78,6 +78,17 @@ fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: ZigNode) !void {
78 }78 }
79}79}
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
81fn failDecl(c: *Context, loc: TokenIndex, name: []const u8, comptime format: []const u8, args: anytype) Error!void {92fn failDecl(c: *Context, loc: TokenIndex, name: []const u8, comptime format: []const u8, args: anytype) Error!void {
82 // location93 // location
83 // pub const name = @compileError(msg);94 // pub const name = @compileError(msg);
...@@ -185,7 +196,7 @@ fn prepopulateGlobalNameTable(c: *Context) !void {...@@ -185,7 +196,7 @@ fn prepopulateGlobalNameTable(c: *Context) !void {
185 for (c.tree.root_decls) |node| {196 for (c.tree.root_decls) |node| {
186 const data = node_data[@intFromEnum(node)];197 const data = node_data[@intFromEnum(node)];
187 switch (node_tags[@intFromEnum(node)]) {198 switch (node_tags[@intFromEnum(node)]) {
188 .typedef => @panic("TODO"),199 .typedef => {},
189200
190 .struct_decl_two,201 .struct_decl_two,
191 .union_decl_two,202 .union_decl_two,
...@@ -243,6 +254,7 @@ fn transTopLevelDecls(c: *Context) !void {...@@ -243,6 +254,7 @@ fn transTopLevelDecls(c: *Context) !void {
243fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {254fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {
244 const node_tags = c.tree.nodes.items(.tag);255 const node_tags = c.tree.nodes.items(.tag);
245 const node_data = c.tree.nodes.items(.data);256 const node_data = c.tree.nodes.items(.data);
257 const node_ty = c.tree.nodes.items(.ty);
246 const data = node_data[@intFromEnum(decl)];258 const data = node_data[@intFromEnum(decl)];
247 switch (node_tags[@intFromEnum(decl)]) {259 switch (node_tags[@intFromEnum(decl)]) {
248 .typedef => {260 .typedef => {
...@@ -252,17 +264,12 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {...@@ -252,17 +264,12 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {
252 .struct_decl_two,264 .struct_decl_two,
253 .union_decl_two,265 .union_decl_two,
254 => {266 => {
255 var fields = [2]NodeIndex{ data.bin.lhs, data.bin.rhs };267 try transRecordDecl(c, scope, node_ty[@intFromEnum(decl)]);
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]);
260 },268 },
261 .struct_decl,269 .struct_decl,
262 .union_decl,270 .union_decl,
263 => {271 => {
264 const fields = c.tree.data[data.range.start..data.range.end];272 try transRecordDecl(c, scope, node_ty[@intFromEnum(decl)]);
265 try transRecordDecl(c, scope, decl, fields);
266 },273 },
267274
268 .enum_decl_two => {275 .enum_decl_two => {
...@@ -270,11 +277,13 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {...@@ -270,11 +277,13 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {
270 var field_count: u8 = 0;277 var field_count: u8 = 0;
271 if (fields[0] != .none) field_count += 1;278 if (fields[0] != .none) field_count += 1;
272 if (fields[1] != .none) field_count += 1;279 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]);
274 },282 },
275 .enum_decl => {283 .enum_decl => {
276 const fields = c.tree.data[data.range.start..data.range.end];284 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);
278 },287 },
279288
280 .enum_field_decl,289 .enum_field_decl,
...@@ -294,7 +303,7 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {...@@ -294,7 +303,7 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {
294 .inline_fn_def,303 .inline_fn_def,
295 .inline_static_fn_def,304 .inline_static_fn_def,
296 => {305 => {
297 try transFnDecl(c, decl);306 try transFnDecl(c, decl, true);
298 },307 },
299308
300 .@"var",309 .@"var",
...@@ -304,15 +313,51 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {...@@ -304,15 +313,51 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {
304 .threadlocal_extern_var,313 .threadlocal_extern_var,
305 .threadlocal_static_var,314 .threadlocal_static_var,
306 => {315 => {
307 try transVarDecl(c, decl, null);316 try transVarDecl(c, decl);
308 },317 },
309 .static_assert => try warn(c, &c.global_scope.base, 0, "ignoring _Static_assert declaration", .{}),318 .static_assert => try warn(c, &c.global_scope.base, 0, "ignoring _Static_assert declaration", .{}),
310 else => unreachable,319 else => unreachable,
311 }320 }
312}321}
313322
314fn transTypeDef(_: *Context, _: *Scope, _: NodeIndex) Error!void {323fn transTypeDef(c: *Context, scope: *Scope, typedef_decl: NodeIndex) Error!void {
315 @panic("TODO");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 }
316}361}
317362
318fn mangleWeakGlobalName(c: *Context, want_name: []const u8) ![]const u8 {363fn mangleWeakGlobalName(c: *Context, want_name: []const u8) ![]const u8 {
...@@ -330,16 +375,14 @@ fn mangleWeakGlobalName(c: *Context, want_name: []const u8) ![]const u8 {...@@ -330,16 +375,14 @@ fn mangleWeakGlobalName(c: *Context, want_name: []const u8) ![]const u8 {
330 return cur_name;375 return cur_name;
331}376}
332377
333fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nodes: []const NodeIndex) Error!void {378fn transRecordDecl(c: *Context, scope: *Scope, record_ty: Type) Error!void {
334 const node_types = c.tree.nodes.items(.ty);379 const record_decl = record_ty.getRecord().?;
335 const raw_record_ty = node_types[@intFromEnum(record_node)];
336 const record_decl = raw_record_ty.getRecord().?;
337 if (c.decl_table.get(@intFromPtr(record_decl))) |_|380 if (c.decl_table.get(@intFromPtr(record_decl))) |_|
338 return; // Avoid processing this decl twice381 return; // Avoid processing this decl twice
339 const toplevel = scope.id == .root;382 const toplevel = scope.id == .root;
340 const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined;383 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";
343 const container_kind_name: []const u8 = @tagName(container_kind);386 const container_kind_name: []const u8 = @tagName(container_kind);
344387
345 var is_unnamed = false;388 var is_unnamed = false;
...@@ -350,7 +393,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod...@@ -350,7 +393,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod
350 bare_name = typedef_name;393 bare_name = typedef_name;
351 name = typedef_name;394 name = typedef_name;
352 } else {395 } else {
353 if (raw_record_ty.isAnonymousRecord(c.comp)) {396 if (record_ty.isAnonymousRecord(c.comp)) {
354 bare_name = try std.fmt.allocPrint(c.arena, "unnamed_{d}", .{c.getMangle()});397 bare_name = try std.fmt.allocPrint(c.arena, "unnamed_{d}", .{c.getMangle()});
355 is_unnamed = true;398 is_unnamed = true;
356 }399 }
...@@ -364,6 +407,11 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod...@@ -364,6 +407,11 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod
364407
365 const is_pub = toplevel and !is_unnamed;408 const is_pub = toplevel and !is_unnamed;
366 const init_node = blk: {409 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
367 var fields = try std.ArrayList(ast.Payload.Record.Field).initCapacity(c.gpa, record_decl.fields.len);415 var fields = try std.ArrayList(ast.Payload.Record.Field).initCapacity(c.gpa, record_decl.fields.len);
368 defer fields.deinit();416 defer fields.deinit();
369417
...@@ -377,17 +425,10 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod...@@ -377,17 +425,10 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod
377 // layout, then we can just use a simple `extern` type. If it does have attributes,425 // layout, then we can just use a simple `extern` type. If it does have attributes,
378 // then we need to inspect the layout and assign an `align` value for each field.426 // then we need to inspect the layout and assign an `align` value for each field.
379 const has_alignment_attributes = record_decl.field_attributes != null or427 const has_alignment_attributes = record_decl.field_attributes != null or
380 raw_record_ty.hasAttribute(.@"packed") or428 record_ty.hasAttribute(.@"packed") or
381 raw_record_ty.hasAttribute(.aligned);429 record_ty.hasAttribute(.aligned);
382 const head_field_alignment: ?c_uint = if (has_alignment_attributes) headFieldAlignment(record_decl) else null;430 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
391 for (record_decl.fields, 0..) |field, field_index| {432 for (record_decl.fields, 0..) |field, field_index| {
392 const field_loc = field.name_tok;433 const field_loc = field.name_tok;
393434
...@@ -473,7 +514,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod...@@ -473,7 +514,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod
473 }514 }
474}515}
475516
476fn transFnDecl(c: *Context, fn_decl: NodeIndex) Error!void {517fn transFnDecl(c: *Context, fn_decl: NodeIndex, is_pub: bool) Error!void {
477 const raw_ty = c.tree.nodes.items(.ty)[@intFromEnum(fn_decl)];518 const raw_ty = c.tree.nodes.items(.ty)[@intFromEnum(fn_decl)];
478 const fn_ty = raw_ty.canonicalize(.standard);519 const fn_ty = raw_ty.canonicalize(.standard);
479 const node_data = c.tree.nodes.items(.data)[@intFromEnum(fn_decl)];520 const node_data = c.tree.nodes.items(.data)[@intFromEnum(fn_decl)];
...@@ -498,6 +539,7 @@ fn transFnDecl(c: *Context, fn_decl: NodeIndex) Error!void {...@@ -498,6 +539,7 @@ fn transFnDecl(c: *Context, fn_decl: NodeIndex) Error!void {
498539
499 else => unreachable,540 else => unreachable,
500 },541 },
542 .is_pub = is_pub,
501 };543 };
502544
503 const proto_node = transFnType(c, &c.global_scope.base, raw_ty, fn_ty, fn_decl_loc, proto_ctx) catch |err| switch (err) {545 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 {...@@ -566,22 +608,22 @@ fn transFnDecl(c: *Context, fn_decl: NodeIndex) Error!void {
566 return addTopLevelDecl(c, fn_name, proto_node);608 return addTopLevelDecl(c, fn_name, proto_node);
567}609}
568610
569fn transVarDecl(_: *Context, _: NodeIndex, _: ?usize) Error!void {611fn transVarDecl(c: *Context, node: NodeIndex) Error!void {
570 @panic("TODO");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", .{});
571}615}
572616
573fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes: []const NodeIndex) Error!void {617fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const Type.Enum, field_nodes: []const NodeIndex) Error!void {
574 const node_types = c.tree.nodes.items(.ty);618 if (c.decl_table.get(@intFromPtr(enum_decl))) |_|
575 const ty = node_types[@intFromEnum(enum_decl)];
576 if (c.decl_table.get(@intFromPtr(ty.data.@"enum"))) |_|
577 return; // Avoid processing this decl twice619 return; // Avoid processing this decl twice
578 const toplevel = scope.id == .root;620 const toplevel = scope.id == .root;
579 const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined;621 const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined;
580622
581 var is_unnamed = false;623 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);
583 var name = bare_name;625 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| {
585 bare_name = typedef_name;627 bare_name = typedef_name;
586 name = typedef_name;628 name = typedef_name;
587 } else {629 } else {
...@@ -592,10 +634,10 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes:...@@ -592,10 +634,10 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes:
592 name = try std.fmt.allocPrint(c.arena, "enum_{s}", .{bare_name});634 name = try std.fmt.allocPrint(c.arena, "enum_{s}", .{bare_name});
593 }635 }
594 if (!toplevel) name = try bs.makeMangledName(c, name);636 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: {639 const enum_type_node = if (!enum_decl.isIncomplete()) blk: {
598 for (ty.data.@"enum".fields, field_nodes) |field, field_node| {640 for (enum_decl.fields, field_nodes) |field, field_node| {
599 var enum_val_name: []const u8 = c.mapper.lookup(field.name);641 var enum_val_name: []const u8 = c.mapper.lookup(field.name);
600 if (!toplevel) {642 if (!toplevel) {
601 enum_val_name = try bs.makeMangledName(c, enum_val_name);643 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:...@@ -621,14 +663,14 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes:
621 }663 }
622 }664 }
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) {
625 error.UnsupportedType => {667 error.UnsupportedType => {
626 return failDecl(c, 0, name, "unable to translate enum integer type", .{});668 return failDecl(c, 0, name, "unable to translate enum integer type", .{});
627 },669 },
628 else => |e| return e,670 else => |e| return e,
629 };671 };
630 } else blk: {672 } 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), {});
632 break :blk ZigTag.opaque_literal.init();674 break :blk ZigTag.opaque_literal.init();
633 };675 };
634676
...@@ -654,8 +696,21 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes:...@@ -654,8 +696,21 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes:
654 }696 }
655}697}
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
657fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualHandling, source_loc: TokenIndex) TypeError!ZigNode {707fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualHandling, source_loc: TokenIndex) TypeError!ZigNode {
658 const ty = raw_ty.canonicalize(qual_handling);708 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
659 switch (ty.specifier) {714 switch (ty.specifier) {
660 .void => return ZigTag.type.create(c.arena, "anyopaque"),715 .void => return ZigTag.type.create(c.arena, "anyopaque"),
661 .bool => return ZigTag.type.create(c.arena, "bool"),716 .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...@@ -678,13 +733,53 @@ fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualH
678 .long_double => return ZigTag.type.create(c.arena, "c_longdouble"),733 .long_double => return ZigTag.type.create(c.arena, "c_longdouble"),
679 .float80 => return ZigTag.type.create(c.arena, "f80"),734 .float80 => return ZigTag.type.create(c.arena, "f80"),
680 .float128 => return ZigTag.type.create(c.arena, "f128"),735 .float128 => return ZigTag.type.create(c.arena, "f128"),
681 .@"enum" => @panic("TODO"),736 .@"enum" => {
682 .pointer,737 const enum_decl = ty.data.@"enum";
683 .unspecified_variable_len_array,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 },
684 .array,776 .array,
685 .static_array,777 .static_array,
686 .incomplete_array,778 => {
687 => @panic("TODO"),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 },
688 .func,783 .func,
689 .var_args_func,784 .var_args_func,
690 .old_style_func,785 .old_style_func,
...@@ -698,6 +793,7 @@ fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualH...@@ -698,6 +793,7 @@ fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualH
698 const name_id = c.mapper.lookup(record_decl.name);793 const name_id = c.mapper.lookup(record_decl.name);
699 if (c.weak_global_names.contains(name_id)) trans_scope = &c.global_scope.base;794 if (c.weak_global_names.contains(name_id)) trans_scope = &c.global_scope.base;
700 }795 }
796 try transRecordDecl(c, trans_scope, ty);
701 const name = c.decl_table.get(@intFromPtr(ty.data.record)).?;797 const name = c.decl_table.get(@intFromPtr(ty.data.record)).?;
702 return ZigTag.identifier.create(c.arena, name);798 return ZigTag.identifier.create(c.arena, name);
703 },799 },
...@@ -927,7 +1023,9 @@ fn transFnType(...@@ -927,7 +1023,9 @@ fn transFnType(
927}1023}
9281024
929fn transStmt(c: *Context, node: NodeIndex) TransError!ZigNode {1025fn transStmt(c: *Context, node: NodeIndex) TransError!ZigNode {
930 return transExpr(c, node, .unused);1026 _ = c;
1027 _ = node;
1028 return error.UnsupportedTranslation;
931}1029}
9321030
933fn transCompoundStmtInline(c: *Context, compound: NodeIndex, block: *Scope.Block) TransError!void {1031fn transCompoundStmtInline(c: *Context, compound: NodeIndex, block: *Scope.Block) TransError!void {
...@@ -952,6 +1050,45 @@ fn transCompoundStmtInline(c: *Context, compound: NodeIndex, block: *Scope.Block...@@ -952,6 +1050,45 @@ fn transCompoundStmtInline(c: *Context, compound: NodeIndex, block: *Scope.Block
952 }1050 }
953}1051}
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
955fn transCompoundStmt(c: *Context, scope: *Scope, compound: NodeIndex) TransError!ZigNode {1092fn transCompoundStmt(c: *Context, scope: *Scope, compound: NodeIndex) TransError!ZigNode {
956 var block_scope = try Scope.Block.init(c, scope, false);1093 var block_scope = try Scope.Block.init(c, scope, false);
957 defer block_scope.deinit();1094 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 {...@@ -494,16 +494,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
494 \\};494 \\};
495 });495 });
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
507 cases.add("array initializer w/ typedef",497 cases.add("array initializer w/ typedef",
508 \\typedef unsigned char uuid_t[16];498 \\typedef unsigned char uuid_t[16];
509 \\static const uuid_t UUID_NULL __attribute__ ((unused)) = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};499 \\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 {...@@ -529,10 +519,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
529 \\};519 \\};
530 });520 });
531521
532 cases.add("empty declaration",
533 \\;
534 , &[_][]const u8{""});
535
536 cases.add("#define hex literal with capital X",522 cases.add("#define hex literal with capital X",
537 \\#define VAL 0XF00D523 \\#define VAL 0XF00D
538 , &[_][]const u8{524 , &[_][]const u8{
...@@ -658,14 +644,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -658,14 +644,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
658 \\pub export fn my_fn() linksection("NEAR,.data") void {}644 \\pub export fn my_fn() linksection("NEAR,.data") void {}
659 });645 });
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
669 cases.add("simple var decls",647 cases.add("simple var decls",
670 \\void foo(void) {648 \\void foo(void) {
671 \\ int a;649 \\ int a;
...@@ -796,12 +774,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -796,12 +774,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
796 \\}774 \\}
797 });775 });
798776
799 cases.add("noreturn attribute",
800 \\void foo(void) __attribute__((noreturn));
801 , &[_][]const u8{
802 \\pub extern fn foo() noreturn;
803 });
804
805 cases.add("always_inline attribute",777 cases.add("always_inline attribute",
806 \\__attribute__((always_inline)) int foo() {778 \\__attribute__((always_inline)) int foo() {
807 \\ return 5;779 \\ return 5;
...@@ -901,17 +873,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -901,17 +873,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
901 \\pub const Foo = struct_Foo;873 \\pub const Foo = struct_Foo;
902 });874 });
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
915 cases.add("#define an unsigned integer literal",876 cases.add("#define an unsigned integer literal",
916 \\#define CHANNEL_COUNT 24877 \\#define CHANNEL_COUNT 24
917 , &[_][]const u8{878 , &[_][]const u8{