authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-07 16:05:44-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-07 16:06:25-07:00
log6ac204714236eaeaea5dc66afddbe158966b2532
tree3e0a8b35ba2aa6ec803861cfc9a6b0d8fe80e49f
parent47531b7d9389c45af3e46b623235792f14a40ff2

stage2: implement extern functions


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 };
28882891
...@@ -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 });
32273231
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 }
80118016
8012 if (args.cc != .none or args.lib_name != 0 or8017 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 {
282282
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 }
29622958
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 };
29712976
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 };
28872889
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 }
29322930
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;
29352944
...@@ -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 };
22232224
...@@ -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);
42524257
4253 if (body.len == 0) {4258 if (body.len == 0) {