aboutsummaryrefslogtreecommitdiff
path: root/src/Module.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-12-28 17:15:29 -0700
committerAndrew Kelley <andrew@ziglang.org>2020-12-28 17:15:29 -0700
commit87c6341b61aa54301aa98fea1a449fff40ba25af (patch)
treea9c9c60c20bb600314cebb2dce25579dca94ee5f /src/Module.zig
parent2df2f0020f4ddc41b3b914cd17efcb403cf0f6ad (diff)
downloadzig-87c6341b61aa54301aa98fea1a449fff40ba25af.tar.gz
zig-87c6341b61aa54301aa98fea1a449fff40ba25af.zip
stage2: add extern functions
and improve the C backend enough to support Hello World (almost)
Diffstat (limited to 'src/Module.zig')
-rw-r--r--src/Module.zig97
1 files changed, 86 insertions, 11 deletions
diff --git a/src/Module.zig b/src/Module.zig
index c0b7011f43..dbb845116a 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -277,6 +277,8 @@ pub const Decl = struct {
};
/// Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.
+/// Extern functions do not have this data structure; they are represented by
+/// the `Decl` only, with a `Value` tag of `extern_fn`.
pub const Fn = struct {
/// This memory owned by the Decl's TypedValue.Managed arena allocator.
analysis: union(enum) {
@@ -1010,8 +1012,6 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
defer fn_type_scope.instructions.deinit(self.gpa);
decl.is_pub = fn_proto.getVisibToken() != null;
- const body_node = fn_proto.getBodyNode() orelse
- return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{});
const param_decls = fn_proto.params();
const param_types = try fn_type_scope.arena.alloc(*zir.Inst, param_decls.len);
@@ -1083,6 +1083,36 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
const fn_type = try zir_sema.analyzeBodyValueAsType(self, &block_scope, fn_type_inst, .{
.instructions = fn_type_scope.instructions.items,
});
+ const body_node = fn_proto.getBodyNode() orelse {
+ // Extern function.
+ var type_changed = true;
+ if (decl.typedValueManaged()) |tvm| {
+ type_changed = !tvm.typed_value.ty.eql(fn_type);
+
+ tvm.deinit(self.gpa);
+ }
+ const value_payload = try decl_arena.allocator.create(Value.Payload.ExternFn);
+ value_payload.* = .{ .decl = decl };
+
+ decl_arena_state.* = decl_arena.state;
+ decl.typed_value = .{
+ .most_recent = .{
+ .typed_value = .{
+ .ty = fn_type,
+ .val = Value.initPayload(&value_payload.base),
+ },
+ .arena = decl_arena_state,
+ },
+ };
+ decl.analysis = .complete;
+ decl.generation = self.generation;
+
+ try self.comp.bin_file.allocateDeclIndexes(decl);
+ try self.comp.work_queue.writeItem(.{ .codegen_decl = decl });
+
+ return type_changed;
+ };
+
const new_func = try decl_arena.allocator.create(Fn);
const fn_payload = try decl_arena.allocator.create(Value.Payload.Function);
@@ -1899,7 +1929,13 @@ pub fn resolveDefinedValue(self: *Module, scope: *Scope, base: *Inst) !?Value {
return null;
}
-pub fn analyzeExport(self: *Module, scope: *Scope, src: usize, borrowed_symbol_name: []const u8, exported_decl: *Decl) !void {
+pub fn analyzeExport(
+ self: *Module,
+ scope: *Scope,
+ src: usize,
+ borrowed_symbol_name: []const u8,
+ exported_decl: *Decl,
+) !void {
try self.ensureDeclAnalyzed(exported_decl);
const typed_value = exported_decl.typed_value.most_recent.typed_value;
switch (typed_value.ty.zigTypeTag()) {
@@ -2801,16 +2837,47 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
}
}
- // *[N]T to []T
- if (inst.ty.isSinglePointer() and dest_type.isSlice() and
- (!inst.ty.isConstPtr() or dest_type.isConstPtr()))
- {
+ // Coercions where the source is a single pointer to an array.
+ src_array_ptr: {
+ if (!inst.ty.isSinglePointer()) break :src_array_ptr;
const array_type = inst.ty.elemType();
+ if (array_type.zigTypeTag() != .Array) break :src_array_ptr;
+ const array_elem_type = array_type.elemType();
+ if (inst.ty.isConstPtr() and !dest_type.isConstPtr()) break :src_array_ptr;
+ if (inst.ty.isVolatilePtr() and !dest_type.isVolatilePtr()) break :src_array_ptr;
+
const dst_elem_type = dest_type.elemType();
- if (array_type.zigTypeTag() == .Array and
- coerceInMemoryAllowed(dst_elem_type, array_type.elemType()) == .ok)
- {
- return self.coerceArrayPtrToSlice(scope, dest_type, inst);
+ switch (coerceInMemoryAllowed(dst_elem_type, array_elem_type)) {
+ .ok => {},
+ .no_match => break :src_array_ptr,
+ }
+
+ switch (dest_type.ptrSize()) {
+ .Slice => {
+ // *[N]T to []T
+ return self.coerceArrayPtrToSlice(scope, dest_type, inst);
+ },
+ .C => {
+ // *[N]T to [*c]T
+ return self.coerceArrayPtrToMany(scope, dest_type, inst);
+ },
+ .Many => {
+ // *[N]T to [*]T
+ // *[N:s]T to [*:s]T
+ const src_sentinel = array_type.sentinel();
+ const dst_sentinel = dest_type.sentinel();
+ if (src_sentinel == null and dst_sentinel == null)
+ return self.coerceArrayPtrToMany(scope, dest_type, inst);
+
+ if (src_sentinel) |src_s| {
+ if (dst_sentinel) |dst_s| {
+ if (src_s.eql(dst_s)) {
+ return self.coerceArrayPtrToMany(scope, dest_type, inst);
+ }
+ }
+ }
+ },
+ .One => {},
}
}
@@ -2918,6 +2985,14 @@ fn coerceArrayPtrToSlice(self: *Module, scope: *Scope, dest_type: Type, inst: *I
return self.fail(scope, inst.src, "TODO implement coerceArrayPtrToSlice runtime instruction", .{});
}
+fn coerceArrayPtrToMany(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
+ if (inst.value()) |val| {
+ // The comptime Value representation is compatible with both types.
+ return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
+ }
+ return self.fail(scope, inst.src, "TODO implement coerceArrayPtrToMany runtime instruction", .{});
+}
+
pub fn fail(self: *Module, scope: *Scope, src: usize, comptime format: []const u8, args: anytype) InnerError {
@setCold(true);
const err_msg = try Compilation.ErrorMsg.create(self.gpa, src, format, args);