From 236567de8d7706b7a6c529670a1a15f4c8b9f95e Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Tue, 30 Jul 2024 10:52:33 -0700 Subject: [PATCH 01/15] aro_translate_c: Emit compile errors instead of panicking for var decls --- lib/compiler/aro_translate_c.zig | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/compiler/aro_translate_c.zig b/lib/compiler/aro_translate_c.zig index 02c7547ce5..2e20918d4b 100644 --- a/lib/compiler/aro_translate_c.zig +++ b/lib/compiler/aro_translate_c.zig @@ -304,7 +304,7 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void { .threadlocal_extern_var, .threadlocal_static_var, => { - try transVarDecl(c, decl, null); + try transVarDecl(c, decl); }, .static_assert => try warn(c, &c.global_scope.base, 0, "ignoring _Static_assert declaration", .{}), else => unreachable, @@ -566,8 +566,10 @@ fn transFnDecl(c: *Context, fn_decl: NodeIndex) Error!void { return addTopLevelDecl(c, fn_name, proto_node); } -fn transVarDecl(_: *Context, _: NodeIndex, _: ?usize) Error!void { - @panic("TODO"); +fn transVarDecl(c: *Context, node: NodeIndex) Error!void { + const data = c.tree.nodes.items(.data)[@intFromEnum(node)]; + const name = c.tree.tokSlice(data.decl.name); + return failDecl(c, data.decl.name, name, "unable to translate variable declaration", .{}); } fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes: []const NodeIndex) Error!void { From da3822f4c2b6a9e0703079c80a43c3e2a5f01aec Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Tue, 30 Jul 2024 11:25:15 -0700 Subject: [PATCH 02/15] aro_translate_c: Translate array types --- lib/compiler/aro_translate_c.zig | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/compiler/aro_translate_c.zig b/lib/compiler/aro_translate_c.zig index 2e20918d4b..1963b8f84f 100644 --- a/lib/compiler/aro_translate_c.zig +++ b/lib/compiler/aro_translate_c.zig @@ -681,12 +681,15 @@ fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualH .float80 => return ZigTag.type.create(c.arena, "f80"), .float128 => return ZigTag.type.create(c.arena, "f128"), .@"enum" => @panic("TODO"), - .pointer, + .pointer, .incomplete_array => @panic("todo"), .unspecified_variable_len_array, .array, .static_array, - .incomplete_array, - => @panic("TODO"), + => { + const size = ty.arrayLen().?; + const elem_type = try transType(c, scope, ty.elemType(), qual_handling, source_loc); + return ZigTag.array_type.create(c.arena, .{ .len = size, .elem_type = elem_type }); + }, .func, .var_args_func, .old_style_func, From e32cde256811c0de68c507014d901b1a88c8e7f9 Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Tue, 30 Jul 2024 11:31:30 -0700 Subject: [PATCH 03/15] aro_translate_c: translate incomplete arrays --- lib/compiler/aro_translate_c.zig | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/compiler/aro_translate_c.zig b/lib/compiler/aro_translate_c.zig index 1963b8f84f..a183df4fb9 100644 --- a/lib/compiler/aro_translate_c.zig +++ b/lib/compiler/aro_translate_c.zig @@ -681,8 +681,16 @@ fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualH .float80 => return ZigTag.type.create(c.arena, "f80"), .float128 => return ZigTag.type.create(c.arena, "f128"), .@"enum" => @panic("TODO"), - .pointer, .incomplete_array => @panic("todo"), + .pointer => @panic("todo"), .unspecified_variable_len_array, + .incomplete_array => { + const child_type = ty.elemType(); + const is_const = child_type.qual.@"const"; + const is_volatile = child_type.qual.@"volatile"; + const elem_type = try transType(c, scope, child_type, qual_handling, source_loc); + + return ZigTag.c_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type }); + }, .array, .static_array, => { From 2f2f35105ec76b3543b3198071fef35f4cbf71e2 Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Tue, 30 Jul 2024 12:19:26 -0700 Subject: [PATCH 04/15] aro_translate_c: translate pointer types --- lib/compiler/aro_translate_c.zig | 65 ++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/lib/compiler/aro_translate_c.zig b/lib/compiler/aro_translate_c.zig index a183df4fb9..9ba092ab9c 100644 --- a/lib/compiler/aro_translate_c.zig +++ b/lib/compiler/aro_translate_c.zig @@ -681,9 +681,29 @@ fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualH .float80 => return ZigTag.type.create(c.arena, "f80"), .float128 => return ZigTag.type.create(c.arena, "f128"), .@"enum" => @panic("TODO"), - .pointer => @panic("todo"), - .unspecified_variable_len_array, - .incomplete_array => { + .pointer => { + const child_type = ty.elemType(); + + const is_fn_proto = child_type.isFunc(); + const is_const = is_fn_proto or child_type.isConst(); + const is_volatile = child_type.qual.@"volatile"; + const elem_type = try transType(c, scope, child_type, qual_handling, source_loc); + const ptr_info = .{ + .is_const = is_const, + .is_volatile = is_volatile, + .elem_type = elem_type, + }; + if (is_fn_proto or + typeIsOpaque(c, child_type) or + typeWasDemotedToOpaque(c, child_type)) + { + const ptr = try ZigTag.single_pointer.create(c.arena, ptr_info); + return ZigTag.optional_type.create(c.arena, ptr); + } + + return ZigTag.c_pointer.create(c.arena, ptr_info); + }, + .unspecified_variable_len_array, .incomplete_array => { const child_type = ty.elemType(); const is_const = child_type.qual.@"const"; const is_volatile = child_type.qual.@"volatile"; @@ -965,6 +985,45 @@ fn transCompoundStmtInline(c: *Context, compound: NodeIndex, block: *Scope.Block } } +fn recordHasBitfield(record: *const Type.Record) bool { + if (record.isIncomplete()) return false; + for (record.fields) |field| { + if (!field.isRegularField()) return true; + } + return false; +} + +fn typeIsOpaque(c: *Context, ty: Type) bool { + return switch (ty.specifier) { + .void => true, + .@"struct", .@"union" => recordHasBitfield(ty.getRecord().?), + .typeof_type => typeIsOpaque(c, ty.data.sub_type.*), + .typeof_expr => typeIsOpaque(c, ty.data.expr.ty), + .attributed => typeIsOpaque(c, ty.data.attributed.base), + else => false, + }; +} + +fn typeWasDemotedToOpaque(c: *Context, ty: Type) bool { + switch (ty.specifier) { + .@"struct", .@"union" => { + const record = ty.getRecord().?; + if (c.opaque_demotes.contains(@intFromPtr(record))) return true; + for (record.fields) |field| { + if (typeWasDemotedToOpaque(c, field.ty)) return true; + } + return false; + }, + + .@"enum" => return c.opaque_demotes.contains(@intFromPtr(ty.data.@"enum")), + + .typeof_type => return typeWasDemotedToOpaque(c, ty.data.sub_type.*), + .typeof_expr => return typeWasDemotedToOpaque(c, ty.data.expr.ty), + .attributed => return typeWasDemotedToOpaque(c, ty.data.attributed.base), + else => return false, + } +} + fn transCompoundStmt(c: *Context, scope: *Scope, compound: NodeIndex) TransError!ZigNode { var block_scope = try Scope.Block.init(c, scope, false); defer block_scope.deinit(); From 5cc9e18277e1b166be0898255448f3c642759bbc Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Tue, 30 Jul 2024 13:37:37 -0700 Subject: [PATCH 05/15] aro_translate_c: Translate enum types --- lib/compiler/aro_translate_c.zig | 38 ++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/lib/compiler/aro_translate_c.zig b/lib/compiler/aro_translate_c.zig index 9ba092ab9c..5c9e9771ba 100644 --- a/lib/compiler/aro_translate_c.zig +++ b/lib/compiler/aro_translate_c.zig @@ -243,6 +243,7 @@ fn transTopLevelDecls(c: *Context) !void { fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void { const node_tags = c.tree.nodes.items(.tag); const node_data = c.tree.nodes.items(.data); + const node_ty = c.tree.nodes.items(.ty); const data = node_data[@intFromEnum(decl)]; switch (node_tags[@intFromEnum(decl)]) { .typedef => { @@ -270,11 +271,13 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void { var field_count: u8 = 0; if (fields[0] != .none) field_count += 1; if (fields[1] != .none) field_count += 1; - try transEnumDecl(c, scope, decl, fields[0..field_count]); + const enum_decl = node_ty[@intFromEnum(decl)].canonicalize(.standard).data.@"enum"; + try transEnumDecl(c, scope, enum_decl, fields[0..field_count]); }, .enum_decl => { const fields = c.tree.data[data.range.start..data.range.end]; - try transEnumDecl(c, scope, decl, fields); + const enum_decl = node_ty[@intFromEnum(decl)].canonicalize(.standard).data.@"enum"; + try transEnumDecl(c, scope, enum_decl, fields); }, .enum_field_decl, @@ -572,18 +575,16 @@ fn transVarDecl(c: *Context, node: NodeIndex) Error!void { return failDecl(c, data.decl.name, name, "unable to translate variable declaration", .{}); } -fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes: []const NodeIndex) Error!void { - const node_types = c.tree.nodes.items(.ty); - const ty = node_types[@intFromEnum(enum_decl)]; - if (c.decl_table.get(@intFromPtr(ty.data.@"enum"))) |_| +fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const Type.Enum, field_nodes: []const NodeIndex) Error!void { + if (c.decl_table.get(@intFromPtr(enum_decl))) |_| return; // Avoid processing this decl twice const toplevel = scope.id == .root; const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined; var is_unnamed = false; - var bare_name: []const u8 = c.mapper.lookup(ty.data.@"enum".name); + var bare_name: []const u8 = c.mapper.lookup(enum_decl.name); var name = bare_name; - if (c.unnamed_typedefs.get(@intFromPtr(ty.data.@"enum"))) |typedef_name| { + if (c.unnamed_typedefs.get(@intFromPtr(enum_decl))) |typedef_name| { bare_name = typedef_name; name = typedef_name; } else { @@ -594,10 +595,10 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes: name = try std.fmt.allocPrint(c.arena, "enum_{s}", .{bare_name}); } if (!toplevel) name = try bs.makeMangledName(c, name); - try c.decl_table.putNoClobber(c.gpa, @intFromPtr(ty.data.@"enum"), name); + try c.decl_table.putNoClobber(c.gpa, @intFromPtr(enum_decl), name); - const enum_type_node = if (!ty.data.@"enum".isIncomplete()) blk: { - for (ty.data.@"enum".fields, field_nodes) |field, field_node| { + const enum_type_node = if (!enum_decl.isIncomplete()) blk: { + for (enum_decl.fields, field_nodes) |field, field_node| { var enum_val_name: []const u8 = c.mapper.lookup(field.name); if (!toplevel) { enum_val_name = try bs.makeMangledName(c, enum_val_name); @@ -623,14 +624,14 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes: } } - break :blk transType(c, scope, ty.data.@"enum".tag_ty, .standard, 0) catch |err| switch (err) { + break :blk transType(c, scope, enum_decl.tag_ty, .standard, 0) catch |err| switch (err) { error.UnsupportedType => { return failDecl(c, 0, name, "unable to translate enum integer type", .{}); }, else => |e| return e, }; } else blk: { - try c.opaque_demotes.put(c.gpa, @intFromPtr(ty.data.@"enum"), {}); + try c.opaque_demotes.put(c.gpa, @intFromPtr(enum_decl), {}); break :blk ZigTag.opaque_literal.init(); }; @@ -680,7 +681,16 @@ fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualH .long_double => return ZigTag.type.create(c.arena, "c_longdouble"), .float80 => return ZigTag.type.create(c.arena, "f80"), .float128 => return ZigTag.type.create(c.arena, "f128"), - .@"enum" => @panic("TODO"), + .@"enum" => { + const enum_decl = ty.data.@"enum"; + var trans_scope = scope; + if (enum_decl.name != .empty) { + const decl_name = c.mapper.lookup(enum_decl.name); + if (c.weak_global_names.contains(decl_name)) trans_scope = &c.global_scope.base; + } + try transEnumDecl(c, trans_scope, enum_decl, &.{}); + return ZigTag.identifier.create(c.arena, c.decl_table.get(@intFromPtr(enum_decl)).?); + }, .pointer => { const child_type = ty.elemType(); From 4300a9c417cb9344d65e74335c9ce09cbf9bfc17 Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Tue, 30 Jul 2024 16:47:10 -0700 Subject: [PATCH 06/15] aro_translate_c: Make function decls public --- lib/compiler/aro_translate_c.zig | 5 +++-- .../translate_c/function prototype with parenthesis.c | 10 ++++++++++ test/translate_c.zig | 10 ---------- 3 files changed, 13 insertions(+), 12 deletions(-) create mode 100644 test/cases/translate_c/function prototype with parenthesis.c diff --git a/lib/compiler/aro_translate_c.zig b/lib/compiler/aro_translate_c.zig index 5c9e9771ba..dd8ca54819 100644 --- a/lib/compiler/aro_translate_c.zig +++ b/lib/compiler/aro_translate_c.zig @@ -297,7 +297,7 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void { .inline_fn_def, .inline_static_fn_def, => { - try transFnDecl(c, decl); + try transFnDecl(c, decl, true); }, .@"var", @@ -476,7 +476,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod } } -fn transFnDecl(c: *Context, fn_decl: NodeIndex) Error!void { +fn transFnDecl(c: *Context, fn_decl: NodeIndex, is_pub: bool) Error!void { const raw_ty = c.tree.nodes.items(.ty)[@intFromEnum(fn_decl)]; const fn_ty = raw_ty.canonicalize(.standard); const node_data = c.tree.nodes.items(.data)[@intFromEnum(fn_decl)]; @@ -501,6 +501,7 @@ fn transFnDecl(c: *Context, fn_decl: NodeIndex) Error!void { else => unreachable, }, + .is_pub = is_pub, }; const proto_node = transFnType(c, &c.global_scope.base, raw_ty, fn_ty, fn_decl_loc, proto_ctx) catch |err| switch (err) { diff --git a/test/cases/translate_c/function prototype with parenthesis.c b/test/cases/translate_c/function prototype with parenthesis.c new file mode 100644 index 0000000000..7b93e3fa93 --- /dev/null +++ b/test/cases/translate_c/function prototype with parenthesis.c @@ -0,0 +1,10 @@ +void (f0) (void *L); +void ((f1)) (void *L); +void (((f2))) (void *L); + +// translate-c +// c_frontend=clang,aro +// +// pub extern fn f0(L: ?*anyopaque) void; +// pub extern fn f1(L: ?*anyopaque) void; +// pub extern fn f2(L: ?*anyopaque) void; diff --git a/test/translate_c.zig b/test/translate_c.zig index c07b29f772..31bb577f00 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -494,16 +494,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\}; }); - cases.add("function prototype with parenthesis", - \\void (f0) (void *L); - \\void ((f1)) (void *L); - \\void (((f2))) (void *L); - , &[_][]const u8{ - \\pub extern fn f0(L: ?*anyopaque) void; - \\pub extern fn f1(L: ?*anyopaque) void; - \\pub extern fn f2(L: ?*anyopaque) void; - }); - cases.add("array initializer w/ typedef", \\typedef unsigned char uuid_t[16]; \\static const uuid_t UUID_NULL __attribute__ ((unused)) = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; From 6997f82e028642a727cc8762a9077c473066e265 Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Tue, 30 Jul 2024 16:49:59 -0700 Subject: [PATCH 07/15] translate_c: move empty declaration test to test manifest --- test/cases/translate_c/empty declaration.c | 6 ++++++ test/translate_c.zig | 4 ---- 2 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 test/cases/translate_c/empty declaration.c diff --git a/test/cases/translate_c/empty declaration.c b/test/cases/translate_c/empty declaration.c new file mode 100644 index 0000000000..5f19328acf --- /dev/null +++ b/test/cases/translate_c/empty declaration.c @@ -0,0 +1,6 @@ +; + +// translate-c +// c_frontend=clang,aro +// +// \ No newline at end of file diff --git a/test/translate_c.zig b/test/translate_c.zig index 31bb577f00..772129be9b 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -519,10 +519,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\}; }); - cases.add("empty declaration", - \\; - , &[_][]const u8{""}); - cases.add("#define hex literal with capital X", \\#define VAL 0XF00D , &[_][]const u8{ From c57fcd1db536591ecdee8c9ec497c8ea667c57f0 Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Tue, 30 Jul 2024 17:20:09 -0700 Subject: [PATCH 08/15] aro_translate_c: demote functions with bodies to extern Translating statements is currently not supported; demoting to extern is better than crashing. --- lib/compiler/aro_translate_c.zig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/compiler/aro_translate_c.zig b/lib/compiler/aro_translate_c.zig index dd8ca54819..39cdbcba1e 100644 --- a/lib/compiler/aro_translate_c.zig +++ b/lib/compiler/aro_translate_c.zig @@ -971,7 +971,9 @@ fn transFnType( } fn transStmt(c: *Context, node: NodeIndex) TransError!ZigNode { - return transExpr(c, node, .unused); + _ = c; + _ = node; + return error.UnsupportedTranslation; } fn transCompoundStmtInline(c: *Context, compound: NodeIndex, block: *Scope.Block) TransError!void { From 055077f9dd0091a0e071243e10e4d2500038d0be Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Tue, 30 Jul 2024 18:24:16 -0700 Subject: [PATCH 09/15] aro_translate_c: improve record translation Move field record decl translation into `transType` instead of `transDecl` --- lib/compiler/aro_translate_c.zig | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/lib/compiler/aro_translate_c.zig b/lib/compiler/aro_translate_c.zig index 39cdbcba1e..5bacf73226 100644 --- a/lib/compiler/aro_translate_c.zig +++ b/lib/compiler/aro_translate_c.zig @@ -253,17 +253,12 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void { .struct_decl_two, .union_decl_two, => { - var fields = [2]NodeIndex{ data.bin.lhs, data.bin.rhs }; - var field_count: u2 = 0; - if (fields[0] != .none) field_count += 1; - if (fields[1] != .none) field_count += 1; - try transRecordDecl(c, scope, decl, fields[0..field_count]); + try transRecordDecl(c, scope, node_ty[@intFromEnum(decl)]); }, .struct_decl, .union_decl, => { - const fields = c.tree.data[data.range.start..data.range.end]; - try transRecordDecl(c, scope, decl, fields); + try transRecordDecl(c, scope, node_ty[@intFromEnum(decl)]); }, .enum_decl_two => { @@ -333,16 +328,14 @@ fn mangleWeakGlobalName(c: *Context, want_name: []const u8) ![]const u8 { return cur_name; } -fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nodes: []const NodeIndex) Error!void { - const node_types = c.tree.nodes.items(.ty); - const raw_record_ty = node_types[@intFromEnum(record_node)]; - const record_decl = raw_record_ty.getRecord().?; +fn transRecordDecl(c: *Context, scope: *Scope, record_ty: Type) Error!void { + const record_decl = record_ty.getRecord().?; if (c.decl_table.get(@intFromPtr(record_decl))) |_| return; // Avoid processing this decl twice const toplevel = scope.id == .root; const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined; - const container_kind: ZigTag = if (raw_record_ty.is(.@"union")) .@"union" else .@"struct"; + const container_kind: ZigTag = if (record_ty.is(.@"union")) .@"union" else .@"struct"; const container_kind_name: []const u8 = @tagName(container_kind); var is_unnamed = false; @@ -353,7 +346,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod bare_name = typedef_name; name = typedef_name; } else { - if (raw_record_ty.isAnonymousRecord(c.comp)) { + if (record_ty.isAnonymousRecord(c.comp)) { bare_name = try std.fmt.allocPrint(c.arena, "unnamed_{d}", .{c.getMangle()}); is_unnamed = true; } @@ -380,17 +373,10 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod // layout, then we can just use a simple `extern` type. If it does have attributes, // then we need to inspect the layout and assign an `align` value for each field. const has_alignment_attributes = record_decl.field_attributes != null or - raw_record_ty.hasAttribute(.@"packed") or - raw_record_ty.hasAttribute(.aligned); + record_ty.hasAttribute(.@"packed") or + record_ty.hasAttribute(.aligned); const head_field_alignment: ?c_uint = if (has_alignment_attributes) headFieldAlignment(record_decl) else null; - // Iterate over field nodes so that we translate any type decls included in this record decl. - // TODO: Move this logic into `fn transType()` instead of handling decl translation here. - for (field_nodes) |field_node| { - const field_raw_ty = node_types[@intFromEnum(field_node)]; - if (field_raw_ty.isEnumOrRecord()) try transDecl(c, scope, field_node); - } - for (record_decl.fields, 0..) |field, field_index| { const field_loc = field.name_tok; @@ -742,6 +728,7 @@ fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualH const name_id = c.mapper.lookup(record_decl.name); if (c.weak_global_names.contains(name_id)) trans_scope = &c.global_scope.base; } + try transRecordDecl(c, trans_scope, ty); const name = c.decl_table.get(@intFromPtr(ty.data.record)).?; return ZigTag.identifier.create(c.arena, name); }, From 6a103d87f650ed7cac79866033e3136433259f67 Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Tue, 30 Jul 2024 21:27:08 -0700 Subject: [PATCH 10/15] aro_translate_c: basic typedef support --- lib/compiler/aro_translate_c.zig | 44 +++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/lib/compiler/aro_translate_c.zig b/lib/compiler/aro_translate_c.zig index 5bacf73226..5665c3b2e6 100644 --- a/lib/compiler/aro_translate_c.zig +++ b/lib/compiler/aro_translate_c.zig @@ -185,7 +185,7 @@ fn prepopulateGlobalNameTable(c: *Context) !void { for (c.tree.root_decls) |node| { const data = node_data[@intFromEnum(node)]; switch (node_tags[@intFromEnum(node)]) { - .typedef => @panic("TODO"), + .typedef => {}, .struct_decl_two, .union_decl_two, @@ -309,8 +309,46 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void { } } -fn transTypeDef(_: *Context, _: *Scope, _: NodeIndex) Error!void { - @panic("TODO"); +fn transTypeDef(c: *Context, scope: *Scope, typedef_decl: NodeIndex) Error!void { + const ty = c.tree.nodes.items(.ty)[@intFromEnum(typedef_decl)]; + const data = c.tree.nodes.items(.data)[@intFromEnum(typedef_decl)]; + + const toplevel = scope.id == .root; + const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined; + + var name: []const u8 = c.tree.tokSlice(data.decl.name); + try c.typedefs.put(c.gpa, name, {}); + + if (!toplevel) name = try bs.makeMangledName(c, name); + + const typedef_loc = data.decl.name; + const init_node = transType(c, scope, ty, .standard, typedef_loc) catch |err| switch (err) { + error.UnsupportedType => { + return failDecl(c, typedef_loc, name, "unable to resolve typedef child type", .{}); + }, + error.OutOfMemory => |e| return e, + }; + + const payload = try c.arena.create(ast.Payload.SimpleVarDecl); + payload.* = .{ + .base = .{ .tag = ([2]ZigTag{ .var_simple, .pub_var_simple })[@intFromBool(toplevel)] }, + .data = .{ + .name = name, + .init = init_node, + }, + }; + const node = ZigNode.initPayload(&payload.base); + + if (toplevel) { + try addTopLevelDecl(c, name, node); + } else { + try scope.appendNode(node); + if (node.tag() != .pub_var_simple) { + try bs.discardVariable(c, name); + } + } + + } fn mangleWeakGlobalName(c: *Context, want_name: []const u8) ![]const u8 { From 93a502cb2f5a38d0a94ebccd1be523bc71f6a00b Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Tue, 30 Jul 2024 21:31:34 -0700 Subject: [PATCH 11/15] aro_translate_c: move simple function prototype test to manifest --- test/cases/translate_c/simple function prototypes.c | 8 ++++++++ test/translate_c.zig | 8 -------- 2 files changed, 8 insertions(+), 8 deletions(-) create mode 100644 test/cases/translate_c/simple function prototypes.c diff --git a/test/cases/translate_c/simple function prototypes.c b/test/cases/translate_c/simple function prototypes.c new file mode 100644 index 0000000000..ee1e2bad32 --- /dev/null +++ b/test/cases/translate_c/simple function prototypes.c @@ -0,0 +1,8 @@ +void __attribute__((noreturn)) foo(void); +int bar(void); + +// translate-c +// c_frontend=clang,aro +// +// pub extern fn foo() noreturn; +// pub extern fn bar() c_int; diff --git a/test/translate_c.zig b/test/translate_c.zig index 772129be9b..d2ed936434 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -644,14 +644,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub export fn my_fn() linksection("NEAR,.data") void {} }); - cases.add("simple function prototypes", - \\void __attribute__((noreturn)) foo(void); - \\int bar(void); - , &[_][]const u8{ - \\pub extern fn foo() noreturn; - \\pub extern fn bar() c_int; - }); - cases.add("simple var decls", \\void foo(void) { \\ int a; From b3f576993087f90a249b75f8e72cb95974633eb4 Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Tue, 30 Jul 2024 23:30:10 -0700 Subject: [PATCH 12/15] aro_translate_c: handle opaque struct defs in prototypes --- lib/compiler/aro_translate_c.zig | 5 +++++ .../cases/translate_c/struct prototype used in func.c | 10 ++++++++++ test/translate_c.zig | 11 ----------- 3 files changed, 15 insertions(+), 11 deletions(-) create mode 100644 test/cases/translate_c/struct prototype used in func.c diff --git a/lib/compiler/aro_translate_c.zig b/lib/compiler/aro_translate_c.zig index 5665c3b2e6..cec10a301a 100644 --- a/lib/compiler/aro_translate_c.zig +++ b/lib/compiler/aro_translate_c.zig @@ -398,6 +398,11 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_ty: Type) Error!void { const is_pub = toplevel and !is_unnamed; const init_node = blk: { + if (record_decl.isIncomplete()) { + try c.opaque_demotes.put(c.gpa, @intFromPtr(record_decl), {}); + break :blk ZigTag.opaque_literal.init(); + } + var fields = try std.ArrayList(ast.Payload.Record.Field).initCapacity(c.gpa, record_decl.fields.len); defer fields.deinit(); diff --git a/test/cases/translate_c/struct prototype used in func.c b/test/cases/translate_c/struct prototype used in func.c new file mode 100644 index 0000000000..b688e6e742 --- /dev/null +++ b/test/cases/translate_c/struct prototype used in func.c @@ -0,0 +1,10 @@ +struct Foo; +struct Foo *some_func(struct Foo *foo, int x); + +// translate-c +// c_frontend=clang,aro +// +// pub const struct_Foo = opaque {}; +// pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo; +// +// pub const Foo = struct_Foo; diff --git a/test/translate_c.zig b/test/translate_c.zig index d2ed936434..5c74110749 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -879,17 +879,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const Foo = struct_Foo; }); - cases.add("struct prototype used in func", - \\struct Foo; - \\struct Foo *some_func(struct Foo *foo, int x); - , &[_][]const u8{ - \\pub const struct_Foo = opaque {}; - , - \\pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo; - , - \\pub const Foo = struct_Foo; - }); - cases.add("#define an unsigned integer literal", \\#define CHANNEL_COUNT 24 , &[_][]const u8{ From 6c632d52f903b97d28210a6a4155eee8e6704d33 Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Tue, 30 Jul 2024 23:30:25 -0700 Subject: [PATCH 13/15] aro_translate_c: move noreturn test to manifest --- test/cases/translate_c/noreturn attribute.c | 6 ++++++ test/translate_c.zig | 6 ------ 2 files changed, 6 insertions(+), 6 deletions(-) create mode 100644 test/cases/translate_c/noreturn attribute.c diff --git a/test/cases/translate_c/noreturn attribute.c b/test/cases/translate_c/noreturn attribute.c new file mode 100644 index 0000000000..9564fd0092 --- /dev/null +++ b/test/cases/translate_c/noreturn attribute.c @@ -0,0 +1,6 @@ +void foo(void) __attribute__((noreturn)); + +// translate-c +// c_frontend=aro,clang +// +// pub extern fn foo() noreturn; diff --git a/test/translate_c.zig b/test/translate_c.zig index 5c74110749..3b4b80920e 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -774,12 +774,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add("noreturn attribute", - \\void foo(void) __attribute__((noreturn)); - , &[_][]const u8{ - \\pub extern fn foo() noreturn; - }); - cases.add("always_inline attribute", \\__attribute__((always_inline)) int foo() { \\ return 5; From aa5a1105e838fbf2f9f918c2a544be6fa0c35e22 Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Wed, 31 Jul 2024 09:22:25 -0700 Subject: [PATCH 14/15] aro_translate_c: do not translate atomic types --- lib/compiler/aro_translate_c.zig | 24 ++++++++++++++++++++++++ test/cases/translate_c/atomic types.c | 8 ++++++++ 2 files changed, 32 insertions(+) create mode 100644 test/cases/translate_c/atomic types.c diff --git a/lib/compiler/aro_translate_c.zig b/lib/compiler/aro_translate_c.zig index cec10a301a..9de4ec52d4 100644 --- a/lib/compiler/aro_translate_c.zig +++ b/lib/compiler/aro_translate_c.zig @@ -78,6 +78,17 @@ fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: ZigNode) !void { } } +fn fail( + c: *Context, + err: anytype, + source_loc: TokenIndex, + comptime format: []const u8, + args: anytype, +) (@TypeOf(err) || error{OutOfMemory}) { + try warn(c, &c.global_scope.base, source_loc, format, args); + return err; +} + fn failDecl(c: *Context, loc: TokenIndex, name: []const u8, comptime format: []const u8, args: anytype) Error!void { // location // pub const name = @compileError(msg); @@ -687,8 +698,21 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const Type.Enum, field_ } } +fn getTypeStr(c: *Context, ty: Type) ![]const u8 { + var buf: std.ArrayListUnmanaged(u8) = .{}; + defer buf.deinit(c.gpa); + const w = buf.writer(c.gpa); + try ty.print(c.mapper, c.comp.langopts, w); + return c.arena.dupe(u8, buf.items); +} + fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualHandling, source_loc: TokenIndex) TypeError!ZigNode { const ty = raw_ty.canonicalize(qual_handling); + if (ty.qual.atomic) { + const type_name = try getTypeStr(c, ty); + return fail(c, error.UnsupportedType, source_loc, "unsupported type: '{s}'", .{type_name}); + } + switch (ty.specifier) { .void => return ZigTag.type.create(c.arena, "anyopaque"), .bool => return ZigTag.type.create(c.arena, "bool"), diff --git a/test/cases/translate_c/atomic types.c b/test/cases/translate_c/atomic types.c new file mode 100644 index 0000000000..ad1af598c4 --- /dev/null +++ b/test/cases/translate_c/atomic types.c @@ -0,0 +1,8 @@ +typedef _Atomic(int) AtomicInt; + +// translate-c +// target=x86_64-linux +// c_frontend=aro +// +// tmp.c:1:22: warning: unsupported type: '_Atomic(int)' +// pub const AtomicInt = @compileError("unable to resolve typedef child type"); From 1cc74f3cae32bc5c002868d7d53af4e14f5a9ce6 Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Wed, 31 Jul 2024 10:33:44 -0700 Subject: [PATCH 15/15] aro_translate_c: fix formatting --- lib/compiler/aro_translate_c.zig | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/compiler/aro_translate_c.zig b/lib/compiler/aro_translate_c.zig index 9de4ec52d4..ad7584c726 100644 --- a/lib/compiler/aro_translate_c.zig +++ b/lib/compiler/aro_translate_c.zig @@ -358,8 +358,6 @@ fn transTypeDef(c: *Context, scope: *Scope, typedef_decl: NodeIndex) Error!void try bs.discardVariable(c, name); } } - - } fn mangleWeakGlobalName(c: *Context, want_name: []const u8) ![]const u8 {