| ... | ... | @@ -325,7 +325,7 @@ fn declVisitorNamesOnly(c: *Context, decl: *const clang.Decl) Error!void { |
| 325 | 325 | fn declVisitor(c: *Context, decl: *const clang.Decl) Error!void { |
| 326 | 326 | switch (decl.getKind()) { |
| 327 | 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 | 330 | .Typedef => { |
| 331 | 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 | 367 | try scope.appendNode(comptime_node); |
| 368 | 368 | } |
| 369 | 369 | |
| 370 | | fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { |
| 370 | fn transFnDecl(c: *Context, scope: *Scope, fn_decl: *const clang.FunctionDecl) Error!void { |
| 371 | 371 | const fn_name = try c.str(@as(*const clang.NamedDecl, @ptrCast(fn_decl)).getName_bytes_begin()); |
| 372 | 372 | if (c.global_scope.sym_table.contains(fn_name)) |
| 373 | 373 | return; // Avoid processing this decl twice |
| ... | ... | @@ -375,7 +375,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { |
| 375 | 375 | // Skip this declaration if a proper definition exists |
| 376 | 376 | if (!fn_decl.isThisDeclarationADefinition()) { |
| 377 | 377 | if (fn_decl.getDefinition()) |def| |
| 378 | | return visitFnDecl(c, def); |
| 378 | return transFnDecl(c, scope, def); |
| 379 | 379 | } |
| 380 | 380 | |
| 381 | 381 | const fn_decl_loc = fn_decl.getLocation(); |
| ... | ... | @@ -446,6 +446,9 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { |
| 446 | 446 | }; |
| 447 | 447 | |
| 448 | 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 | 452 | return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base)); |
| 450 | 453 | } |
| 451 | 454 | |
| ... | ... | @@ -455,7 +458,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { |
| 455 | 458 | block_scope.return_type = return_qt; |
| 456 | 459 | defer block_scope.deinit(); |
| 457 | 460 | |
| 458 | | const scope = &block_scope.base; |
| 461 | const top_scope = &block_scope.base; |
| 459 | 462 | |
| 460 | 463 | var param_id: c_uint = 0; |
| 461 | 464 | for (proto_node.data.params) |*param| { |
| ... | ... | @@ -508,7 +511,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { |
| 508 | 511 | break :blk; |
| 509 | 512 | } |
| 510 | 513 | |
| 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 | 515 | error.OutOfMemory => |e| return e, |
| 513 | 516 | error.UnsupportedTranslation, |
| 514 | 517 | error.UnsupportedType, |
| ... | ... | @@ -1874,7 +1877,7 @@ fn transDeclStmtOne( |
| 1874 | 1877 | try transEnumDecl(c, scope, @as(*const clang.EnumDecl, @ptrCast(decl))); |
| 1875 | 1878 | }, |
| 1876 | 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 | 1882 | else => { |
| 1880 | 1883 | const decl_name = try c.str(decl.getDeclKindName()); |
| ... | ... | @@ -1903,11 +1906,19 @@ fn transDeclRefExpr( |
| 1903 | 1906 | const name = try c.str(@as(*const clang.NamedDecl, @ptrCast(value_decl)).getName_bytes_begin()); |
| 1904 | 1907 | const mangled_name = scope.getAlias(name); |
| 1905 | 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; |
| 1907 | 1911 | |
| 1908 | 1912 | var confirmed_local_extern = false; |
| 1913 | var confirmed_local_extern_fn = false; |
| 1909 | 1914 | var ref_expr = val: { |
| 1910 | 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 | 1922 | break :val try Tag.fn_identifier.create(c.arena, mangled_name); |
| 1912 | 1923 | } else if (potential_local_extern) { |
| 1913 | 1924 | if (scope.getLocalExternAlias(name)) |v| { |
| ... | ... | @@ -1934,6 +1945,11 @@ fn transDeclRefExpr( |
| 1934 | 1945 | .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 | 1954 | scope.skipVariableDiscard(mangled_name); |
| 1939 | 1955 | return ref_expr; |
| ... | ... | @@ -4213,6 +4229,23 @@ fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: Node) !void { |
| 4213 | 4229 | } |
| 4214 | 4230 | } |
| 4215 | 4231 | |
| 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 | /// |
| 4235 | fn 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 | |
| 4216 | 4249 | fn transQualTypeInitializedStringLiteral(c: *Context, elem_ty: Node, string_lit: *const clang.StringLiteral) TypeError!Node { |
| 4217 | 4250 | const string_lit_size = string_lit.getLength(); |
| 4218 | 4251 | const array_size = @as(usize, @intCast(string_lit_size)); |