authorgravatar for flyfish30@users.noreply.github.comParker Liu <flyfish30@users.noreply.github.com> 2025-04-03 04:07:41+08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-04-02 20:07:41+00:00
logde62dc884edb1205e1aac799e0a3b4273be999a1
treea422d9b06ad72ce6d13cca7015fe4091b707faac
parent9dfdf3503242428f93c56c8f211834bd6b87ac76
signaturebadge-check Signed by PGP key B5690EEEBB952194

translate-c: fix function prototype decalared inside a function

* If a function prototype is declarated inside a function, do not translate it to a top-level extern function declaration. Similar to extern local variable, just wrapped it into a block-local struct. * Add a new extern_local_fn tag of aro_translate_c node for present extern local function declaration. * When a function body has a C function prototype declaration, it adds an extern local function declaration. Subsequent function references will look for this function declaration.

4 files changed, 78 insertions(+), 20 deletions(-)

lib/compiler/aro_translate_c.zig+17-7
...@@ -1502,19 +1502,29 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ...@@ -1502,19 +1502,29 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ
1502 return scope.base.parent.?.getAlias(name);1502 return scope.base.parent.?.getAlias(name);
1503 }1503 }
15041504
1505 /// Finds the (potentially) mangled struct name for a locally scoped extern variable given the original declaration name.1505 /// Finds the (potentially) mangled struct name for a locally scoped extern variable or function given the original declaration name.
1506 ///1506 ///
1507 /// Block scoped extern declarations translate to:1507 /// Block scoped extern declarations translate to:
1508 /// const MangledStructName = struct {extern [qualifiers] original_extern_variable_name: [type]};1508 /// const MangledStructName = struct {extern [qualifiers] original_extern_variable_name: [type]};
1509 /// This finds MangledStructName given original_extern_variable_name for referencing correctly in transDeclRefExpr()1509 /// This finds MangledStructName given original_extern_variable_name for referencing correctly in transDeclRefExpr()
1510 pub fn getLocalExternAlias(scope: *Block, name: []const u8) ?[]const u8 {1510 pub fn getLocalExternAlias(scope: *Block, name: []const u8) ?[]const u8 {
1511 for (scope.statements.items) |node| {1511 for (scope.statements.items) |node| {
1512 if (node.tag() == .extern_local_var) {1512 switch (node.tag()) {
1513 const parent_node = node.castTag(.extern_local_var).?;1513 .extern_local_var => {
1514 const init_node = parent_node.data.init.castTag(.var_decl).?;1514 const parent_node = node.castTag(.extern_local_var).?;
1515 if (std.mem.eql(u8, init_node.data.name, name)) {1515 const init_node = parent_node.data.init.castTag(.var_decl).?;
1516 return parent_node.data.name;1516 if (std.mem.eql(u8, init_node.data.name, name)) {
1517 }1517 return parent_node.data.name;
1518 }
1519 },
1520 .extern_local_fn => {
1521 const parent_node = node.castTag(.extern_local_fn).?;
1522 const init_node = parent_node.data.init.castTag(.func).?;
1523 if (std.mem.eql(u8, init_node.data.name.?, name)) {
1524 return parent_node.data.name;
1525 }
1526 },
1527 else => {},
1518 }1528 }
1519 }1529 }
1520 return null;1530 return null;
lib/compiler/aro_translate_c/ast.zig+16-4
...@@ -57,6 +57,8 @@ pub const Node = extern union {...@@ -57,6 +57,8 @@ pub const Node = extern union {
57 static_local_var,57 static_local_var,
58 /// const ExternLocal_name = struct { init }58 /// const ExternLocal_name = struct { init }
59 extern_local_var,59 extern_local_var,
60 /// const ExternLocal_name = struct { init }
61 extern_local_fn,
60 /// var name = init.*62 /// var name = init.*
61 mut_str,63 mut_str,
62 func,64 func,
...@@ -367,7 +369,13 @@ pub const Node = extern union {...@@ -367,7 +369,13 @@ pub const Node = extern union {
367 .c_pointer, .single_pointer => Payload.Pointer,369 .c_pointer, .single_pointer => Payload.Pointer,
368 .array_type, .null_sentinel_array_type => Payload.Array,370 .array_type, .null_sentinel_array_type => Payload.Array,
369 .arg_redecl, .alias, .fail_decl => Payload.ArgRedecl,371 .arg_redecl, .alias, .fail_decl => Payload.ArgRedecl,
370 .var_simple, .pub_var_simple, .static_local_var, .extern_local_var, .mut_str => Payload.SimpleVarDecl,372 .var_simple,
373 .pub_var_simple,
374 .static_local_var,
375 .extern_local_var,
376 .extern_local_fn,
377 .mut_str,
378 => Payload.SimpleVarDecl,
371 .enum_constant => Payload.EnumConstant,379 .enum_constant => Payload.EnumConstant,
372 .array_filler => Payload.ArrayFiller,380 .array_filler => Payload.ArrayFiller,
373 .pub_inline_fn => Payload.PubInlineFn,381 .pub_inline_fn => Payload.PubInlineFn,
...@@ -1265,8 +1273,11 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {...@@ -1265,8 +1273,11 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
1265 } },1273 } },
1266 });1274 });
1267 },1275 },
1268 .extern_local_var => {1276 .extern_local_var, .extern_local_fn => {
1269 const payload = node.castTag(.extern_local_var).?.data;1277 const payload = if (node.tag() == .extern_local_var)
1278 node.castTag(.extern_local_var).?.data
1279 else
1280 node.castTag(.extern_local_fn).?.data;
12701281
1271 const const_tok = try c.addToken(.keyword_const, "const");1282 const const_tok = try c.addToken(.keyword_const, "const");
1272 _ = try c.addIdentifier(payload.name);1283 _ = try c.addIdentifier(payload.name);
...@@ -2293,7 +2304,7 @@ fn renderNullSentinelArrayType(c: *Context, len: usize, elem_type: Node) !NodeIn...@@ -2293,7 +2304,7 @@ fn renderNullSentinelArrayType(c: *Context, len: usize, elem_type: Node) !NodeIn
2293fn addSemicolonIfNeeded(c: *Context, node: Node) !void {2304fn addSemicolonIfNeeded(c: *Context, node: Node) !void {
2294 switch (node.tag()) {2305 switch (node.tag()) {
2295 .warning => unreachable,2306 .warning => unreachable,
2296 .var_decl, .var_simple, .arg_redecl, .alias, .block, .empty_block, .block_single, .@"switch", .static_local_var, .extern_local_var, .mut_str => {},2307 .var_decl, .var_simple, .arg_redecl, .alias, .block, .empty_block, .block_single, .@"switch", .static_local_var, .extern_local_var, .extern_local_fn, .mut_str => {},
2297 .while_true => {2308 .while_true => {
2298 const payload = node.castTag(.while_true).?.data;2309 const payload = node.castTag(.while_true).?.data;
2299 return addSemicolonIfNotBlock(c, payload);2310 return addSemicolonIfNotBlock(c, payload);
...@@ -2390,6 +2401,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {...@@ -2390,6 +2401,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
2390 .builtin_extern,2401 .builtin_extern,
2391 .static_local_var,2402 .static_local_var,
2392 .extern_local_var,2403 .extern_local_var,
2404 .extern_local_fn,
2393 .mut_str,2405 .mut_str,
2394 .macro_arithmetic,2406 .macro_arithmetic,
2395 => {2407 => {
src/translate_c.zig+40-7
...@@ -325,7 +325,7 @@ fn declVisitorNamesOnly(c: *Context, decl: *const clang.Decl) Error!void {...@@ -325,7 +325,7 @@ fn declVisitorNamesOnly(c: *Context, decl: *const clang.Decl) Error!void {
325fn declVisitor(c: *Context, decl: *const clang.Decl) Error!void {325fn declVisitor(c: *Context, decl: *const clang.Decl) Error!void {
326 switch (decl.getKind()) {326 switch (decl.getKind()) {
327 .Function => {327 .Function => {
328 return visitFnDecl(c, @as(*const clang.FunctionDecl, @ptrCast(decl)));328 return transFnDecl(c, &c.global_scope.base, @as(*const clang.FunctionDecl, @ptrCast(decl)));
329 },329 },
330 .Typedef => {330 .Typedef => {
331 try transTypeDef(c, &c.global_scope.base, @as(*const clang.TypedefNameDecl, @ptrCast(decl)));331 try transTypeDef(c, &c.global_scope.base, @as(*const clang.TypedefNameDecl, @ptrCast(decl)));
...@@ -367,7 +367,7 @@ fn transFileScopeAsm(c: *Context, scope: *Scope, file_scope_asm: *const clang.Fi...@@ -367,7 +367,7 @@ fn transFileScopeAsm(c: *Context, scope: *Scope, file_scope_asm: *const clang.Fi
367 try scope.appendNode(comptime_node);367 try scope.appendNode(comptime_node);
368}368}
369369
370fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {370fn transFnDecl(c: *Context, scope: *Scope, fn_decl: *const clang.FunctionDecl) Error!void {
371 const fn_name = try c.str(@as(*const clang.NamedDecl, @ptrCast(fn_decl)).getName_bytes_begin());371 const fn_name = try c.str(@as(*const clang.NamedDecl, @ptrCast(fn_decl)).getName_bytes_begin());
372 if (c.global_scope.sym_table.contains(fn_name))372 if (c.global_scope.sym_table.contains(fn_name))
373 return; // Avoid processing this decl twice373 return; // Avoid processing this decl twice
...@@ -375,7 +375,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {...@@ -375,7 +375,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
375 // Skip this declaration if a proper definition exists375 // Skip this declaration if a proper definition exists
376 if (!fn_decl.isThisDeclarationADefinition()) {376 if (!fn_decl.isThisDeclarationADefinition()) {
377 if (fn_decl.getDefinition()) |def|377 if (fn_decl.getDefinition()) |def|
378 return visitFnDecl(c, def);378 return transFnDecl(c, scope, def);
379 }379 }
380380
381 const fn_decl_loc = fn_decl.getLocation();381 const fn_decl_loc = fn_decl.getLocation();
...@@ -446,6 +446,9 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {...@@ -446,6 +446,9 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
446 };446 };
447447
448 if (!decl_ctx.has_body) {448 if (!decl_ctx.has_body) {
449 if (scope.id != .root) {
450 return addLocalExternFnDecl(c, scope, fn_name, Node.initPayload(&proto_node.base));
451 }
449 return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base));452 return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base));
450 }453 }
451454
...@@ -455,7 +458,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {...@@ -455,7 +458,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
455 block_scope.return_type = return_qt;458 block_scope.return_type = return_qt;
456 defer block_scope.deinit();459 defer block_scope.deinit();
457460
458 const scope = &block_scope.base;461 const top_scope = &block_scope.base;
459462
460 var param_id: c_uint = 0;463 var param_id: c_uint = 0;
461 for (proto_node.data.params) |*param| {464 for (proto_node.data.params) |*param| {
...@@ -508,7 +511,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {...@@ -508,7 +511,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
508 break :blk;511 break :blk;
509 }512 }
510513
511 const rhs = transZeroInitExpr(c, scope, fn_decl_loc, return_qt.getTypePtr()) catch |err| switch (err) {514 const rhs = transZeroInitExpr(c, top_scope, fn_decl_loc, return_qt.getTypePtr()) catch |err| switch (err) {
512 error.OutOfMemory => |e| return e,515 error.OutOfMemory => |e| return e,
513 error.UnsupportedTranslation,516 error.UnsupportedTranslation,
514 error.UnsupportedType,517 error.UnsupportedType,
...@@ -1874,7 +1877,7 @@ fn transDeclStmtOne(...@@ -1874,7 +1877,7 @@ fn transDeclStmtOne(
1874 try transEnumDecl(c, scope, @as(*const clang.EnumDecl, @ptrCast(decl)));1877 try transEnumDecl(c, scope, @as(*const clang.EnumDecl, @ptrCast(decl)));
1875 },1878 },
1876 .Function => {1879 .Function => {
1877 try visitFnDecl(c, @as(*const clang.FunctionDecl, @ptrCast(decl)));1880 try transFnDecl(c, scope, @as(*const clang.FunctionDecl, @ptrCast(decl)));
1878 },1881 },
1879 else => {1882 else => {
1880 const decl_name = try c.str(decl.getDeclKindName());1883 const decl_name = try c.str(decl.getDeclKindName());
...@@ -1903,11 +1906,19 @@ fn transDeclRefExpr(...@@ -1903,11 +1906,19 @@ fn transDeclRefExpr(
1903 const name = try c.str(@as(*const clang.NamedDecl, @ptrCast(value_decl)).getName_bytes_begin());1906 const name = try c.str(@as(*const clang.NamedDecl, @ptrCast(value_decl)).getName_bytes_begin());
1904 const mangled_name = scope.getAlias(name);1907 const mangled_name = scope.getAlias(name);
1905 const decl_is_var = @as(*const clang.Decl, @ptrCast(value_decl)).getKind() == .Var;1908 const decl_is_var = @as(*const clang.Decl, @ptrCast(value_decl)).getKind() == .Var;
1906 const potential_local_extern = if (decl_is_var) ((@as(*const clang.VarDecl, @ptrCast(value_decl)).getStorageClass() == .Extern) and (scope.id != .root)) else false;1909 const storage_class = @as(*const clang.VarDecl, @ptrCast(value_decl)).getStorageClass();
1910 const potential_local_extern = if (decl_is_var) ((storage_class == .Extern) and (scope.id != .root)) else false;
19071911
1908 var confirmed_local_extern = false;1912 var confirmed_local_extern = false;
1913 var confirmed_local_extern_fn = false;
1909 var ref_expr = val: {1914 var ref_expr = val: {
1910 if (cIsFunctionDeclRef(@as(*const clang.Expr, @ptrCast(expr)))) {1915 if (cIsFunctionDeclRef(@as(*const clang.Expr, @ptrCast(expr)))) {
1916 if (scope.id != .root) {
1917 if (scope.getLocalExternAlias(name)) |v| {
1918 confirmed_local_extern_fn = true;
1919 break :val try Tag.identifier.create(c.arena, v);
1920 }
1921 }
1911 break :val try Tag.fn_identifier.create(c.arena, mangled_name);1922 break :val try Tag.fn_identifier.create(c.arena, mangled_name);
1912 } else if (potential_local_extern) {1923 } else if (potential_local_extern) {
1913 if (scope.getLocalExternAlias(name)) |v| {1924 if (scope.getLocalExternAlias(name)) |v| {
...@@ -1934,6 +1945,11 @@ fn transDeclRefExpr(...@@ -1934,6 +1945,11 @@ fn transDeclRefExpr(
1934 .field_name = name, // by necessity, name will always == mangled_name1945 .field_name = name, // by necessity, name will always == mangled_name
1935 });1946 });
1936 }1947 }
1948 } else if (confirmed_local_extern_fn) {
1949 ref_expr = try Tag.field_access.create(c.arena, .{
1950 .lhs = ref_expr,
1951 .field_name = name, // by necessity, name will always == mangled_name
1952 });
1937 }1953 }
1938 scope.skipVariableDiscard(mangled_name);1954 scope.skipVariableDiscard(mangled_name);
1939 return ref_expr;1955 return ref_expr;
...@@ -4213,6 +4229,23 @@ fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: Node) !void {...@@ -4213,6 +4229,23 @@ fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: Node) !void {
4213 }4229 }
4214}4230}
42154231
4232/// Add an "extern" function prototype declaration that's been declared within a scoped block.
4233/// Similar to static local variables, this will be wrapped in a struct to work with Zig's syntax requirements.
4234///
4235fn addLocalExternFnDecl(c: *Context, scope: *Scope, name: []const u8, decl_node: Node) !void {
4236 const bs: *Scope.Block = try scope.findBlockScope(c);
4237
4238 // Special naming convention for local extern function wrapper struct,
4239 // this named "ExternLocal_[name]".
4240 const struct_name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ Scope.Block.extern_inner_prepend, name });
4241
4242 // Outer Node for the wrapper struct
4243 const node = try Tag.extern_local_fn.create(c.arena, .{ .name = struct_name, .init = decl_node });
4244
4245 try bs.statements.append(node);
4246 try bs.discardVariable(c, struct_name);
4247}
4248
4216fn transQualTypeInitializedStringLiteral(c: *Context, elem_ty: Node, string_lit: *const clang.StringLiteral) TypeError!Node {4249fn transQualTypeInitializedStringLiteral(c: *Context, elem_ty: Node, string_lit: *const clang.StringLiteral) TypeError!Node {
4217 const string_lit_size = string_lit.getLength();4250 const string_lit_size = string_lit.getLength();
4218 const array_size = @as(usize, @intCast(string_lit_size));4251 const array_size = @as(usize, @intCast(string_lit_size));
test/translate_c.zig+5-2
...@@ -3537,9 +3537,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -3537,9 +3537,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
3537 \\ return bar(1, 2);3537 \\ return bar(1, 2);
3538 \\}3538 \\}
3539 , &[_][]const u8{3539 , &[_][]const u8{
3540 \\pub extern fn bar(c_int, c_int) c_int;
3541 \\pub export fn foo() c_int {3540 \\pub export fn foo() c_int {
3542 \\ return bar(@as(c_int, 1), @as(c_int, 2));3541 \\ const ExternLocal_bar = struct {
3542 \\ pub extern fn bar(c_int, c_int) c_int;
3543 \\ };
3544 \\ _ = &ExternLocal_bar;
3545 \\ return ExternLocal_bar.bar(@as(c_int, 1), @as(c_int, 2));
3543 \\}3546 \\}
3544 });3547 });
35453548