| ... | ... | @@ -4909,7 +4909,13 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 4909 | 4909 | return sema.fail(block, src, "TODO: implement exporting with field access", .{}); |
| 4910 | 4910 | } |
| 4911 | 4911 | const decl_index = try sema.lookupIdentifier(block, operand_src, decl_name); |
| 4912 | | const options = try sema.resolveExportOptions(block, options_src, extra.options); |
| 4912 | const options = sema.resolveExportOptions(block, .unneeded, extra.options) catch |err| switch (err) { |
| 4913 | error.NeededSourceLocation => { |
| 4914 | _ = try sema.resolveExportOptions(block, options_src, extra.options); |
| 4915 | return error.AnalysisFail; |
| 4916 | }, |
| 4917 | else => |e| return e, |
| 4918 | }; |
| 4913 | 4919 | try sema.analyzeExport(block, src, options, decl_index); |
| 4914 | 4920 | } |
| 4915 | 4921 | |
| ... | ... | @@ -4923,7 +4929,13 @@ fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 4923 | 4929 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 4924 | 4930 | const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 4925 | 4931 | const operand = try sema.resolveInstConst(block, operand_src, extra.operand, "export target must be comptime known"); |
| 4926 | | const options = try sema.resolveExportOptions(block, options_src, extra.options); |
| 4932 | const options = sema.resolveExportOptions(block, .unneeded, extra.options) catch |err| switch (err) { |
| 4933 | error.NeededSourceLocation => { |
| 4934 | _ = try sema.resolveExportOptions(block, options_src, extra.options); |
| 4935 | return error.AnalysisFail; |
| 4936 | }, |
| 4937 | else => |e| return e, |
| 4938 | }; |
| 4927 | 4939 | const decl_index = switch (operand.val.tag()) { |
| 4928 | 4940 | .function => operand.val.castTag(.function).?.data.owner_decl, |
| 4929 | 4941 | else => return sema.fail(block, operand_src, "TODO implement exporting arbitrary Value objects", .{}), // TODO put this Value into an anonymous Decl and then export it. |
| ... | ... | @@ -17029,6 +17041,11 @@ fn checkVectorizableBinaryOperands( |
| 17029 | 17041 | } |
| 17030 | 17042 | } |
| 17031 | 17043 | |
| 17044 | fn maybeOptionsSrc(sema: *Sema, block: *Block, base_src: LazySrcLoc, wanted: []const u8) LazySrcLoc { |
| 17045 | if (base_src == .unneeded) return .unneeded; |
| 17046 | return Module.optionsSrc(sema.gpa, sema.mod.declPtr(block.src_decl), base_src, wanted); |
| 17047 | } |
| 17048 | |
| 17032 | 17049 | fn resolveExportOptions( |
| 17033 | 17050 | sema: *Sema, |
| 17034 | 17051 | block: *Block, |
| ... | ... | @@ -17039,34 +17056,39 @@ fn resolveExportOptions( |
| 17039 | 17056 | const air_ref = try sema.resolveInst(zir_ref); |
| 17040 | 17057 | const options = try sema.coerce(block, export_options_ty, air_ref, src); |
| 17041 | 17058 | |
| 17042 | | const name_operand = try sema.fieldVal(block, src, options, "name", src); |
| 17043 | | const name_val = try sema.resolveConstValue(block, src, name_operand, "name of exported value must be comptime known"); |
| 17059 | const name_src = sema.maybeOptionsSrc(block, src, "name"); |
| 17060 | const linkage_src = sema.maybeOptionsSrc(block, src, "linkage"); |
| 17061 | const section_src = sema.maybeOptionsSrc(block, src, "section"); |
| 17062 | const visibility_src = sema.maybeOptionsSrc(block, src, "visibility"); |
| 17063 | |
| 17064 | const name_operand = try sema.fieldVal(block, src, options, "name", name_src); |
| 17065 | const name_val = try sema.resolveConstValue(block, name_src, name_operand, "name of exported value must be comptime known"); |
| 17044 | 17066 | const name_ty = Type.initTag(.const_slice_u8); |
| 17045 | 17067 | const name = try name_val.toAllocatedBytes(name_ty, sema.arena, sema.mod); |
| 17046 | 17068 | |
| 17047 | | const linkage_operand = try sema.fieldVal(block, src, options, "linkage", src); |
| 17048 | | const linkage_val = try sema.resolveConstValue(block, src, linkage_operand, "linkage of exported value must be comptime known"); |
| 17069 | const linkage_operand = try sema.fieldVal(block, src, options, "linkage", linkage_src); |
| 17070 | const linkage_val = try sema.resolveConstValue(block, linkage_src, linkage_operand, "linkage of exported value must be comptime known"); |
| 17049 | 17071 | const linkage = linkage_val.toEnum(std.builtin.GlobalLinkage); |
| 17050 | 17072 | |
| 17051 | | const section = try sema.fieldVal(block, src, options, "section", src); |
| 17052 | | const section_val = try sema.resolveConstValue(block, src, section, "linksection of exported value must be comptime known"); |
| 17073 | const section = try sema.fieldVal(block, src, options, "section", section_src); |
| 17074 | const section_val = try sema.resolveConstValue(block, section_src, section, "linksection of exported value must be comptime known"); |
| 17053 | 17075 | |
| 17054 | | const visibility_operand = try sema.fieldVal(block, src, options, "visibility", src); |
| 17055 | | const visibility_val = try sema.resolveConstValue(block, src, visibility_operand, "visibility of exported value must be comptime known"); |
| 17076 | const visibility_operand = try sema.fieldVal(block, src, options, "visibility", visibility_src); |
| 17077 | const visibility_val = try sema.resolveConstValue(block, visibility_src, visibility_operand, "visibility of exported value must be comptime known"); |
| 17056 | 17078 | const visibility = visibility_val.toEnum(std.builtin.SymbolVisibility); |
| 17057 | 17079 | |
| 17058 | 17080 | if (name.len < 1) { |
| 17059 | | return sema.fail(block, src, "exported symbol name cannot be empty", .{}); |
| 17081 | return sema.fail(block, name_src, "exported symbol name cannot be empty", .{}); |
| 17060 | 17082 | } |
| 17061 | 17083 | |
| 17062 | 17084 | if (visibility != .default and linkage == .Internal) { |
| 17063 | | return sema.fail(block, src, "symbol '{s}' exported with internal linkage has non-default visibility {s}", .{ |
| 17085 | return sema.fail(block, visibility_src, "symbol '{s}' exported with internal linkage has non-default visibility {s}", .{ |
| 17064 | 17086 | name, @tagName(visibility), |
| 17065 | 17087 | }); |
| 17066 | 17088 | } |
| 17067 | 17089 | |
| 17068 | 17090 | if (!section_val.isNull()) { |
| 17069 | | return sema.fail(block, src, "TODO: implement exporting with linksection", .{}); |
| 17091 | return sema.fail(block, section_src, "TODO: implement exporting with linksection", .{}); |
| 17070 | 17092 | } |
| 17071 | 17093 | |
| 17072 | 17094 | return std.builtin.ExportOptions{ |
| ... | ... | @@ -17805,80 +17827,113 @@ fn zirMulAdd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 17805 | 17827 | }); |
| 17806 | 17828 | } |
| 17807 | 17829 | |
| 17808 | | fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 17809 | | const tracy = trace(@src()); |
| 17810 | | defer tracy.end(); |
| 17811 | | |
| 17812 | | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 17813 | | const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 17814 | | const func_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 17815 | | const args_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; |
| 17816 | | const call_src = inst_data.src(); |
| 17817 | | |
| 17818 | | const extra = sema.code.extraData(Zir.Inst.BuiltinCall, inst_data.payload_index).data; |
| 17819 | | var func = try sema.resolveInst(extra.callee); |
| 17820 | | const options = try sema.resolveInst(extra.options); |
| 17821 | | const args = try sema.resolveInst(extra.args); |
| 17822 | | |
| 17823 | | const wanted_modifier: std.builtin.CallOptions.Modifier = modifier: { |
| 17824 | | const call_options_ty = try sema.getBuiltinType(block, options_src, "CallOptions"); |
| 17825 | | const coerced_options = try sema.coerce(block, call_options_ty, options, options_src); |
| 17830 | fn resolveCallOptions( |
| 17831 | sema: *Sema, |
| 17832 | block: *Block, |
| 17833 | src: LazySrcLoc, |
| 17834 | zir_ref: Zir.Inst.Ref, |
| 17835 | is_comptime: bool, |
| 17836 | is_nosuspend: bool, |
| 17837 | func: Air.Inst.Ref, |
| 17838 | func_src: LazySrcLoc, |
| 17839 | ) CompileError!std.builtin.CallOptions.Modifier { |
| 17840 | const call_options_ty = try sema.getBuiltinType(block, src, "CallOptions"); |
| 17841 | const air_ref = try sema.resolveInst(zir_ref); |
| 17842 | const options = try sema.coerce(block, call_options_ty, air_ref, src); |
| 17826 | 17843 | |
| 17827 | | const modifier = try sema.fieldVal(block, options_src, coerced_options, "modifier", options_src); |
| 17828 | | const modifier_val = try sema.resolveConstValue(block, options_src, modifier, "call modifier must be comptime known"); |
| 17844 | const modifier_src = sema.maybeOptionsSrc(block, src, "modifier"); |
| 17845 | const stack_src = sema.maybeOptionsSrc(block, src, "stack"); |
| 17829 | 17846 | |
| 17830 | | const stack = try sema.fieldVal(block, options_src, coerced_options, "stack", options_src); |
| 17831 | | const stack_val = try sema.resolveConstValue(block, options_src, stack, "call stack value must be comptime known"); |
| 17847 | const modifier = try sema.fieldVal(block, src, options, "modifier", modifier_src); |
| 17848 | const modifier_val = try sema.resolveConstValue(block, modifier_src, modifier, "call modifier must be comptime known"); |
| 17849 | const wanted_modifier = modifier_val.toEnum(std.builtin.CallOptions.Modifier); |
| 17832 | 17850 | |
| 17833 | | if (!stack_val.isNull()) { |
| 17834 | | return sema.fail(block, options_src, "TODO: implement @call with stack", .{}); |
| 17835 | | } |
| 17836 | | break :modifier modifier_val.toEnum(std.builtin.CallOptions.Modifier); |
| 17837 | | }; |
| 17851 | const stack = try sema.fieldVal(block, src, options, "stack", stack_src); |
| 17852 | const stack_val = try sema.resolveConstValue(block, stack_src, stack, "call stack value must be comptime known"); |
| 17838 | 17853 | |
| 17839 | | const is_comptime = extra.flags.is_comptime or block.is_comptime; |
| 17854 | if (!stack_val.isNull()) { |
| 17855 | return sema.fail(block, stack_src, "TODO: implement @call with stack", .{}); |
| 17856 | } |
| 17840 | 17857 | |
| 17841 | | const modifier: std.builtin.CallOptions.Modifier = switch (wanted_modifier) { |
| 17858 | switch (wanted_modifier) { |
| 17842 | 17859 | // These can be upgraded to comptime or nosuspend calls. |
| 17843 | | .auto, .never_tail, .no_async => m: { |
| 17860 | .auto, .never_tail, .no_async => { |
| 17844 | 17861 | if (is_comptime) { |
| 17845 | 17862 | if (wanted_modifier == .never_tail) { |
| 17846 | | return sema.fail(block, options_src, "unable to perform 'never_tail' call at compile-time", .{}); |
| 17863 | return sema.fail(block, modifier_src, "unable to perform 'never_tail' call at compile-time", .{}); |
| 17847 | 17864 | } |
| 17848 | | break :m .compile_time; |
| 17865 | return .compile_time; |
| 17849 | 17866 | } |
| 17850 | | if (extra.flags.is_nosuspend) { |
| 17851 | | break :m .no_async; |
| 17867 | if (is_nosuspend) { |
| 17868 | return .no_async; |
| 17852 | 17869 | } |
| 17853 | | break :m wanted_modifier; |
| 17870 | return wanted_modifier; |
| 17854 | 17871 | }, |
| 17855 | 17872 | // These can be upgraded to comptime. nosuspend bit can be safely ignored. |
| 17856 | | .always_tail, .always_inline, .compile_time => m: { |
| 17873 | .always_tail, .always_inline, .compile_time => { |
| 17857 | 17874 | _ = (try sema.resolveDefinedValue(block, func_src, func)) orelse { |
| 17858 | 17875 | return sema.fail(block, func_src, "modifier '{s}' requires a comptime-known function", .{@tagName(wanted_modifier)}); |
| 17859 | 17876 | }; |
| 17860 | 17877 | |
| 17861 | 17878 | if (is_comptime) { |
| 17862 | | break :m .compile_time; |
| 17879 | return .compile_time; |
| 17863 | 17880 | } |
| 17864 | | break :m wanted_modifier; |
| 17881 | return wanted_modifier; |
| 17865 | 17882 | }, |
| 17866 | | .async_kw => m: { |
| 17867 | | if (extra.flags.is_nosuspend) { |
| 17868 | | return sema.fail(block, options_src, "modifier 'async_kw' cannot be used inside nosuspend block", .{}); |
| 17883 | .async_kw => { |
| 17884 | if (is_nosuspend) { |
| 17885 | return sema.fail(block, modifier_src, "modifier 'async_kw' cannot be used inside nosuspend block", .{}); |
| 17869 | 17886 | } |
| 17870 | 17887 | if (is_comptime) { |
| 17871 | | return sema.fail(block, options_src, "modifier 'async_kw' cannot be used in combination with comptime function call", .{}); |
| 17888 | return sema.fail(block, modifier_src, "modifier 'async_kw' cannot be used in combination with comptime function call", .{}); |
| 17872 | 17889 | } |
| 17873 | | break :m wanted_modifier; |
| 17890 | return wanted_modifier; |
| 17874 | 17891 | }, |
| 17875 | | .never_inline => m: { |
| 17892 | .never_inline => { |
| 17876 | 17893 | if (is_comptime) { |
| 17877 | | return sema.fail(block, options_src, "unable to perform 'never_inline' call at compile-time", .{}); |
| 17894 | return sema.fail(block, modifier_src, "unable to perform 'never_inline' call at compile-time", .{}); |
| 17878 | 17895 | } |
| 17879 | | break :m wanted_modifier; |
| 17896 | return wanted_modifier; |
| 17880 | 17897 | }, |
| 17898 | } |
| 17899 | } |
| 17900 | |
| 17901 | fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 17902 | const tracy = trace(@src()); |
| 17903 | defer tracy.end(); |
| 17904 | |
| 17905 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 17906 | const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 17907 | const func_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 17908 | const args_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; |
| 17909 | const call_src = inst_data.src(); |
| 17910 | |
| 17911 | const extra = sema.code.extraData(Zir.Inst.BuiltinCall, inst_data.payload_index).data; |
| 17912 | var func = try sema.resolveInst(extra.callee); |
| 17913 | const modifier = sema.resolveCallOptions( |
| 17914 | block, |
| 17915 | .unneeded, |
| 17916 | extra.options, |
| 17917 | extra.flags.is_comptime, |
| 17918 | extra.flags.is_nosuspend, |
| 17919 | func, |
| 17920 | func_src, |
| 17921 | ) catch |err| switch (err) { |
| 17922 | error.NeededSourceLocation => { |
| 17923 | _ = try sema.resolveCallOptions( |
| 17924 | block, |
| 17925 | options_src, |
| 17926 | extra.options, |
| 17927 | extra.flags.is_comptime, |
| 17928 | extra.flags.is_nosuspend, |
| 17929 | func, |
| 17930 | func_src, |
| 17931 | ); |
| 17932 | return error.AnalysisFail; |
| 17933 | }, |
| 17934 | else => |e| return e, |
| 17881 | 17935 | }; |
| 17936 | const args = try sema.resolveInst(extra.args); |
| 17882 | 17937 | |
| 17883 | 17938 | const args_ty = sema.typeOf(args); |
| 17884 | 17939 | if (!args_ty.isTuple() and args_ty.tag() != .empty_struct_literal) { |
| ... | ... | @@ -18579,6 +18634,36 @@ fn zirWasmMemoryGrow( |
| 18579 | 18634 | }); |
| 18580 | 18635 | } |
| 18581 | 18636 | |
| 18637 | fn resolvePrefetchOptions( |
| 18638 | sema: *Sema, |
| 18639 | block: *Block, |
| 18640 | src: LazySrcLoc, |
| 18641 | zir_ref: Zir.Inst.Ref, |
| 18642 | ) CompileError!std.builtin.PrefetchOptions { |
| 18643 | const options_ty = try sema.getBuiltinType(block, src, "PrefetchOptions"); |
| 18644 | const options = try sema.coerce(block, options_ty, try sema.resolveInst(zir_ref), src); |
| 18645 | const target = sema.mod.getTarget(); |
| 18646 | |
| 18647 | const rw_src = sema.maybeOptionsSrc(block, src, "rw"); |
| 18648 | const locality_src = sema.maybeOptionsSrc(block, src, "locality"); |
| 18649 | const cache_src = sema.maybeOptionsSrc(block, src, "cache"); |
| 18650 | |
| 18651 | const rw = try sema.fieldVal(block, src, options, "rw", rw_src); |
| 18652 | const rw_val = try sema.resolveConstValue(block, rw_src, rw, "prefetch read/write must be comptime known"); |
| 18653 | |
| 18654 | const locality = try sema.fieldVal(block, src, options, "locality", locality_src); |
| 18655 | const locality_val = try sema.resolveConstValue(block, locality_src, locality, "prefetch locality must be comptime known"); |
| 18656 | |
| 18657 | const cache = try sema.fieldVal(block, src, options, "cache", cache_src); |
| 18658 | const cache_val = try sema.resolveConstValue(block, cache_src, cache, "prefetch cache must be comptime known"); |
| 18659 | |
| 18660 | return std.builtin.PrefetchOptions{ |
| 18661 | .rw = rw_val.toEnum(std.builtin.PrefetchOptions.Rw), |
| 18662 | .locality = @intCast(u2, locality_val.toUnsignedInt(target)), |
| 18663 | .cache = cache_val.toEnum(std.builtin.PrefetchOptions.Cache), |
| 18664 | }; |
| 18665 | } |
| 18666 | |
| 18582 | 18667 | fn zirPrefetch( |
| 18583 | 18668 | sema: *Sema, |
| 18584 | 18669 | block: *Block, |
| ... | ... | @@ -18587,32 +18672,25 @@ fn zirPrefetch( |
| 18587 | 18672 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; |
| 18588 | 18673 | const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| 18589 | 18674 | const opts_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; |
| 18590 | | const options_ty = try sema.getBuiltinType(block, opts_src, "PrefetchOptions"); |
| 18591 | 18675 | const ptr = try sema.resolveInst(extra.lhs); |
| 18592 | 18676 | try sema.checkPtrOperand(block, ptr_src, sema.typeOf(ptr)); |
| 18593 | | const options = try sema.coerce(block, options_ty, try sema.resolveInst(extra.rhs), opts_src); |
| 18594 | | const target = sema.mod.getTarget(); |
| 18595 | | |
| 18596 | | const rw = try sema.fieldVal(block, opts_src, options, "rw", opts_src); |
| 18597 | | const rw_val = try sema.resolveConstValue(block, opts_src, rw, "prefetch read/write must be comptime known"); |
| 18598 | | const rw_tag = rw_val.toEnum(std.builtin.PrefetchOptions.Rw); |
| 18599 | | |
| 18600 | | const locality = try sema.fieldVal(block, opts_src, options, "locality", opts_src); |
| 18601 | | const locality_val = try sema.resolveConstValue(block, opts_src, locality, "prefetch locality must be comptime known"); |
| 18602 | | const locality_int = @intCast(u2, locality_val.toUnsignedInt(target)); |
| 18603 | 18677 | |
| 18604 | | const cache = try sema.fieldVal(block, opts_src, options, "cache", opts_src); |
| 18605 | | const cache_val = try sema.resolveConstValue(block, opts_src, cache, "prefetch cache must be comptime known"); |
| 18606 | | const cache_tag = cache_val.toEnum(std.builtin.PrefetchOptions.Cache); |
| 18678 | const options = sema.resolvePrefetchOptions(block, .unneeded, extra.rhs) catch |err| switch (err) { |
| 18679 | error.NeededSourceLocation => { |
| 18680 | _ = try sema.resolvePrefetchOptions(block, opts_src, extra.rhs); |
| 18681 | return error.AnalysisFail; |
| 18682 | }, |
| 18683 | else => |e| return e, |
| 18684 | }; |
| 18607 | 18685 | |
| 18608 | 18686 | if (!block.is_comptime) { |
| 18609 | 18687 | _ = try block.addInst(.{ |
| 18610 | 18688 | .tag = .prefetch, |
| 18611 | 18689 | .data = .{ .prefetch = .{ |
| 18612 | 18690 | .ptr = ptr, |
| 18613 | | .rw = rw_tag, |
| 18614 | | .locality = locality_int, |
| 18615 | | .cache = cache_tag, |
| 18691 | .rw = options.rw, |
| 18692 | .locality = options.locality, |
| 18693 | .cache = options.cache, |
| 18616 | 18694 | } }, |
| 18617 | 18695 | }); |
| 18618 | 18696 | } |
| ... | ... | @@ -18620,71 +18698,93 @@ fn zirPrefetch( |
| 18620 | 18698 | return Air.Inst.Ref.void_value; |
| 18621 | 18699 | } |
| 18622 | 18700 | |
| 18623 | | fn zirBuiltinExtern( |
| 18701 | fn resolveExternOptions( |
| 18624 | 18702 | sema: *Sema, |
| 18625 | 18703 | block: *Block, |
| 18626 | | extended: Zir.Inst.Extended.InstData, |
| 18627 | | ) CompileError!Air.Inst.Ref { |
| 18628 | | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; |
| 18629 | | const src = LazySrcLoc.nodeOffset(extra.node); |
| 18630 | | const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| 18631 | | const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; |
| 18632 | | |
| 18633 | | var ty = try sema.resolveType(block, ty_src, extra.lhs); |
| 18634 | | const options_inst = try sema.resolveInst(extra.rhs); |
| 18704 | src: LazySrcLoc, |
| 18705 | zir_ref: Zir.Inst.Ref, |
| 18706 | ) CompileError!std.builtin.ExternOptions { |
| 18707 | const options_inst = try sema.resolveInst(zir_ref); |
| 18708 | const extern_options_ty = try sema.getBuiltinType(block, src, "ExternOptions"); |
| 18709 | const options = try sema.coerce(block, extern_options_ty, options_inst, src); |
| 18635 | 18710 | const mod = sema.mod; |
| 18636 | 18711 | |
| 18637 | | const options = options: { |
| 18638 | | const extern_options_ty = try sema.getBuiltinType(block, options_src, "ExternOptions"); |
| 18639 | | const options = try sema.coerce(block, extern_options_ty, options_inst, options_src); |
| 18712 | const name_src = sema.maybeOptionsSrc(block, src, "name"); |
| 18713 | const library_src = sema.maybeOptionsSrc(block, src, "library"); |
| 18714 | const linkage_src = sema.maybeOptionsSrc(block, src, "linkage"); |
| 18715 | const thread_local_src = sema.maybeOptionsSrc(block, src, "thread_local"); |
| 18640 | 18716 | |
| 18641 | | const name = try sema.fieldVal(block, options_src, options, "name", options_src); |
| 18642 | | const name_val = try sema.resolveConstValue(block, options_src, name, "name of the extern symbol must be comptime known"); |
| 18717 | const name_ref = try sema.fieldVal(block, src, options, "name", name_src); |
| 18718 | const name_val = try sema.resolveConstValue(block, name_src, name_ref, "name of the extern symbol must be comptime known"); |
| 18719 | const name = try name_val.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena, mod); |
| 18643 | 18720 | |
| 18644 | | const library_name_inst = try sema.fieldVal(block, options_src, options, "library_name", options_src); |
| 18645 | | const library_name_val = try sema.resolveConstValue(block, options_src, library_name_inst, "library in which extern symbol is must be comptime known"); |
| 18721 | const library_name_inst = try sema.fieldVal(block, src, options, "library_name", library_src); |
| 18722 | const library_name_val = try sema.resolveConstValue(block, library_src, library_name_inst, "library in which extern symbol is must be comptime known"); |
| 18646 | 18723 | |
| 18647 | | const linkage = try sema.fieldVal(block, options_src, options, "linkage", options_src); |
| 18648 | | const linkage_val = try sema.resolveConstValue(block, options_src, linkage, "linkage of the extern symbol must be comptime known"); |
| 18724 | const linkage_ref = try sema.fieldVal(block, src, options, "linkage", linkage_src); |
| 18725 | const linkage_val = try sema.resolveConstValue(block, linkage_src, linkage_ref, "linkage of the extern symbol must be comptime known"); |
| 18726 | const linkage = linkage_val.toEnum(std.builtin.GlobalLinkage); |
| 18649 | 18727 | |
| 18650 | | const is_thread_local = try sema.fieldVal(block, options_src, options, "is_thread_local", options_src); |
| 18651 | | const is_thread_local_val = try sema.resolveConstValue(block, options_src, is_thread_local, "threadlocality of the extern symbol must be comptime known"); |
| 18728 | const is_thread_local = try sema.fieldVal(block, src, options, "is_thread_local", thread_local_src); |
| 18729 | const is_thread_local_val = try sema.resolveConstValue(block, thread_local_src, is_thread_local, "threadlocality of the extern symbol must be comptime known"); |
| 18652 | 18730 | |
| 18653 | | var library_name: ?[]const u8 = null; |
| 18654 | | if (!library_name_val.isNull()) { |
| 18655 | | const payload = library_name_val.castTag(.opt_payload).?.data; |
| 18656 | | library_name = try payload.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena, mod); |
| 18731 | const library_name = if (!library_name_val.isNull()) blk: { |
| 18732 | const payload = library_name_val.castTag(.opt_payload).?.data; |
| 18733 | const library_name = try payload.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena, mod); |
| 18734 | if (library_name.len == 0) { |
| 18735 | return sema.fail(block, library_src, "library name name cannot be empty", .{}); |
| 18657 | 18736 | } |
| 18737 | break :blk try sema.handleExternLibName(block, library_src, library_name); |
| 18738 | } else null; |
| 18658 | 18739 | |
| 18659 | | break :options std.builtin.ExternOptions{ |
| 18660 | | .name = try name_val.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena, mod), |
| 18661 | | .library_name = library_name, |
| 18662 | | .linkage = linkage_val.toEnum(std.builtin.GlobalLinkage), |
| 18663 | | .is_thread_local = is_thread_local_val.toBool(), |
| 18664 | | }; |
| 18665 | | }; |
| 18666 | | |
| 18667 | | if (!ty.isPtrAtRuntime()) { |
| 18668 | | return sema.fail(block, options_src, "expected (optional) pointer", .{}); |
| 18740 | if (name.len == 0) { |
| 18741 | return sema.fail(block, name_src, "extern symbol name cannot be empty", .{}); |
| 18669 | 18742 | } |
| 18670 | 18743 | |
| 18671 | | if (options.name.len == 0) { |
| 18672 | | return sema.fail(block, options_src, "extern symbol name cannot be empty", .{}); |
| 18744 | if (linkage != .Weak and linkage != .Strong) { |
| 18745 | return sema.fail(block, linkage_src, "extern symbol must use strong or weak linkage", .{}); |
| 18673 | 18746 | } |
| 18674 | 18747 | |
| 18675 | | if (options.linkage != .Weak and options.linkage != .Strong) { |
| 18676 | | return sema.fail(block, options_src, "extern symbol must use strong or weak linkage", .{}); |
| 18748 | return std.builtin.ExternOptions{ |
| 18749 | .name = name, |
| 18750 | .library_name = library_name, |
| 18751 | .linkage = linkage, |
| 18752 | .is_thread_local = is_thread_local_val.toBool(), |
| 18753 | }; |
| 18754 | } |
| 18755 | |
| 18756 | fn zirBuiltinExtern( |
| 18757 | sema: *Sema, |
| 18758 | block: *Block, |
| 18759 | extended: Zir.Inst.Extended.InstData, |
| 18760 | ) CompileError!Air.Inst.Ref { |
| 18761 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; |
| 18762 | const src = LazySrcLoc.nodeOffset(extra.node); |
| 18763 | const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| 18764 | const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; |
| 18765 | |
| 18766 | var ty = try sema.resolveType(block, ty_src, extra.lhs); |
| 18767 | if (!ty.isPtrAtRuntime()) { |
| 18768 | return sema.fail(block, ty_src, "expected (optional) pointer", .{}); |
| 18677 | 18769 | } |
| 18678 | 18770 | |
| 18771 | const options = sema.resolveExternOptions(block, .unneeded, extra.rhs) catch |err| switch (err) { |
| 18772 | error.NeededSourceLocation => { |
| 18773 | _ = try sema.resolveExternOptions(block, options_src, extra.rhs); |
| 18774 | return error.AnalysisFail; |
| 18775 | }, |
| 18776 | else => |e| return e, |
| 18777 | }; |
| 18778 | |
| 18679 | 18779 | if (options.linkage == .Weak and !ty.ptrAllowsZero()) { |
| 18680 | 18780 | ty = try Type.optional(sema.arena, ty); |
| 18681 | 18781 | } |
| 18682 | 18782 | |
| 18683 | 18783 | // TODO check duplicate extern |
| 18684 | 18784 | |
| 18685 | | const new_decl_index = try mod.allocateNewDecl(sema.owner_decl.src_namespace, sema.owner_decl.src_node, null); |
| 18686 | | errdefer mod.destroyDecl(new_decl_index); |
| 18687 | | const new_decl = mod.declPtr(new_decl_index); |
| 18785 | const new_decl_index = try sema.mod.allocateNewDecl(sema.owner_decl.src_namespace, sema.owner_decl.src_node, null); |
| 18786 | errdefer sema.mod.destroyDecl(new_decl_index); |
| 18787 | const new_decl = sema.mod.declPtr(new_decl_index); |
| 18688 | 18788 | new_decl.name = try sema.gpa.dupeZ(u8, options.name); |
| 18689 | 18789 | |
| 18690 | 18790 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); |
| ... | ... | @@ -18704,13 +18804,6 @@ fn zirBuiltinExtern( |
| 18704 | 18804 | .lib_name = null, |
| 18705 | 18805 | }; |
| 18706 | 18806 | |
| 18707 | | if (options.library_name) |library_name| { |
| 18708 | | if (library_name.len == 0) { |
| 18709 | | return sema.fail(block, options_src, "library name name cannot be empty", .{}); |
| 18710 | | } |
| 18711 | | new_var.lib_name = try sema.handleExternLibName(block, options_src, library_name); |
| 18712 | | } |
| 18713 | | |
| 18714 | 18807 | new_decl.src_line = sema.owner_decl.src_line; |
| 18715 | 18808 | new_decl.ty = try ty.copy(new_decl_arena_allocator); |
| 18716 | 18809 | new_decl.val = try Value.Tag.variable.create(new_decl_arena_allocator, new_var); |
| ... | ... | @@ -18718,7 +18811,7 @@ fn zirBuiltinExtern( |
| 18718 | 18811 | new_decl.@"linksection" = null; |
| 18719 | 18812 | new_decl.has_tv = true; |
| 18720 | 18813 | new_decl.analysis = .complete; |
| 18721 | | new_decl.generation = mod.generation; |
| 18814 | new_decl.generation = sema.mod.generation; |
| 18722 | 18815 | |
| 18723 | 18816 | const arena_state = try new_decl_arena_allocator.create(std.heap.ArenaAllocator.State); |
| 18724 | 18817 | arena_state.* = new_decl_arena.state; |