| ... | @@ -13384,11 +13384,11 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -13384,11 +13384,11 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 13384 | const args = sema.resolveInst(extra.data.args); | 13384 | const args = sema.resolveInst(extra.data.args); |
| 13385 | | 13385 | |
| 13386 | const modifier: std.builtin.CallOptions.Modifier = modifier: { | 13386 | const modifier: std.builtin.CallOptions.Modifier = modifier: { |
| 13387 | const export_options_ty = try sema.getBuiltinType(block, options_src, "CallOptions"); | 13387 | const call_options_ty = try sema.getBuiltinType(block, options_src, "CallOptions"); |
| 13388 | const coerced_options = try sema.coerce(block, export_options_ty, options, options_src); | 13388 | const coerced_options = try sema.coerce(block, call_options_ty, options, options_src); |
| 13389 | const options_val = try sema.resolveConstValue(block, options_src, coerced_options); | 13389 | const options_val = try sema.resolveConstValue(block, options_src, coerced_options); |
| 13390 | const fields = options_val.castTag(.@"struct").?.data; | 13390 | const fields = options_val.castTag(.@"struct").?.data; |
| 13391 | const struct_obj = export_options_ty.castTag(.@"struct").?.data; | 13391 | const struct_obj = call_options_ty.castTag(.@"struct").?.data; |
| 13392 | const modifier_index = struct_obj.fields.getIndex("modifier").?; | 13392 | const modifier_index = struct_obj.fields.getIndex("modifier").?; |
| 13393 | const stack_index = struct_obj.fields.getIndex("stack").?; | 13393 | const stack_index = struct_obj.fields.getIndex("stack").?; |
| 13394 | if (!fields[stack_index].isNull()) { | 13394 | if (!fields[stack_index].isNull()) { |
| ... | @@ -13743,6 +13743,7 @@ fn zirVarExtended( | ... | @@ -13743,6 +13743,7 @@ fn zirVarExtended( |
| 13743 | .is_extern = small.is_extern, | 13743 | .is_extern = small.is_extern, |
| 13744 | .is_mutable = true, // TODO get rid of this unused field | 13744 | .is_mutable = true, // TODO get rid of this unused field |
| 13745 | .is_threadlocal = small.is_threadlocal, | 13745 | .is_threadlocal = small.is_threadlocal, |
| | 13746 | .is_weak_linkage = false, |
| 13746 | .lib_name = null, | 13747 | .lib_name = null, |
| 13747 | }; | 13748 | }; |
| 13748 | | 13749 | |
| ... | @@ -13937,7 +13938,98 @@ fn zirBuiltinExtern( | ... | @@ -13937,7 +13938,98 @@ fn zirBuiltinExtern( |
| 13937 | ) CompileError!Air.Inst.Ref { | 13938 | ) CompileError!Air.Inst.Ref { |
| 13938 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; | 13939 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; |
| 13939 | const src: LazySrcLoc = .{ .node_offset = extra.node }; | 13940 | const src: LazySrcLoc = .{ .node_offset = extra.node }; |
| 13940 | return sema.fail(block, src, "TODO: implement Sema.zirBuiltinExtern", .{}); | 13941 | const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| | 13942 | const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; |
| | 13943 | |
| | 13944 | var ty = try sema.resolveType(block, ty_src, extra.lhs); |
| | 13945 | const options_inst = sema.resolveInst(extra.rhs); |
| | 13946 | |
| | 13947 | const options = options: { |
| | 13948 | const extern_options_ty = try sema.getBuiltinType(block, options_src, "ExternOptions"); |
| | 13949 | const coerced_options = try sema.coerce(block, extern_options_ty, options_inst, options_src); |
| | 13950 | const options_val = try sema.resolveConstValue(block, options_src, coerced_options); |
| | 13951 | const fields = options_val.castTag(.@"struct").?.data; |
| | 13952 | const struct_obj = extern_options_ty.castTag(.@"struct").?.data; |
| | 13953 | const name_index = struct_obj.fields.getIndex("name").?; |
| | 13954 | const library_name_index = struct_obj.fields.getIndex("library_name").?; |
| | 13955 | const linkage_index = struct_obj.fields.getIndex("linkage").?; |
| | 13956 | const is_thread_local_index = struct_obj.fields.getIndex("is_thread_local").?; |
| | 13957 | |
| | 13958 | var library_name: ?[]const u8 = null; |
| | 13959 | if (!fields[library_name_index].isNull()) { |
| | 13960 | const payload = fields[library_name_index].castTag(.opt_payload).?.data; |
| | 13961 | library_name = try payload.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena); |
| | 13962 | } |
| | 13963 | |
| | 13964 | break :options std.builtin.ExternOptions{ |
| | 13965 | .name = try fields[name_index].toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena), |
| | 13966 | .library_name = library_name, |
| | 13967 | .linkage = fields[linkage_index].toEnum(std.builtin.GlobalLinkage), |
| | 13968 | .is_thread_local = fields[is_thread_local_index].toBool(), |
| | 13969 | }; |
| | 13970 | }; |
| | 13971 | |
| | 13972 | if (!ty.isPtrAtRuntime()) { |
| | 13973 | return sema.fail(block, options_src, "expected (optional) pointer", .{}); |
| | 13974 | } |
| | 13975 | |
| | 13976 | if (options.name.len == 0) { |
| | 13977 | return sema.fail(block, options_src, "extern symbol name cannot be empty", .{}); |
| | 13978 | } |
| | 13979 | |
| | 13980 | if (options.linkage != .Weak and options.linkage != .Strong) { |
| | 13981 | return sema.fail(block, options_src, "extern symbol must use strong or weak linkage", .{}); |
| | 13982 | } |
| | 13983 | |
| | 13984 | if (options.linkage == .Weak and !ty.ptrAllowsZero()) { |
| | 13985 | ty = try Type.optional(sema.arena, ty); |
| | 13986 | } |
| | 13987 | |
| | 13988 | // TODO check duplicate extern |
| | 13989 | |
| | 13990 | const new_decl = try sema.mod.allocateNewDecl(try sema.gpa.dupeZ(u8, options.name), sema.owner_decl.src_namespace, sema.owner_decl.src_node, null); |
| | 13991 | errdefer new_decl.destroy(sema.mod); |
| | 13992 | |
| | 13993 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); |
| | 13994 | errdefer new_decl_arena.deinit(); |
| | 13995 | const new_decl_arena_allocator = new_decl_arena.allocator(); |
| | 13996 | |
| | 13997 | const new_var = try new_decl_arena_allocator.create(Module.Var); |
| | 13998 | errdefer new_decl_arena_allocator.destroy(new_var); |
| | 13999 | |
| | 14000 | new_var.* = .{ |
| | 14001 | .owner_decl = sema.owner_decl, |
| | 14002 | .init = Value.initTag(.unreachable_value), |
| | 14003 | .is_extern = true, |
| | 14004 | .is_mutable = false, // TODO get rid of this unused field |
| | 14005 | .is_threadlocal = options.is_thread_local, |
| | 14006 | .is_weak_linkage = options.linkage == .Weak, |
| | 14007 | .lib_name = null, |
| | 14008 | }; |
| | 14009 | |
| | 14010 | if (options.library_name) |library_name| { |
| | 14011 | if (library_name.len == 0) { |
| | 14012 | return sema.fail(block, options_src, "library name name cannot be empty", .{}); |
| | 14013 | } |
| | 14014 | new_var.lib_name = try sema.handleExternLibName(block, options_src, library_name); |
| | 14015 | } |
| | 14016 | |
| | 14017 | new_decl.src_line = sema.owner_decl.src_line; |
| | 14018 | new_decl.ty = try ty.copy(new_decl_arena_allocator); |
| | 14019 | new_decl.val = try Value.Tag.variable.create(new_decl_arena_allocator, new_var); |
| | 14020 | new_decl.align_val = Value.@"null"; |
| | 14021 | new_decl.linksection_val = Value.@"null"; |
| | 14022 | new_decl.has_tv = true; |
| | 14023 | new_decl.analysis = .complete; |
| | 14024 | new_decl.generation = sema.mod.generation; |
| | 14025 | |
| | 14026 | const arena_state = try new_decl_arena_allocator.create(std.heap.ArenaAllocator.State); |
| | 14027 | arena_state.* = new_decl_arena.state; |
| | 14028 | new_decl.value_arena = arena_state; |
| | 14029 | |
| | 14030 | const ref = try sema.analyzeDeclRef(new_decl); |
| | 14031 | try sema.requireRuntimeBlock(block, src); |
| | 14032 | return block.addBitCast(ty, ref); |
| 13941 | } | 14033 | } |
| 13942 | | 14034 | |
| 13943 | fn requireFunctionBlock(sema: *Sema, block: *Block, src: LazySrcLoc) !void { | 14035 | fn requireFunctionBlock(sema: *Sema, block: *Block, src: LazySrcLoc) !void { |