| author | |
| committer | |
| log | 6ac204714236eaeaea5dc66afddbe158966b2532 |
| tree | 3e0a8b35ba2aa6ec803861cfc9a6b0d8fe80e49f |
| parent | 47531b7d9389c45af3e46b623235792f14a40ff2 |
4 files changed, 57 insertions(+), 20 deletions(-)
src/AstGen.zig+8-1| ... | @@ -1081,6 +1081,7 @@ fn fnProtoExpr( | ... | @@ -1081,6 +1081,7 @@ fn fnProtoExpr( |
| 1081 | .is_var_args = is_var_args, | 1081 | .is_var_args = is_var_args, |
| 1082 | .is_inferred_error = false, | 1082 | .is_inferred_error = false, |
| 1083 | .is_test = false, | 1083 | .is_test = false, |
| 1084 | .is_extern = false, | ||
| 1084 | }); | 1085 | }); |
| 1085 | return rvalue(gz, scope, rl, result, fn_proto.ast.proto_node); | 1086 | return rvalue(gz, scope, rl, result, fn_proto.ast.proto_node); |
| 1086 | } | 1087 | } |
| ... | @@ -2807,6 +2808,7 @@ fn fnDecl( | ... | @@ -2807,6 +2808,7 @@ fn fnDecl( |
| 2807 | .is_var_args = is_var_args, | 2808 | .is_var_args = is_var_args, |
| 2808 | .is_inferred_error = false, | 2809 | .is_inferred_error = false, |
| 2809 | .is_test = false, | 2810 | .is_test = false, |
| 2811 | .is_extern = true, | ||
| 2810 | }); | 2812 | }); |
| 2811 | } else func: { | 2813 | } else func: { |
| 2812 | if (is_var_args) { | 2814 | if (is_var_args) { |
| ... | @@ -2883,6 +2885,7 @@ fn fnDecl( | ... | @@ -2883,6 +2885,7 @@ fn fnDecl( |
| 2883 | .is_var_args = is_var_args, | 2885 | .is_var_args = is_var_args, |
| 2884 | .is_inferred_error = is_inferred_error, | 2886 | .is_inferred_error = is_inferred_error, |
| 2885 | .is_test = false, | 2887 | .is_test = false, |
| 2888 | .is_extern = false, | ||
| 2886 | }); | 2889 | }); |
| 2887 | }; | 2890 | }; |
| 2888 | 2891 | ||
| ... | @@ -3223,6 +3226,7 @@ fn testDecl( | ... | @@ -3223,6 +3226,7 @@ fn testDecl( |
| 3223 | .is_var_args = false, | 3226 | .is_var_args = false, |
| 3224 | .is_inferred_error = true, | 3227 | .is_inferred_error = true, |
| 3225 | .is_test = true, | 3228 | .is_test = true, |
| 3229 | .is_extern = false, | ||
| 3226 | }); | 3230 | }); |
| 3227 | 3231 | ||
| 3228 | _ = try decl_block.addBreak(.break_inline, block_inst, func_inst); | 3232 | _ = try decl_block.addBreak(.break_inline, block_inst, func_inst); |
| ... | @@ -7973,6 +7977,7 @@ const GenZir = struct { | ... | @@ -7973,6 +7977,7 @@ const GenZir = struct { |
| 7973 | is_var_args: bool, | 7977 | is_var_args: bool, |
| 7974 | is_inferred_error: bool, | 7978 | is_inferred_error: bool, |
| 7975 | is_test: bool, | 7979 | is_test: bool, |
| 7980 | is_extern: bool, | ||
| 7976 | }) !Zir.Inst.Ref { | 7981 | }) !Zir.Inst.Ref { |
| 7977 | assert(args.src_node != 0); | 7982 | assert(args.src_node != 0); |
| 7978 | assert(args.ret_ty != .none); | 7983 | assert(args.ret_ty != .none); |
| ... | @@ -8010,7 +8015,8 @@ const GenZir = struct { | ... | @@ -8010,7 +8015,8 @@ const GenZir = struct { |
| 8010 | } | 8015 | } |
| 8011 | 8016 | ||
| 8012 | if (args.cc != .none or args.lib_name != 0 or | 8017 | if (args.cc != .none or args.lib_name != 0 or |
| 8013 | args.is_var_args or args.is_test or args.align_inst != .none) | 8018 | args.is_var_args or args.is_test or args.align_inst != .none or |
| 8019 | args.is_extern) | ||
| 8014 | { | 8020 | { |
| 8015 | try astgen.extra.ensureUnusedCapacity( | 8021 | try astgen.extra.ensureUnusedCapacity( |
| 8016 | gpa, | 8022 | gpa, |
| ... | @@ -8051,6 +8057,7 @@ const GenZir = struct { | ... | @@ -8051,6 +8057,7 @@ const GenZir = struct { |
| 8051 | .has_cc = args.cc != .none, | 8057 | .has_cc = args.cc != .none, |
| 8052 | .has_align = args.align_inst != .none, | 8058 | .has_align = args.align_inst != .none, |
| 8053 | .is_test = args.is_test, | 8059 | .is_test = args.is_test, |
| 8060 | .is_extern = args.is_extern, | ||
| 8054 | }), | 8061 | }), |
| 8055 | .operand = payload_index, | 8062 | .operand = payload_index, |
| 8056 | } }, | 8063 | } }, |
src/Module.zig+29-14| ... | @@ -282,13 +282,10 @@ pub const Decl = struct { | ... | @@ -282,13 +282,10 @@ pub const Decl = struct { |
| 282 | 282 | ||
| 283 | pub fn destroy(decl: *Decl, module: *Module) void { | 283 | pub fn destroy(decl: *Decl, module: *Module) void { |
| 284 | const gpa = module.gpa; | 284 | const gpa = module.gpa; |
| 285 | log.debug("destroy Decl {*} ({s})", .{ decl, decl.name }); | 285 | log.debug("destroy {*} ({s})", .{ decl, decl.name }); |
| 286 | decl.clearName(gpa); | 286 | decl.clearName(gpa); |
| 287 | if (decl.has_tv) { | 287 | if (decl.has_tv) { |
| 288 | if (decl.getFunction()) |func| { | 288 | if (decl.val.getTypeNamespace()) |namespace| { |
| 289 | func.deinit(gpa); | ||
| 290 | gpa.destroy(func); | ||
| 291 | } else if (decl.val.getTypeNamespace()) |namespace| { | ||
| 292 | if (namespace.getDecl() == decl) { | 289 | if (namespace.getDecl() == decl) { |
| 293 | namespace.clearDecls(module); | 290 | namespace.clearDecls(module); |
| 294 | } | 291 | } |
| ... | @@ -470,7 +467,6 @@ pub const Decl = struct { | ... | @@ -470,7 +467,6 @@ pub const Decl = struct { |
| 470 | /// otherwise null. | 467 | /// otherwise null. |
| 471 | pub fn getFunction(decl: *Decl) ?*Fn { | 468 | pub fn getFunction(decl: *Decl) ?*Fn { |
| 472 | if (!decl.has_tv) return null; | 469 | if (!decl.has_tv) return null; |
| 473 | if (decl.ty.zigTypeTag() != .Fn) return null; | ||
| 474 | const func = (decl.val.castTag(.function) orelse return null).data; | 470 | const func = (decl.val.castTag(.function) orelse return null).data; |
| 475 | if (func.owner_decl != decl) return null; | 471 | if (func.owner_decl != decl) return null; |
| 476 | return func; | 472 | return func; |
| ... | @@ -2960,17 +2956,26 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { | ... | @@ -2960,17 +2956,26 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { |
| 2960 | decl.clearValues(gpa); | 2956 | decl.clearValues(gpa); |
| 2961 | } | 2957 | } |
| 2962 | 2958 | ||
| 2963 | const new_variable = try decl_arena.allocator.create(Var); | 2959 | const copied_val = try decl_tv.val.copy(&decl_arena.allocator); |
| 2964 | new_variable.* = .{ | 2960 | const is_extern_fn = copied_val.tag() == .extern_fn; |
| 2965 | .owner_decl = decl, | 2961 | |
| 2966 | .init = try decl_tv.val.copy(&decl_arena.allocator), | 2962 | // TODO: also avoid allocating this Var structure if `!is_mutable`. |
| 2967 | .is_extern = is_extern, | 2963 | // I think this will require adjusting Sema to copy the value or something |
| 2968 | .is_mutable = is_mutable, | 2964 | // like that; otherwise it causes use of undefined value when freeing resources. |
| 2969 | .is_threadlocal = is_threadlocal, | 2965 | const decl_val: Value = if (is_extern_fn) copied_val else blk: { |
| 2966 | const new_variable = try decl_arena.allocator.create(Var); | ||
| 2967 | new_variable.* = .{ | ||
| 2968 | .owner_decl = decl, | ||
| 2969 | .init = copied_val, | ||
| 2970 | .is_extern = is_extern, | ||
| 2971 | .is_mutable = is_mutable, | ||
| 2972 | .is_threadlocal = is_threadlocal, | ||
| 2973 | }; | ||
| 2974 | break :blk try Value.Tag.variable.create(&decl_arena.allocator, new_variable); | ||
| 2970 | }; | 2975 | }; |
| 2971 | 2976 | ||
| 2972 | decl.ty = try decl_tv.ty.copy(&decl_arena.allocator); | 2977 | decl.ty = try decl_tv.ty.copy(&decl_arena.allocator); |
| 2973 | decl.val = try Value.Tag.variable.create(&decl_arena.allocator, new_variable); | 2978 | decl.val = decl_val; |
| 2974 | decl.align_val = try align_val.copy(&decl_arena.allocator); | 2979 | decl.align_val = try align_val.copy(&decl_arena.allocator); |
| 2975 | decl.linksection_val = try linksection_val.copy(&decl_arena.allocator); | 2980 | decl.linksection_val = try linksection_val.copy(&decl_arena.allocator); |
| 2976 | decl.has_tv = true; | 2981 | decl.has_tv = true; |
| ... | @@ -2984,6 +2989,16 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { | ... | @@ -2984,6 +2989,16 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { |
| 2984 | // The scope needs to have the decl in it. | 2989 | // The scope needs to have the decl in it. |
| 2985 | try mod.analyzeExport(&block_scope.base, export_src, mem.spanZ(decl.name), decl); | 2990 | try mod.analyzeExport(&block_scope.base, export_src, mem.spanZ(decl.name), decl); |
| 2986 | } | 2991 | } |
| 2992 | |||
| 2993 | if (decl.val.tag() == .extern_fn) { | ||
| 2994 | try mod.comp.bin_file.allocateDeclIndexes(decl); | ||
| 2995 | try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl }); | ||
| 2996 | |||
| 2997 | if (type_changed and mod.emit_h != null) { | ||
| 2998 | try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl }); | ||
| 2999 | } | ||
| 3000 | } | ||
| 3001 | |||
| 2987 | return type_changed; | 3002 | return type_changed; |
| 2988 | } | 3003 | } |
| 2989 | } | 3004 | } |
src/Sema.zig+14-4| ... | @@ -2819,6 +2819,7 @@ fn zirFunc( | ... | @@ -2819,6 +2819,7 @@ fn zirFunc( |
| 2819 | Value.initTag(.null_value), | 2819 | Value.initTag(.null_value), |
| 2820 | false, | 2820 | false, |
| 2821 | inferred_error_set, | 2821 | inferred_error_set, |
| 2822 | false, | ||
| 2822 | src_locs, | 2823 | src_locs, |
| 2823 | null, | 2824 | null, |
| 2824 | ); | 2825 | ); |
| ... | @@ -2835,6 +2836,7 @@ fn funcCommon( | ... | @@ -2835,6 +2836,7 @@ fn funcCommon( |
| 2835 | align_val: Value, | 2836 | align_val: Value, |
| 2836 | var_args: bool, | 2837 | var_args: bool, |
| 2837 | inferred_error_set: bool, | 2838 | inferred_error_set: bool, |
| 2839 | is_extern: bool, | ||
| 2838 | src_locs: Zir.Inst.Func.SrcLocs, | 2840 | src_locs: Zir.Inst.Func.SrcLocs, |
| 2839 | opt_lib_name: ?[]const u8, | 2841 | opt_lib_name: ?[]const u8, |
| 2840 | ) InnerError!*Inst { | 2842 | ) InnerError!*Inst { |
| ... | @@ -2885,10 +2887,6 @@ fn funcCommon( | ... | @@ -2885,10 +2887,6 @@ fn funcCommon( |
| 2885 | }); | 2887 | }); |
| 2886 | }; | 2888 | }; |
| 2887 | 2889 | ||
| 2888 | if (body_inst == 0) { | ||
| 2889 | return mod.constType(sema.arena, src, fn_ty); | ||
| 2890 | } | ||
| 2891 | |||
| 2892 | if (opt_lib_name) |lib_name| blk: { | 2890 | if (opt_lib_name) |lib_name| blk: { |
| 2893 | const lib_name_src: LazySrcLoc = .{ .node_offset_lib_name = src_node_offset }; | 2891 | const lib_name_src: LazySrcLoc = .{ .node_offset_lib_name = src_node_offset }; |
| 2894 | log.debug("extern fn symbol expected in lib '{s}'", .{lib_name}); | 2892 | log.debug("extern fn symbol expected in lib '{s}'", .{lib_name}); |
| ... | @@ -2930,6 +2928,17 @@ fn funcCommon( | ... | @@ -2930,6 +2928,17 @@ fn funcCommon( |
| 2930 | } | 2928 | } |
| 2931 | } | 2929 | } |
| 2932 | 2930 | ||
| 2931 | if (is_extern) { | ||
| 2932 | return sema.mod.constInst(sema.arena, src, .{ | ||
| 2933 | .ty = fn_ty, | ||
| 2934 | .val = try Value.Tag.extern_fn.create(sema.arena, sema.owner_decl), | ||
| 2935 | }); | ||
| 2936 | } | ||
| 2937 | |||
| 2938 | if (body_inst == 0) { | ||
| 2939 | return mod.constType(sema.arena, src, fn_ty); | ||
| 2940 | } | ||
| 2941 | |||
| 2933 | const is_inline = fn_ty.fnCallingConvention() == .Inline; | 2942 | const is_inline = fn_ty.fnCallingConvention() == .Inline; |
| 2934 | const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .queued; | 2943 | const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .queued; |
| 2935 | 2944 | ||
| ... | @@ -5795,6 +5804,7 @@ fn zirFuncExtended( | ... | @@ -5795,6 +5804,7 @@ fn zirFuncExtended( |
| 5795 | align_val, | 5804 | align_val, |
| 5796 | small.is_var_args, | 5805 | small.is_var_args, |
| 5797 | small.is_inferred_error, | 5806 | small.is_inferred_error, |
| 5807 | small.is_extern, | ||
| 5798 | src_locs, | 5808 | src_locs, |
| 5799 | lib_name, | 5809 | lib_name, |
| 5800 | ); | 5810 | ); |
src/Zir.zig+6-1| ... | @@ -2217,7 +2217,8 @@ pub const Inst = struct { | ... | @@ -2217,7 +2217,8 @@ pub const Inst = struct { |
| 2217 | has_cc: bool, | 2217 | has_cc: bool, |
| 2218 | has_align: bool, | 2218 | has_align: bool, |
| 2219 | is_test: bool, | 2219 | is_test: bool, |
| 2220 | _: u10 = undefined, | 2220 | is_extern: bool, |
| 2221 | _: u9 = undefined, | ||
| 2221 | }; | 2222 | }; |
| 2222 | }; | 2223 | }; |
| 2223 | 2224 | ||
| ... | @@ -4103,6 +4104,7 @@ const Writer = struct { | ... | @@ -4103,6 +4104,7 @@ const Writer = struct { |
| 4103 | extra.data.return_type, | 4104 | extra.data.return_type, |
| 4104 | inferred_error_set, | 4105 | inferred_error_set, |
| 4105 | false, | 4106 | false, |
| 4107 | false, | ||
| 4106 | .none, | 4108 | .none, |
| 4107 | .none, | 4109 | .none, |
| 4108 | body, | 4110 | body, |
| ... | @@ -4150,6 +4152,7 @@ const Writer = struct { | ... | @@ -4150,6 +4152,7 @@ const Writer = struct { |
| 4150 | extra.data.return_type, | 4152 | extra.data.return_type, |
| 4151 | small.is_inferred_error, | 4153 | small.is_inferred_error, |
| 4152 | small.is_var_args, | 4154 | small.is_var_args, |
| 4155 | small.is_extern, | ||
| 4153 | cc, | 4156 | cc, |
| 4154 | align_inst, | 4157 | align_inst, |
| 4155 | body, | 4158 | body, |
| ... | @@ -4232,6 +4235,7 @@ const Writer = struct { | ... | @@ -4232,6 +4235,7 @@ const Writer = struct { |
| 4232 | ret_ty: Inst.Ref, | 4235 | ret_ty: Inst.Ref, |
| 4233 | inferred_error_set: bool, | 4236 | inferred_error_set: bool, |
| 4234 | var_args: bool, | 4237 | var_args: bool, |
| 4238 | is_extern: bool, | ||
| 4235 | cc: Inst.Ref, | 4239 | cc: Inst.Ref, |
| 4236 | align_inst: Inst.Ref, | 4240 | align_inst: Inst.Ref, |
| 4237 | body: []const Inst.Index, | 4241 | body: []const Inst.Index, |
| ... | @@ -4248,6 +4252,7 @@ const Writer = struct { | ... | @@ -4248,6 +4252,7 @@ const Writer = struct { |
| 4248 | try self.writeOptionalInstRef(stream, ", cc=", cc); | 4252 | try self.writeOptionalInstRef(stream, ", cc=", cc); |
| 4249 | try self.writeOptionalInstRef(stream, ", align=", align_inst); | 4253 | try self.writeOptionalInstRef(stream, ", align=", align_inst); |
| 4250 | try self.writeFlag(stream, ", vargs", var_args); | 4254 | try self.writeFlag(stream, ", vargs", var_args); |
| 4255 | try self.writeFlag(stream, ", extern", is_extern); | ||
| 4251 | try self.writeFlag(stream, ", inferror", inferred_error_set); | 4256 | try self.writeFlag(stream, ", inferror", inferred_error_set); |
| 4252 | 4257 | ||
| 4253 | if (body.len == 0) { | 4258 | if (body.len == 0) { |