diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-09-21 00:01:30 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-09-21 00:01:30 -0400 |
| commit | 5269cbea202c6a81108390f4c47bc8a04fc6d1ff (patch) | |
| tree | a95896bf83bb427953a6a33d037698e30c05d8f8 /src | |
| parent | 1ad905c71e0896295d4781853cd577bbe1b4111a (diff) | |
| parent | 0c74ce1156d6a967cd089cd4657575a3e22bb782 (diff) | |
| download | zig-5269cbea202c6a81108390f4c47bc8a04fc6d1ff.tar.gz zig-5269cbea202c6a81108390f4c47bc8a04fc6d1ff.zip | |
Merge pull request #9797 from Vexu/stage2
stage2: implement cImport
Diffstat (limited to 'src')
| -rw-r--r-- | src/AstGen.zig | 11 | ||||
| -rw-r--r-- | src/Compilation.zig | 2 | ||||
| -rw-r--r-- | src/Module.zig | 3 | ||||
| -rw-r--r-- | src/Sema.zig | 295 | ||||
| -rw-r--r-- | src/print_zir.zig | 18 | ||||
| -rw-r--r-- | src/type.zig | 2 |
6 files changed, 302 insertions, 29 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig index f1eabe4c0c..176203d37f 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -7082,7 +7082,7 @@ fn builtinCall( .bit_cast => return bitCast( gz, scope, rl, node, params[0], params[1]), .TypeOf => return typeOf( gz, scope, rl, node, params), .union_init => return unionInit(gz, scope, rl, node, params), - .c_import => return cImport( gz, scope, rl, node, params[0]), + .c_import => return cImport( gz, scope, node, params[0]), .@"export" => { const node_tags = tree.nodes.items(.tag); @@ -7269,6 +7269,7 @@ fn builtinCall( return rvalue(gz, rl, result, node); }, .c_define => { + if (!gz.c_import) return gz.astgen.failNode(node, "C define valid only inside C import block", .{}); const name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[0]); const value = try comptimeExpr(gz, scope, .none, params[1]); const result = try gz.addExtendedPayload(.c_define, Zir.Inst.BinNode{ @@ -7641,6 +7642,8 @@ fn simpleCBuiltin( operand_node: Ast.Node.Index, tag: Zir.Inst.Extended, ) InnerError!Zir.Inst.Ref { + const name: []const u8 = if (tag == .c_undef) "C undef" else "C include"; + if (!gz.c_import) return gz.astgen.failNode(node, "{s} valid only inside C import block", .{name}); const operand = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, operand_node); _ = try gz.addExtendedPayload(tag, Zir.Inst.UnNode{ .node = gz.nodeIndexToRelative(node), @@ -7689,7 +7692,6 @@ fn shiftOp( fn cImport( gz: *GenZir, scope: *Scope, - rl: ResultLoc, node: Ast.Node.Index, body_node: Ast.Node.Index, ) InnerError!Zir.Inst.Ref { @@ -7698,6 +7700,7 @@ fn cImport( var block_scope = gz.makeSubBlock(scope); block_scope.force_comptime = true; + block_scope.c_import = true; defer block_scope.instructions.deinit(gpa); const block_inst = try gz.addBlock(.c_import, node); @@ -7708,7 +7711,7 @@ fn cImport( try block_scope.setBlockBody(block_inst); try gz.instructions.append(gpa, block_inst); - return rvalue(gz, rl, .void_value, node); + return indexToRef(block_inst); } fn overflowArithmetic( @@ -9025,6 +9028,7 @@ const GenZir = struct { base: Scope = Scope{ .tag = base_tag }, force_comptime: bool, in_defer: bool, + c_import: bool = false, /// How decls created in this scope should be named. anon_name_strategy: Zir.Inst.NameStrategy = .anon, /// The containing decl AST node. @@ -9070,6 +9074,7 @@ const GenZir = struct { return .{ .force_comptime = gz.force_comptime, .in_defer = gz.in_defer, + .c_import = gz.c_import, .decl_node_index = gz.decl_node_index, .decl_line = gz.decl_line, .parent = scope, diff --git a/src/Compilation.zig b/src/Compilation.zig index c1dfe91dc2..53e643acb8 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2644,7 +2644,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult { const dep_basename = std.fs.path.basename(out_dep_path); try man.addDepFilePost(zig_cache_tmp_dir, dep_basename); - try comp.stage1_cache_manifest.addDepFilePost(zig_cache_tmp_dir, dep_basename); + if (build_options.is_stage1 and comp.bin_file.options.use_stage1) try comp.stage1_cache_manifest.addDepFilePost(zig_cache_tmp_dir, dep_basename); const digest = man.final(); const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest }); diff --git a/src/Module.zig b/src/Module.zig index 500c34bcb0..6a183db21f 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -1325,6 +1325,8 @@ pub const Scope = struct { /// when null, it is determined by build mode, changed by @setRuntimeSafety want_safety: ?bool = null, + c_import_buf: ?*std.ArrayList(u8) = null, + const Param = struct { /// `noreturn` means `anytype`. ty: Type, @@ -1377,6 +1379,7 @@ pub const Scope = struct { .runtime_loop = parent.runtime_loop, .runtime_index = parent.runtime_index, .want_safety = parent.want_safety, + .c_import_buf = parent.c_import_buf, }; } diff --git a/src/Sema.zig b/src/Sema.zig index ff32ce49ca..786db21b4a 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -83,6 +83,7 @@ const Decl = Module.Decl; const LazySrcLoc = Module.LazySrcLoc; const RangeSet = @import("RangeSet.zig"); const target_util = @import("target.zig"); +const Package = @import("Package.zig"); pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Ref); @@ -2138,10 +2139,77 @@ fn zirCImport(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) Com const tracy = trace(@src()); defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[inst].pl_node; - const src = inst_data.src(); + const pl_node = sema.code.instructions.items(.data)[inst].pl_node; + const src = pl_node.src(); + const extra = sema.code.extraData(Zir.Inst.Block, pl_node.payload_index); + const body = sema.code.extra[extra.end..][0..extra.data.body_len]; + + // we check this here to avoid undefined symbols + if (!@import("build_options").have_llvm) + return sema.mod.fail(&parent_block.base, src, "cannot do C import on Zig compiler not built with LLVM-extension", .{}); + + var c_import_buf = std.ArrayList(u8).init(sema.gpa); + defer c_import_buf.deinit(); + + var child_block: Scope.Block = .{ + .parent = parent_block, + .sema = sema, + .src_decl = parent_block.src_decl, + .instructions = .{}, + .inlining = parent_block.inlining, + .is_comptime = parent_block.is_comptime, + .c_import_buf = &c_import_buf, + }; + defer child_block.instructions.deinit(sema.gpa); + + _ = try sema.analyzeBody(&child_block, body); + + const c_import_res = sema.mod.comp.cImport(c_import_buf.items) catch |err| + return sema.mod.fail(&child_block.base, src, "C import failed: {s}", .{@errorName(err)}); + + if (c_import_res.errors.len != 0) { + const msg = msg: { + const msg = try sema.mod.errMsg(&child_block.base, src, "C import failed", .{}); + errdefer msg.destroy(sema.gpa); + + if (!sema.mod.comp.bin_file.options.link_libc) + try sema.mod.errNote(&child_block.base, src, msg, "libc headers not available; compilation does not link against libc", .{}); + + for (c_import_res.errors) |_| { + // TODO integrate with LazySrcLoc + // try sema.mod.errNoteNonLazy(.{}, msg, "{s}", .{clang_err.msg_ptr[0..clang_err.msg_len]}); + // if (clang_err.filename_ptr) |p| p[0..clang_err.filename_len] else "(no file)", + // clang_err.line + 1, + // clang_err.column + 1, + } + @import("clang.zig").Stage2ErrorMsg.delete(c_import_res.errors.ptr, c_import_res.errors.len); + break :msg msg; + }; + return sema.mod.failWithOwnedErrorMsg(&child_block.base, msg); + } + const c_import_pkg = Package.create( + sema.gpa, + null, + c_import_res.out_zig_path, + ) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + else => unreachable, // we pass null for root_src_dir_path + }; + const std_pkg = sema.mod.main_pkg.table.get("std").?; + const builtin_pkg = sema.mod.main_pkg.table.get("builtin").?; + try c_import_pkg.add(sema.gpa, "builtin", builtin_pkg); + try c_import_pkg.add(sema.gpa, "std", std_pkg); + + const result = sema.mod.importPkg(c_import_pkg) catch |err| + return sema.mod.fail(&child_block.base, src, "C import failed: {s}", .{@errorName(err)}); + + sema.mod.astGenFile(result.file) catch |err| + return sema.mod.fail(&child_block.base, src, "C import failed: {s}", .{@errorName(err)}); - return sema.mod.fail(&parent_block.base, src, "TODO: implement Sema.zirCImport", .{}); + try sema.mod.semaFile(result.file); + const file_root_decl = result.file.root_decl.?; + try sema.mod.declareDeclDependency(sema.owner_decl, file_root_decl); + return sema.addType(file_root_decl.ty); } fn zirSuspendBlock(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -6405,10 +6473,41 @@ fn runtimeBoolCmp( fn zirSizeOf(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; const operand_ty = try sema.resolveType(block, operand_src, inst_data.operand); const target = sema.mod.getTarget(); - const abi_size = operand_ty.abiSize(target); + const abi_size = switch (operand_ty.zigTypeTag()) { + .Fn => unreachable, + .NoReturn, + .Undefined, + .Null, + .BoundFn, + .Opaque, + => return sema.mod.fail(&block.base, src, "no size available for type '{}'", .{operand_ty}), + .Type, + .EnumLiteral, + .ComptimeFloat, + .ComptimeInt, + .Void, + => 0, + + .Bool, + .Int, + .Float, + .Pointer, + .Array, + .Struct, + .Optional, + .ErrorUnion, + .ErrorSet, + .Enum, + .Union, + .Vector, + .Frame, + .AnyFrame, + => operand_ty.abiSize(target), + }; return sema.addIntUnsigned(Type.initTag(.comptime_int), abi_size); } @@ -6456,19 +6555,80 @@ fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr const target = sema.mod.getTarget(); switch (ty.zigTypeTag()) { + .Type => return sema.addConstant( + type_info_ty, + try Value.Tag.@"union".create(sema.arena, .{ + .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Type)), + .val = Value.initTag(.unreachable_value), + }), + ), + .Void => return sema.addConstant( + type_info_ty, + try Value.Tag.@"union".create(sema.arena, .{ + .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Void)), + .val = Value.initTag(.unreachable_value), + }), + ), + .Bool => return sema.addConstant( + type_info_ty, + try Value.Tag.@"union".create(sema.arena, .{ + .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Bool)), + .val = Value.initTag(.unreachable_value), + }), + ), + .NoReturn => return sema.addConstant( + type_info_ty, + try Value.Tag.@"union".create(sema.arena, .{ + .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.NoReturn)), + .val = Value.initTag(.unreachable_value), + }), + ), + .ComptimeFloat => return sema.addConstant( + type_info_ty, + try Value.Tag.@"union".create(sema.arena, .{ + .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ComptimeFloat)), + .val = Value.initTag(.unreachable_value), + }), + ), + .ComptimeInt => return sema.addConstant( + type_info_ty, + try Value.Tag.@"union".create(sema.arena, .{ + .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ComptimeInt)), + .val = Value.initTag(.unreachable_value), + }), + ), + .Undefined => return sema.addConstant( + type_info_ty, + try Value.Tag.@"union".create(sema.arena, .{ + .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Undefined)), + .val = Value.initTag(.unreachable_value), + }), + ), + .Null => return sema.addConstant( + type_info_ty, + try Value.Tag.@"union".create(sema.arena, .{ + .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Null)), + .val = Value.initTag(.unreachable_value), + }), + ), + .EnumLiteral => return sema.addConstant( + type_info_ty, + try Value.Tag.@"union".create(sema.arena, .{ + .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.EnumLiteral)), + .val = Value.initTag(.unreachable_value), + }), + ), .Fn => { + const info = ty.fnInfo(); const field_values = try sema.arena.alloc(Value, 6); // calling_convention: CallingConvention, - field_values[0] = try Value.Tag.enum_field_index.create( - sema.arena, - @enumToInt(ty.fnCallingConvention()), - ); + field_values[0] = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.cc)); // alignment: comptime_int, field_values[1] = try Value.Tag.int_u64.create(sema.arena, ty.abiAlignment(target)); // is_generic: bool, - field_values[2] = Value.initTag(.bool_false); // TODO + field_values[2] = if (info.is_generic) Value.initTag(.bool_true) else Value.initTag(.bool_false); // is_var_args: bool, - field_values[3] = Value.initTag(.bool_false); // TODO + field_values[3] = if (info.is_var_args) Value.initTag(.bool_true) else Value.initTag(.bool_false); // return_type: ?type, field_values[4] = try Value.Tag.ty.create(sema.arena, ty.fnReturnType()); // args: []const FnArg, @@ -6477,10 +6637,7 @@ fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr return sema.addConstant( type_info_ty, try Value.Tag.@"union".create(sema.arena, .{ - .tag = try Value.Tag.enum_field_index.create( - sema.arena, - @enumToInt(@typeInfo(std.builtin.TypeInfo).Union.tag_type.?.Fn), - ), + .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Fn)), .val = try Value.Tag.@"struct".create(sema.arena, field_values), }), ); @@ -6499,10 +6656,92 @@ fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr return sema.addConstant( type_info_ty, try Value.Tag.@"union".create(sema.arena, .{ - .tag = try Value.Tag.enum_field_index.create( - sema.arena, - @enumToInt(@typeInfo(std.builtin.TypeInfo).Union.tag_type.?.Int), - ), + .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Int)), + .val = try Value.Tag.@"struct".create(sema.arena, field_values), + }), + ); + }, + .Float => { + const field_values = try sema.arena.alloc(Value, 1); + // bits: comptime_int, + field_values[0] = try Value.Tag.int_u64.create(sema.arena, ty.bitSize(target)); + + return sema.addConstant( + type_info_ty, + try Value.Tag.@"union".create(sema.arena, .{ + .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Float)), + .val = try Value.Tag.@"struct".create(sema.arena, field_values), + }), + ); + }, + .Pointer => { + const info = ty.ptrInfo().data; + const field_values = try sema.arena.alloc(Value, 7); + // size: Size, + field_values[0] = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.size)); + // is_const: bool, + field_values[1] = if (!info.mutable) Value.initTag(.bool_true) else Value.initTag(.bool_false); + // is_volatile: bool, + field_values[2] = if (info.@"volatile") Value.initTag(.bool_true) else Value.initTag(.bool_false); + // alignment: comptime_int, + field_values[3] = try Value.Tag.int_u64.create(sema.arena, info.@"align"); + // child: type, + field_values[4] = try Value.Tag.ty.create(sema.arena, info.pointee_type); + // is_allowzero: bool, + field_values[5] = if (info.@"allowzero") Value.initTag(.bool_true) else Value.initTag(.bool_false); + // sentinel: anytype, + field_values[6] = if (info.sentinel) |some| try Value.Tag.opt_payload.create(sema.arena, some) else Value.initTag(.null_value); + + return sema.addConstant( + type_info_ty, + try Value.Tag.@"union".create(sema.arena, .{ + .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Pointer)), + .val = try Value.Tag.@"struct".create(sema.arena, field_values), + }), + ); + }, + .Array => { + const info = ty.arrayInfo(); + const field_values = try sema.arena.alloc(Value, 3); + // len: comptime_int, + field_values[0] = try Value.Tag.int_u64.create(sema.arena, info.len); + // child: type, + field_values[1] = try Value.Tag.ty.create(sema.arena, info.elem_type); + // sentinel: anytype, + field_values[2] = if (info.sentinel) |some| try Value.Tag.opt_payload.create(sema.arena, some) else Value.initTag(.null_value); + + return sema.addConstant( + type_info_ty, + try Value.Tag.@"union".create(sema.arena, .{ + .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Array)), + .val = try Value.Tag.@"struct".create(sema.arena, field_values), + }), + ); + }, + .Optional => { + const field_values = try sema.arena.alloc(Value, 1); + // child: type, + field_values[0] = try Value.Tag.ty.create(sema.arena, try ty.optionalChildAlloc(sema.arena)); + + return sema.addConstant( + type_info_ty, + try Value.Tag.@"union".create(sema.arena, .{ + .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Optional)), + .val = try Value.Tag.@"struct".create(sema.arena, field_values), + }), + ); + }, + .ErrorUnion => { + const field_values = try sema.arena.alloc(Value, 2); + // error_set: type, + field_values[0] = try Value.Tag.ty.create(sema.arena, ty.errorUnionSet()); + // payload: type, + field_values[1] = try Value.Tag.ty.create(sema.arena, ty.errorUnionPayload()); + + return sema.addConstant( + type_info_ty, + try Value.Tag.@"union".create(sema.arena, .{ + .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ErrorUnion)), .val = try Value.Tag.@"struct".create(sema.arena, field_values), }), ); @@ -8226,7 +8465,10 @@ fn zirCUndef( ) CompileError!Air.Inst.Ref { const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; const src: LazySrcLoc = .{ .node_offset = extra.node }; - return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirCUndef", .{}); + + const name = try sema.resolveConstString(block, src, extra.operand); + try block.c_import_buf.?.writer().print("#undefine {s}\n", .{name}); + return Air.Inst.Ref.void_value; } fn zirCInclude( @@ -8236,7 +8478,10 @@ fn zirCInclude( ) CompileError!Air.Inst.Ref { const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; const src: LazySrcLoc = .{ .node_offset = extra.node }; - return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirCInclude", .{}); + + const name = try sema.resolveConstString(block, src, extra.operand); + try block.c_import_buf.?.writer().print("#include <{s}>\n", .{name}); + return Air.Inst.Ref.void_value; } fn zirCDefine( @@ -8246,7 +8491,15 @@ fn zirCDefine( ) CompileError!Air.Inst.Ref { const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; const src: LazySrcLoc = .{ .node_offset = extra.node }; - return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirCDefine", .{}); + + const name = try sema.resolveConstString(block, src, extra.lhs); + if (sema.typeOf(extra.rhs).zigTypeTag() != .Void) { + const value = try sema.resolveConstString(block, src, extra.rhs); + try block.c_import_buf.?.writer().print("#define {s} {s}\n", .{ name, value }); + } else { + try block.c_import_buf.?.writer().print("#define {s}\n", .{name}); + } + return Air.Inst.Ref.void_value; } fn zirWasmMemorySize( diff --git a/src/print_zir.zig b/src/print_zir.zig index 94fa0307bd..35b3da4479 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -407,15 +407,27 @@ const Writer = struct { .mul_with_saturation, .shl_with_saturation, => try self.writeSaturatingArithmetic(stream, extended), + .struct_decl => try self.writeStructDecl(stream, extended), .union_decl => try self.writeUnionDecl(stream, extended), .enum_decl => try self.writeEnumDecl(stream, extended), + .c_undef, .c_include => { + const inst_data = self.code.extraData(Zir.Inst.UnNode, extended.operand).data; + try self.writeInstRef(stream, inst_data.operand); + try stream.writeAll(") "); + }, + + .c_define => { + const inst_data = self.code.extraData(Zir.Inst.BinNode, extended.operand).data; + try self.writeInstRef(stream, inst_data.lhs); + try stream.writeAll(", "); + try self.writeInstRef(stream, inst_data.rhs); + try stream.writeByte(')'); + }, + .alloc, .builtin_extern, - .c_undef, - .c_include, - .c_define, .wasm_memory_size, .wasm_memory_grow, => try stream.writeAll("TODO))"), diff --git a/src/type.zig b/src/type.zig index db193639a7..5d184ed2fc 100644 --- a/src/type.zig +++ b/src/type.zig @@ -602,8 +602,8 @@ pub const Type = extern union { } return false; }, + .Float => return a.tag() == b.tag(), .Opaque, - .Float, .BoundFn, .Frame, => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }), |
