diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-04-08 11:29:31 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-04-08 11:29:31 -0700 |
| commit | b9e508c410cd077d704a73418281f6d7839df241 (patch) | |
| tree | 1ec79de1aebed48460a5e87170a7cbbce99c0dcd /src | |
| parent | a483e38df62f73dc0cdadee6faf3e083094210d4 (diff) | |
| download | zig-b9e508c410cd077d704a73418281f6d7839df241.tar.gz zig-b9e508c410cd077d704a73418281f6d7839df241.zip | |
stage2: revert to only has_decl and export ZIR support
Reverting most of the code from the previous commits in this branch.
Will pull in the code with modifications bit by bit.
Diffstat (limited to 'src')
| -rw-r--r-- | src/AstGen.zig | 10 | ||||
| -rw-r--r-- | src/Compilation.zig | 110 | ||||
| -rw-r--r-- | src/Module.zig | 15 | ||||
| -rw-r--r-- | src/Package.zig | 29 | ||||
| -rw-r--r-- | src/Sema.zig | 59 | ||||
| -rw-r--r-- | src/main.zig | 3 | ||||
| -rw-r--r-- | src/zir.zig | 5 |
7 files changed, 73 insertions, 158 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig index 20e52ea559..e269c4ab4f 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -4149,12 +4149,14 @@ fn builtinCall( }, .@"export" => { - const target_fn = try expr(gz, scope, .none, params[0]); - // FIXME: When structs work in stage2, actually implement this correctly! - // Currently the name is always signifies Strong linkage. + // TODO: @export is supposed to be able to export things other than functions. + // Instead of `comptimeExpr` here we need `decl_ref`. + const fn_to_export = try comptimeExpr(gz, scope, .none, params[0]); + // TODO: the second parameter here is supposed to be + // `std.builtin.ExportOptions`, not a string. const export_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]); _ = try gz.addPlNode(.@"export", node, zir.Inst.Bin{ - .lhs = target_fn, + .lhs = fn_to_export, .rhs = export_name, }); return rvalue(gz, scope, rl, .void_value, node); diff --git a/src/Compilation.zig b/src/Compilation.zig index 2a3d9659b0..080d4bddaa 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -510,11 +510,11 @@ pub const InitOptions = struct { fn addPackageTableToCacheHash( hash: *Cache.HashHelper, arena: *std.heap.ArenaAllocator, - package: *Package, + pkg_table: Package.Table, hash_type: union(enum) { path_bytes, files: *Cache.Manifest }, ) (error{OutOfMemory} || std.os.GetCwdError)!void { const allocator = &arena.allocator; - const pkg_table = package.table; + const packages = try allocator.alloc(Package.Table.Entry, pkg_table.count()); { // Copy over the hashmap entries to our slice @@ -547,8 +547,7 @@ fn addPackageTableToCacheHash( }, } // Recurse to handle the package's dependencies - if (package != pkg.value) - try addPackageTableToCacheHash(hash, arena, pkg.value, hash_type); + try addPackageTableToCacheHash(hash, arena, pkg.value.table, hash_type); } } @@ -886,7 +885,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { { var local_arena = std.heap.ArenaAllocator.init(gpa); defer local_arena.deinit(); - try addPackageTableToCacheHash(&hash, &local_arena, root_pkg, .path_bytes); + try addPackageTableToCacheHash(&hash, &local_arena, root_pkg.table, .path_bytes); } hash.add(valgrind); hash.add(single_threaded); @@ -907,46 +906,38 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { artifact_sub_dir, }; - const builtin_pkg = try Package.create(gpa, zig_cache_artifact_directory.path.?, "builtin2.zig"); - - const std_dir_path = try options.zig_lib_directory.join(gpa, &[_][]const u8{"std"}); - defer gpa.free(std_dir_path); - const start_pkg = try Package.create(gpa, std_dir_path, "start2.zig"); - - try root_pkg.add(gpa, "builtin", builtin_pkg); - try root_pkg.add(gpa, "root", root_pkg); - - try start_pkg.add(gpa, "builtin", builtin_pkg); - try start_pkg.add(gpa, "root", root_pkg); - // TODO when we implement serialization and deserialization of incremental compilation metadata, // this is where we would load it. We have open a handle to the directory where // the output either already is, or will be. // However we currently do not have serialization of such metadata, so for now // we set up an empty Module that does the entire compilation fresh. - if (mem.endsWith(u8, root_pkg.root_src_path, ".zir")) return error.ZirFilesUnsupported; - - const start_scope = ss: { - const start_scope = try gpa.create(Module.Scope.File); - const struct_ty = try Type.Tag.empty_struct.create( - gpa, - &start_scope.root_container, - ); - start_scope.* = .{ - // TODO this is duped so it can be freed in Container.deinit - .sub_file_path = try gpa.dupe(u8, start_pkg.root_src_path), - .source = .{ .unloaded = {} }, - .tree = undefined, - .status = .never_loaded, - .pkg = start_pkg, - .root_container = .{ - .file_scope = start_scope, - .decls = .{}, - .ty = struct_ty, - }, - }; - break :ss start_scope; + const root_scope = rs: { + if (mem.endsWith(u8, root_pkg.root_src_path, ".zig")) { + const root_scope = try gpa.create(Module.Scope.File); + const struct_ty = try Type.Tag.empty_struct.create( + gpa, + &root_scope.root_container, + ); + root_scope.* = .{ + // TODO this is duped so it can be freed in Container.deinit + .sub_file_path = try gpa.dupe(u8, root_pkg.root_src_path), + .source = .{ .unloaded = {} }, + .tree = undefined, + .status = .never_loaded, + .pkg = root_pkg, + .root_container = .{ + .file_scope = root_scope, + .decls = .{}, + .ty = struct_ty, + }, + }; + break :rs root_scope; + } else if (mem.endsWith(u8, root_pkg.root_src_path, ".zir")) { + return error.ZirFilesUnsupported; + } else { + unreachable; + } }; const module = try arena.create(Module); @@ -955,9 +946,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { .gpa = gpa, .comp = comp, .root_pkg = root_pkg, - .root_scope = null, - .start_pkg = start_pkg, - .start_scope = start_scope, + .root_scope = root_scope, .zig_cache_artifact_directory = zig_cache_artifact_directory, .emit_h = options.emit_h, .error_name_list = try std.ArrayListUnmanaged([]const u8).initCapacity(gpa, 1), @@ -1359,9 +1348,9 @@ pub fn update(self: *Compilation) !void { // TODO Detect which source files changed. // Until then we simulate a full cache miss. Source files could have been loaded // for any reason; to force a refresh we unload now. - module.unloadFile(module.start_scope); + module.unloadFile(module.root_scope); module.failed_root_src_file = null; - module.analyzeContainer(&module.start_scope.root_container) catch |err| switch (err) { + module.analyzeContainer(&module.root_scope.root_container) catch |err| switch (err) { error.AnalysisFail => { assert(self.totalErrorCount() != 0); }, @@ -1422,7 +1411,7 @@ pub fn update(self: *Compilation) !void { // to report error messages. Otherwise we unload all source files to save memory. if (self.totalErrorCount() == 0 and !self.keep_source_files_loaded) { if (self.bin_file.options.module) |module| { - module.start_scope.unload(self.gpa); + module.root_scope.unload(self.gpa); } } } @@ -2833,11 +2822,6 @@ fn updateBuiltinZigFile(comp: *Compilation, mod: *Module) !void { const source = try comp.generateBuiltinZigSource(comp.gpa); defer comp.gpa.free(source); try mod.zig_cache_artifact_directory.handle.writeFile("builtin.zig", source); - - // FIXME: Remove builtin2.zig when stage2 can correctly generate code for builtin.zig! - const source2 = try comp.generateBuiltin2ZigSource(comp.gpa); - defer comp.gpa.free(source2); - try mod.zig_cache_artifact_directory.handle.writeFile("builtin2.zig", source2); } pub fn dump_argv(argv: []const []const u8) void { @@ -2847,30 +2831,6 @@ pub fn dump_argv(argv: []const []const u8) void { std.debug.print("{s}\n", .{argv[argv.len - 1]}); } -fn generateBuiltin2ZigSource(comp: *Compilation, allocator: *Allocator) ![]u8 { - var buffer = std.ArrayList(u8).init(allocator); - defer buffer.deinit(); - - const target = comp.getTarget(); - - try buffer.writer().print( - \\pub const link_libc = {}; - \\pub const arch = {}; - \\pub const os = {}; - \\pub const output_mode = {}; - \\pub const object_format = {}; - \\ - , .{ - comp.bin_file.options.link_libc, - @enumToInt(target.cpu.arch), - @enumToInt(target.os.tag), - @enumToInt(comp.bin_file.options.output_mode), - @enumToInt(comp.bin_file.options.object_format), - }); - - return buffer.toOwnedSlice(); -} - pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8 { const tracy = trace(@src()); defer tracy.end(); @@ -3215,7 +3175,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node { var local_arena = std.heap.ArenaAllocator.init(comp.gpa); defer local_arena.deinit(); - try addPackageTableToCacheHash(&man.hash, &local_arena, mod.root_pkg, .{ .files = &man }); + try addPackageTableToCacheHash(&man.hash, &local_arena, mod.root_pkg.table, .{ .files = &man }); } man.hash.add(comp.bin_file.options.valgrind); man.hash.add(comp.bin_file.options.single_threaded); diff --git a/src/Module.zig b/src/Module.zig index dab3319b2e..933917d948 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -35,11 +35,8 @@ comp: *Compilation, zig_cache_artifact_directory: Compilation.Directory, /// Pointer to externally managed resource. `null` if there is no zig file being compiled. root_pkg: *Package, -/// This is populated when `@import("root")` is analysed. -root_scope: ?*Scope.File, -start_pkg: *Package, /// Module owns this resource. -start_scope: *Scope.File, +root_scope: *Scope.File, /// It's rare for a decl to be exported, so we save memory by having a sparse map of /// Decl pointers to details about them being exported. /// The Export memory is owned by the `export_owners` table; the slice itself is owned by this table. @@ -2344,9 +2341,7 @@ pub fn deinit(mod: *Module) void { mod.export_owners.deinit(gpa); mod.symbol_exports.deinit(gpa); - - mod.start_scope.destroy(gpa); - mod.start_pkg.destroy(gpa); + mod.root_scope.destroy(gpa); var it = mod.global_error_set.iterator(); while (it.next()) |entry| { @@ -2518,7 +2513,6 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool { const block_expr = node_datas[decl_node].lhs; _ = try AstGen.comptimeExpr(&gen_scope, &gen_scope.base, .none, block_expr); - _ = try gen_scope.addBreak(.break_inline, gen_scope.break_block, .void_value); const code = try gen_scope.finish(); if (std.builtin.mode == .Debug and mod.comp.verbose_ir) { @@ -2863,9 +2857,8 @@ fn astgenAndSemaFn( _ = try AstGen.expr(&gen_scope, params_scope, .none, body_node); - const inst_tags = astgen.instructions.items(.tag); - if (inst_tags.len == 0 or - !inst_tags[inst_tags.len - 1] + if (gen_scope.instructions.items.len == 0 or + !astgen.instructions.items(.tag)[gen_scope.instructions.items.len - 1] .isNoReturn()) { // astgen uses result location semantics to coerce return operands. diff --git a/src/Package.zig b/src/Package.zig index d5960dcf9a..33ff4766ca 100644 --- a/src/Package.zig +++ b/src/Package.zig @@ -15,9 +15,6 @@ root_src_path: []const u8, table: Table = .{}, parent: ?*Package = null, -// Used when freeing packages -seen: bool = false, - /// Allocate a Package. No references to the slices passed are kept. pub fn create( gpa: *Allocator, @@ -58,20 +55,10 @@ pub fn destroy(pkg: *Package, gpa: *Allocator) void { pkg.root_src_directory.handle.close(); } - // First we recurse into all the packages and remove packages from the tables - // once we have seen it before. We do this to make sure that that - // a package can only be found once in the whole tree. - if (!pkg.seen) { - pkg.seen = true; - pkg.markSeen(gpa); - } - { var it = pkg.table.iterator(); while (it.next()) |kv| { - if (pkg != kv.value) { - kv.value.destroy(gpa); - } + kv.value.destroy(gpa); gpa.free(kv.key); } } @@ -80,20 +67,6 @@ pub fn destroy(pkg: *Package, gpa: *Allocator) void { gpa.destroy(pkg); } -fn markSeen(pkg: *Package, gpa: *Allocator) void { - var it = pkg.table.iterator(); - while (it.next()) |kv| { - if (pkg != kv.value) { - if (kv.value.seen) { - pkg.table.removeAssertDiscard(kv.key); - } else { - kv.value.seen = true; - kv.value.markSeen(gpa); - } - } - } -} - pub fn add(pkg: *Package, gpa: *Allocator, name: []const u8, package: *Package) !void { try pkg.table.ensureCapacity(gpa, pkg.table.count() + 1); const name_dupe = try mem.dupe(gpa, u8, name); diff --git a/src/Sema.zig b/src/Sema.zig index d4c2592446..51d350ea7c 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1345,21 +1345,18 @@ fn zirExport(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError! const inst_data = sema.code.instructions.items(.data)[inst].pl_node; const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data; const src = inst_data.src(); + const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; + const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; - const target_fn = try sema.resolveInst(extra.lhs); - const target_fn_val = try sema.resolveConstValue( - block, - .{ .node_offset_builtin_call_arg0 = inst_data.src_node }, - target_fn, - ); - - const export_name = try sema.resolveConstString( - block, - .{ .node_offset_builtin_call_arg1 = inst_data.src_node }, - extra.rhs, - ); + // TODO (see corresponding TODO in AstGen) this is supposed to be a `decl_ref` + // instruction, which could reference any decl, which is then supposed to get + // exported, regardless of whether or not it is a function. + const target_fn = try sema.resolveInstConst(block, lhs_src, extra.lhs); + // TODO (see corresponding TODO in AstGen) this is supposed to be + // `std.builtin.ExportOptions`, not a string. + const export_name = try sema.resolveConstString(block, rhs_src, extra.rhs); - const actual_fn = target_fn_val.castTag(.function).?.data; + const actual_fn = target_fn.val.castTag(.function).?.data; try sema.mod.analyzeExport(&block.base, src, export_name, actual_fn.owner_decl); } @@ -3636,26 +3633,21 @@ fn zirHasDecl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; const container_type = try sema.resolveType(block, lhs_src, extra.lhs); const decl_name = try sema.resolveConstString(block, rhs_src, extra.rhs); + const mod = sema.mod; + const arena = sema.arena; - const maybe_scope = container_type.getContainerScope(); - if (maybe_scope == null) { - return sema.mod.fail( - &block.base, - src, - "expected container (struct, enum, or union), found '{}'", - .{container_type}, - ); + const container_scope = container_type.getContainerScope() orelse return mod.fail( + &block.base, + lhs_src, + "expected struct, enum, union, or opaque, found '{}'", + .{container_type}, + ); + if (mod.lookupDeclName(&container_scope.base, decl_name)) |decl| { + // TODO if !decl.is_pub and inDifferentFiles() return false + return mod.constBool(arena, src, true); + } else { + return mod.constBool(arena, src, false); } - - const found = blk: { - for (maybe_scope.?.decls.items()) |kv| { - if (mem.eql(u8, mem.spanZ(kv.key.name), decl_name)) - break :blk true; - } - break :blk false; - }; - - return sema.mod.constBool(sema.arena, src, found); } fn zirImport(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { @@ -4699,7 +4691,7 @@ fn namedFieldPtr( } // TODO this will give false positives for structs inside the root file - if (container_scope.file_scope == mod.root_scope.?) { + if (container_scope.file_scope == mod.root_scope) { return mod.fail( &block.base, src, @@ -5338,9 +5330,6 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin .ty = struct_ty, }, }; - if (mem.eql(u8, target_string, "root")) { - sema.mod.root_scope = file_scope; - } sema.mod.analyzeContainer(&file_scope.root_container) catch |err| switch (err) { error.AnalysisFail => { assert(sema.mod.comp.totalErrorCount() != 0); diff --git a/src/main.zig b/src/main.zig index 0f03813a36..5fb74db61f 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1732,8 +1732,6 @@ fn buildOutputType( }, } - // This gets cleaned up, because root_pkg becomes part of the - // package table of the start_pkg. const root_pkg: ?*Package = if (root_src_file) |src_path| blk: { if (main_pkg_path) |p| { const rel_src_path = try fs.path.relative(gpa, p, src_path); @@ -1743,6 +1741,7 @@ fn buildOutputType( break :blk try Package.create(gpa, fs.path.dirname(src_path), fs.path.basename(src_path)); } } else null; + defer if (root_pkg) |p| p.destroy(gpa); // Transfer packages added with --pkg-begin/--pkg-end to the root package if (root_pkg) |pkg| { diff --git a/src/zir.zig b/src/zir.zig index 40ad2b7844..807e25e6b8 100644 --- a/src/zir.zig +++ b/src/zir.zig @@ -328,8 +328,7 @@ pub const Inst = struct { error_union_type, /// `error.Foo` syntax. Uses the `str_tok` field of the Data union. error_value, - /// Exports a function with a specified name. This can be used at comptime - /// to export a function conditionally. + /// Implements the `@export` builtin function. /// Uses the `pl_node` union field. Payload is `Bin`. @"export", /// Given a pointer to a struct or object that contains virtual fields, returns a pointer @@ -364,7 +363,7 @@ pub const Inst = struct { fn_type_cc, /// Same as `fn_type_cc` but the function is variadic. fn_type_cc_var_args, - /// Determines whether a container has a declaration matching name. + /// Implements the `@hasDecl` builtin. /// Uses the `pl_node` union field. Payload is `Bin`. has_decl, /// `@import(operand)`. |
