| author | |
| committer | |
| log | 03e23bcbdea2e832307085e5855ca20b51ac9d9a |
| tree | 761fe4f62155bf1873c389cb64af6337605e1076 |
| parent | c91b06ef52f31090b3c8fda9b9a419bf1391d805 |
| signature |
5 files changed, 143 insertions(+), 185 deletions(-)
src/Sema.zig+60-69| ... | @@ -5746,91 +5746,94 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void | ... | @@ -5746,91 +5746,94 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 5746 | } | 5746 | } |
| 5747 | } | 5747 | } |
| 5748 | 5748 | ||
| 5749 | const export_ty = ptr_ty.childType(zcu); | ||
| 5750 | if (!export_ty.validateExtern(.other, zcu)) { | ||
| 5751 | return sema.failWithOwnedErrorMsg(block, msg: { | ||
| 5752 | const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)}); | ||
| 5753 | errdefer msg.destroy(sema.gpa); | ||
| 5754 | try sema.explainWhyTypeIsNotExtern(msg, src, export_ty, .other); | ||
| 5755 | try sema.addDeclaredHereNote(msg, export_ty); | ||
| 5756 | break :msg msg; | ||
| 5757 | }); | ||
| 5758 | } | ||
| 5759 | |||
| 5749 | const ptr_info = ip.indexToKey(ptr_val.toIntern()).ptr; | 5760 | const ptr_info = ip.indexToKey(ptr_val.toIntern()).ptr; |
| 5750 | switch (ptr_info.base_addr) { | 5761 | const target: Zcu.Exported = switch (ptr_info.base_addr) { |
| 5751 | .comptime_alloc, .int, .comptime_field => return sema.fail(block, ptr_src, "export target must be a global variable or a comptime-known constant", .{}), | 5762 | .comptime_alloc, .int, .comptime_field => return sema.fail(block, ptr_src, "export target must be a global variable or a comptime-known constant", .{}), |
| 5752 | .eu_payload, .opt_payload, .field, .arr_elem => return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{}), | 5763 | .eu_payload, .opt_payload, .field, .arr_elem => return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{}), |
| 5753 | .uav => |uav| { | 5764 | .uav => |uav| .{ .uav = uav.val }, |
| 5754 | if (ptr_info.byte_offset != 0) { | 5765 | .nav => |orig_nav| target: { |
| 5755 | return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{}); | 5766 | try sema.ensureNavResolved(block, src, orig_nav, .fully); |
| 5756 | } | 5767 | const export_nav = switch (ip.indexToKey(ip.getNav(orig_nav).status.fully_resolved.val)) { |
| 5757 | if (zcu.llvm_object != null and options.linkage == .internal) return; | 5768 | .variable => |v| v.owner_nav, |
| 5758 | const export_ty = Value.fromInterned(uav.val).typeOf(zcu); | 5769 | .@"extern" => |e| e.owner_nav, |
| 5759 | if (!export_ty.validateExtern(.other, zcu)) { | 5770 | .func => |f| f.owner_nav, |
| 5760 | return sema.failWithOwnedErrorMsg(block, msg: { | 5771 | else => orig_nav, |
| 5761 | const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)}); | 5772 | }; |
| 5762 | errdefer msg.destroy(sema.gpa); | 5773 | if (ip.getNav(export_nav).getExtern(ip) != null) { |
| 5763 | try sema.explainWhyTypeIsNotExtern(msg, src, export_ty, .other); | 5774 | return sema.fail(block, src, "export target cannot be extern", .{}); |
| 5764 | try sema.addDeclaredHereNote(msg, export_ty); | ||
| 5765 | break :msg msg; | ||
| 5766 | }); | ||
| 5767 | } | ||
| 5768 | try sema.exports.append(zcu.gpa, .{ | ||
| 5769 | .opts = options, | ||
| 5770 | .src = src, | ||
| 5771 | .exported = .{ .uav = uav.val }, | ||
| 5772 | .status = .in_progress, | ||
| 5773 | }); | ||
| 5774 | }, | ||
| 5775 | .nav => |nav| { | ||
| 5776 | if (ptr_info.byte_offset != 0) { | ||
| 5777 | return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{}); | ||
| 5778 | } | 5775 | } |
| 5779 | try sema.analyzeExport(block, src, options, nav); | 5776 | try sema.maybeQueueFuncBodyAnalysis(block, src, export_nav); |
| 5777 | break :target .{ .nav = export_nav }; | ||
| 5780 | }, | 5778 | }, |
| 5779 | }; | ||
| 5780 | if (ptr_info.byte_offset != 0) { | ||
| 5781 | return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{}); | ||
| 5781 | } | 5782 | } |
| 5783 | if (zcu.llvm_object != null and options.linkage == .internal) return; | ||
| 5784 | try sema.exports.append(zcu.gpa, .{ | ||
| 5785 | .opts = options, | ||
| 5786 | .src = src, | ||
| 5787 | .exported = target, | ||
| 5788 | .status = .in_progress, | ||
| 5789 | }); | ||
| 5782 | } | 5790 | } |
| 5783 | 5791 | ||
| 5784 | pub fn analyzeExport( | 5792 | /// Asserts that `sema.owner` is a `.nav_val` whose value is resolved. |
| 5793 | /// | ||
| 5794 | /// Exports that `Nav` by the given name with all other options set to default. | ||
| 5795 | pub fn analyzeExportSelfNav( | ||
| 5785 | sema: *Sema, | 5796 | sema: *Sema, |
| 5786 | block: *Block, | 5797 | block: *Block, |
| 5787 | src: LazySrcLoc, | 5798 | src: LazySrcLoc, |
| 5788 | options: Zcu.Export.Options, | 5799 | name: InternPool.NullTerminatedString, |
| 5789 | orig_nav_index: InternPool.Nav.Index, | ||
| 5790 | ) !void { | 5800 | ) !void { |
| 5791 | const gpa = sema.gpa; | 5801 | const gpa = sema.gpa; |
| 5792 | const pt = sema.pt; | 5802 | const pt = sema.pt; |
| 5793 | const zcu = pt.zcu; | 5803 | const zcu = pt.zcu; |
| 5794 | const ip = &zcu.intern_pool; | 5804 | const ip = &zcu.intern_pool; |
| 5795 | 5805 | ||
| 5796 | if (zcu.llvm_object != null and options.linkage == .internal) | 5806 | const orig_nav = sema.owner.unwrap().nav_val; |
| 5797 | return; | 5807 | const export_val: Value = .fromInterned(ip.getNav(orig_nav).status.fully_resolved.val); |
| 5798 | 5808 | const export_ty = export_val.typeOf(zcu); | |
| 5799 | try sema.ensureNavResolved(block, src, orig_nav_index, .fully); | ||
| 5800 | |||
| 5801 | const exported_nav_index = switch (ip.indexToKey(ip.getNav(orig_nav_index).status.fully_resolved.val)) { | ||
| 5802 | .variable => |v| v.owner_nav, | ||
| 5803 | .@"extern" => |e| e.owner_nav, | ||
| 5804 | .func => |f| f.owner_nav, | ||
| 5805 | else => orig_nav_index, | ||
| 5806 | }; | ||
| 5807 | |||
| 5808 | const exported_nav = ip.getNav(exported_nav_index); | ||
| 5809 | const export_ty: Type = .fromInterned(exported_nav.typeOf(ip)); | ||
| 5810 | 5809 | ||
| 5811 | if (!export_ty.validateExtern(.other, zcu)) { | 5810 | if (!export_ty.validateExtern(.other, zcu)) { |
| 5812 | return sema.failWithOwnedErrorMsg(block, msg: { | 5811 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 5813 | const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)}); | 5812 | const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)}); |
| 5814 | errdefer msg.destroy(gpa); | 5813 | errdefer msg.destroy(gpa); |
| 5815 | |||
| 5816 | try sema.explainWhyTypeIsNotExtern(msg, src, export_ty, .other); | 5814 | try sema.explainWhyTypeIsNotExtern(msg, src, export_ty, .other); |
| 5817 | |||
| 5818 | try sema.addDeclaredHereNote(msg, export_ty); | 5815 | try sema.addDeclaredHereNote(msg, export_ty); |
| 5819 | break :msg msg; | 5816 | break :msg msg; |
| 5820 | }); | 5817 | }); |
| 5821 | } | 5818 | } |
| 5822 | 5819 | ||
| 5823 | // TODO: some backends might support re-exporting extern decls | 5820 | const export_nav = switch (ip.indexToKey(export_val.toIntern())) { |
| 5824 | if (exported_nav.getExtern(ip) != null) { | 5821 | .variable => |v| v.owner_nav, |
| 5825 | return sema.fail(block, src, "export target cannot be extern", .{}); | 5822 | .@"extern" => |e| e.owner_nav, |
| 5826 | } | 5823 | .func => |f| export_nav: { |
| 5827 | 5824 | assert(export_ty.fnHasRuntimeBits(zcu)); // otherwise `validateExtern` failed above | |
| 5828 | try sema.maybeQueueFuncBodyAnalysis(block, src, exported_nav_index); | 5825 | const orig_fn_index = ip.unwrapCoercedFunc(export_val.toIntern()); |
| 5826 | try sema.addReferenceEntry(block, src, .wrap(.{ .func = orig_fn_index })); | ||
| 5827 | try zcu.ensureFuncBodyAnalysisQueued(orig_fn_index); | ||
| 5828 | break :export_nav f.owner_nav; | ||
| 5829 | }, | ||
| 5830 | else => orig_nav, | ||
| 5831 | }; | ||
| 5829 | 5832 | ||
| 5830 | try sema.exports.append(gpa, .{ | 5833 | try sema.exports.append(gpa, .{ |
| 5831 | .opts = options, | 5834 | .opts = .{ .name = name }, |
| 5832 | .src = src, | 5835 | .src = src, |
| 5833 | .exported = .{ .nav = exported_nav_index }, | 5836 | .exported = .{ .nav = export_nav }, |
| 5834 | .status = .in_progress, | 5837 | .status = .in_progress, |
| 5835 | }); | 5838 | }); |
| 5836 | } | 5839 | } |
| ... | @@ -33739,21 +33742,9 @@ pub fn flushExports(sema: *Sema) !void { | ... | @@ -33739,21 +33742,9 @@ pub fn flushExports(sema: *Sema) !void { |
| 33739 | const zcu = sema.pt.zcu; | 33742 | const zcu = sema.pt.zcu; |
| 33740 | const gpa = zcu.gpa; | 33743 | const gpa = zcu.gpa; |
| 33741 | 33744 | ||
| 33742 | // There may be existing exports. For instance, a struct may export | 33745 | assert(!zcu.single_exports.contains(sema.owner)); |
| 33743 | // things during both field type resolution and field default resolution. | 33746 | assert(!zcu.multi_exports.contains(sema.owner)); |
| 33744 | // | ||
| 33745 | // So, pick up and delete any existing exports. This strategy performs | ||
| 33746 | // redundant work, but that's okay, because this case is exceedingly rare. | ||
| 33747 | // | ||
| 33748 | // MLUGG TODO: is this still possible? if not, delete this logic and combine deleteUnitExports into resetUnit | ||
| 33749 | if (zcu.single_exports.get(sema.owner)) |export_idx| { | ||
| 33750 | try sema.exports.append(gpa, export_idx.ptr(zcu).*); | ||
| 33751 | } else if (zcu.multi_exports.get(sema.owner)) |info| { | ||
| 33752 | try sema.exports.appendSlice(gpa, zcu.all_exports.items[info.index..][0..info.len]); | ||
| 33753 | } | ||
| 33754 | zcu.deleteUnitExports(sema.owner); | ||
| 33755 | 33747 | ||
| 33756 | // `sema.exports` is completed; store the data into the `Zcu`. | ||
| 33757 | if (sema.exports.items.len == 1) { | 33748 | if (sema.exports.items.len == 1) { |
| 33758 | try zcu.single_exports.ensureUnusedCapacity(gpa, 1); | 33749 | try zcu.single_exports.ensureUnusedCapacity(gpa, 1); |
| 33759 | const export_idx: Zcu.Export.Index = zcu.free_exports.pop() orelse idx: { | 33750 | const export_idx: Zcu.Export.Index = zcu.free_exports.pop() orelse idx: { |
| ... | @@ -34038,7 +34029,7 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ | ... | @@ -34038,7 +34029,7 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ |
| 34038 | }; | 34029 | }; |
| 34039 | } | 34030 | } |
| 34040 | 34031 | ||
| 34041 | fn setTypeName( | 34032 | pub fn setTypeName( |
| 34042 | sema: *Sema, | 34033 | sema: *Sema, |
| 34043 | block: *Block, | 34034 | block: *Block, |
| 34044 | wip: *const InternPool.WipContainerType, | 34035 | wip: *const InternPool.WipContainerType, |
src/Sema/LowerZon.zig+50-62| ... | @@ -125,89 +125,77 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter | ... | @@ -125,89 +125,77 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter |
| 125 | return (try pt.aggregateValue(.fromInterned(ty), values)).toIntern(); | 125 | return (try pt.aggregateValue(.fromInterned(ty), values)).toIntern(); |
| 126 | }, | 126 | }, |
| 127 | .struct_literal => |init| { | 127 | .struct_literal => |init| { |
| 128 | if (true) @panic("MLUGG TODO"); | ||
| 129 | const elems = try self.sema.arena.alloc(InternPool.Index, init.names.len); | 128 | const elems = try self.sema.arena.alloc(InternPool.Index, init.names.len); |
| 130 | for (0..init.names.len) |i| { | 129 | for (0..init.names.len) |i| { |
| 131 | elems[i] = try self.lowerExprAnonResTy(init.vals.at(@intCast(i))); | 130 | elems[i] = try self.lowerExprAnonResTy(init.vals.at(@intCast(i))); |
| 132 | } | 131 | } |
| 133 | const struct_ty = switch (try ip.getStructType( | 132 | const struct_ty: Type = switch (try ip.getReifiedStructType(gpa, io, pt.tid, .{ |
| 134 | gpa, | 133 | .zir_index = self.base_node_inst, |
| 135 | io, | 134 | .type_hash = hash: { |
| 136 | pt.tid, | 135 | var hasher: std.hash.Wyhash = .init(0); |
| 137 | .{ | 136 | hasher.update(std.mem.asBytes(&node)); |
| 138 | .layout = .auto, | 137 | hasher.update(std.mem.sliceAsBytes(elems)); |
| 139 | .fields_len = @intCast(init.names.len), | 138 | hasher.update(std.mem.sliceAsBytes(init.names)); |
| 140 | .known_non_opv = false, | 139 | break :hash hasher.final(); |
| 141 | .requires_comptime = .no, | ||
| 142 | .any_comptime_fields = true, | ||
| 143 | .any_default_inits = true, | ||
| 144 | .inits_resolved = true, | ||
| 145 | .any_aligned_fields = false, | ||
| 146 | .key = .{ .reified = .{ | ||
| 147 | .zir_index = self.base_node_inst, | ||
| 148 | .type_hash = hash: { | ||
| 149 | var hasher: std.hash.Wyhash = .init(0); | ||
| 150 | hasher.update(std.mem.asBytes(&node)); | ||
| 151 | hasher.update(std.mem.sliceAsBytes(elems)); | ||
| 152 | hasher.update(std.mem.sliceAsBytes(init.names)); | ||
| 153 | break :hash hasher.final(); | ||
| 154 | }, | ||
| 155 | } }, | ||
| 156 | }, | 140 | }, |
| 157 | false, | 141 | .fields_len = @intCast(init.names.len), |
| 158 | )) { | 142 | .layout = .auto, |
| 143 | .any_comptime_fields = true, | ||
| 144 | .any_field_defaults = true, | ||
| 145 | .any_field_aligns = false, | ||
| 146 | .packed_backing_int_type = .none, | ||
| 147 | })) { | ||
| 148 | .existing => |ty| .fromInterned(ty), | ||
| 159 | .wip => |wip| ty: { | 149 | .wip => |wip| ty: { |
| 160 | errdefer wip.cancel(ip, pt.tid); | 150 | errdefer wip.cancel(ip, pt.tid); |
| 161 | const type_name = try self.sema.createTypeName( | 151 | const block = self.block; |
| 162 | self.block, | 152 | const zcu = pt.zcu; |
| 163 | .anon, | 153 | try self.sema.setTypeName(block, &wip, .anon, "struct", self.base_node_inst.resolve(ip).?); |
| 164 | "struct", | 154 | |
| 165 | self.base_node_inst.resolve(ip), | 155 | // Reified structs have field information populated immediately. |
| 166 | wip.index, | 156 | @memcpy(wip.field_values.get(ip), elems); |
| 167 | ); | 157 | if (init.names.len > 0) { |
| 168 | wip.setName(ip, type_name.name, type_name.nav); | 158 | // All fields are comptime, but unused bits remain zeroed. |
| 169 | 159 | const unused_bits = switch (init.names.len % 32) { | |
| 170 | const struct_type = ip.loadStructType(wip.index); | 160 | 0 => 0, |
| 171 | 161 | else => |n| 32 - n, | |
| 172 | for (init.names, 0..) |name, field_idx| { | 162 | }; |
| 173 | const name_interned = try ip.getOrPutString( | 163 | const comptime_bits = wip.field_is_comptime_bits.getAll(ip); |
| 164 | @memset(comptime_bits[0 .. comptime_bits.len - 1], std.math.maxInt(u32)); | ||
| 165 | comptime_bits[comptime_bits.len - 1] = @as(u32, std.math.maxInt(u32)) >> @intCast(unused_bits); | ||
| 166 | } | ||
| 167 | for ( | ||
| 168 | init.names, | ||
| 169 | wip.field_names.get(ip), | ||
| 170 | wip.field_types.get(ip), | ||
| 171 | wip.field_values.get(ip), | ||
| 172 | ) |zoir_name, *field_name, *field_ty, field_val| { | ||
| 173 | field_name.* = try ip.getOrPutString( | ||
| 174 | gpa, | 174 | gpa, |
| 175 | io, | 175 | io, |
| 176 | pt.tid, | 176 | pt.tid, |
| 177 | name.get(self.file.zoir.?), | 177 | zoir_name.get(self.file.zoir.?), |
| 178 | .no_embedded_nulls, | 178 | .no_embedded_nulls, |
| 179 | ); | 179 | ); |
| 180 | assert(struct_type.addFieldName(ip, name_interned) == null); | 180 | field_ty.* = ip.typeOf(field_val); |
| 181 | struct_type.setFieldComptime(ip, field_idx); | ||
| 182 | } | ||
| 183 | |||
| 184 | @memcpy(struct_type.field_inits.get(ip), elems); | ||
| 185 | const types = struct_type.field_types.get(ip); | ||
| 186 | for (0..init.names.len) |i| { | ||
| 187 | types[i] = Value.fromInterned(elems[i]).typeOf(pt.zcu).toIntern(); | ||
| 188 | } | 181 | } |
| 189 | 182 | ||
| 190 | const new_namespace_index = try pt.createNamespace(.{ | 183 | const new_namespace_index = try pt.createNamespace(.{ |
| 191 | .parent = self.block.namespace.toOptional(), | 184 | .parent = block.namespace.toOptional(), |
| 192 | .owner_type = wip.index, | 185 | .owner_type = wip.index, |
| 193 | .file_scope = self.block.getFileScopeIndex(pt.zcu), | 186 | .file_scope = block.getFileScopeIndex(zcu), |
| 194 | .generation = pt.zcu.generation, | 187 | .generation = zcu.generation, |
| 195 | }); | 188 | }); |
| 196 | try pt.zcu.comp.queueJob(.{ .resolve_type_fully = wip.index }); | 189 | errdefer pt.destroyNamespace(new_namespace_index); |
| 197 | codegen_type: { | 190 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); |
| 198 | if (pt.zcu.comp.config.use_llvm) break :codegen_type; | 191 | break :ty .fromInterned(wip.finish(ip, new_namespace_index)); |
| 199 | if (self.block.ownerModule().strip) break :codegen_type; | ||
| 200 | pt.zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); | ||
| 201 | try pt.zcu.comp.queueJob(.{ .link_type = wip.index }); | ||
| 202 | } | ||
| 203 | break :ty wip.finish(ip, new_namespace_index); | ||
| 204 | }, | 192 | }, |
| 205 | .existing => |ty| ty, | ||
| 206 | }; | 193 | }; |
| 207 | try self.sema.declareDependency(.{ .interned = struct_ty }); | ||
| 208 | try self.sema.addTypeReferenceEntry(self.nodeSrc(node), struct_ty); | 194 | try self.sema.addTypeReferenceEntry(self.nodeSrc(node), struct_ty); |
| 195 | // No need for `ensureNamespaceUpToDate` because this type's namespace is always empty. | ||
| 196 | try self.sema.ensureLayoutResolved(struct_ty, self.nodeSrc(node), .init); | ||
| 209 | 197 | ||
| 210 | return (try pt.aggregateValue(.fromInterned(struct_ty), elems)).toIntern(); | 198 | return (try pt.aggregateValue(struct_ty, elems)).toIntern(); |
| 211 | }, | 199 | }, |
| 212 | } | 200 | } |
| 213 | } | 201 | } |
src/Value.zig-1| ... | @@ -1954,7 +1954,6 @@ pub const PointerDeriveStep = union(enum) { | ... | @@ -1954,7 +1954,6 @@ pub const PointerDeriveStep = union(enum) { |
| 1954 | /// which prefer field/elem accesses when lowering constant pointer values. | 1954 | /// which prefer field/elem accesses when lowering constant pointer values. |
| 1955 | /// It is also used by the Value printing logic for pointers. | 1955 | /// It is also used by the Value printing logic for pointers. |
| 1956 | pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread, opt_sema: ?*Sema) Allocator.Error!PointerDeriveStep { | 1956 | pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread, opt_sema: ?*Sema) Allocator.Error!PointerDeriveStep { |
| 1957 | // MLUGG TODO: audit tf outta this code | ||
| 1958 | const zcu = pt.zcu; | 1957 | const zcu = pt.zcu; |
| 1959 | const ptr = zcu.intern_pool.indexToKey(ptr_val.toIntern()).ptr; | 1958 | const ptr = zcu.intern_pool.indexToKey(ptr_val.toIntern()).ptr; |
| 1960 | const base_derive: PointerDeriveStep = switch (ptr.base_addr) { | 1959 | const base_derive: PointerDeriveStep = switch (ptr.base_addr) { |
src/Zcu.zig+31-41| ... | @@ -3518,50 +3518,10 @@ pub const ImportResult = struct { | ... | @@ -3518,50 +3518,10 @@ pub const ImportResult = struct { |
| 3518 | module: ?*Package.Module, | 3518 | module: ?*Package.Module, |
| 3519 | }; | 3519 | }; |
| 3520 | 3520 | ||
| 3521 | /// Delete all the Export objects that are caused by this `AnalUnit`. Re-analysis of | ||
| 3522 | /// this `AnalUnit` will cause them to be re-created (or not). | ||
| 3523 | pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void { | ||
| 3524 | const gpa = zcu.gpa; | ||
| 3525 | |||
| 3526 | const exports_base, const exports_len = if (zcu.single_exports.fetchSwapRemove(anal_unit)) |kv| | ||
| 3527 | .{ @intFromEnum(kv.value), 1 } | ||
| 3528 | else if (zcu.multi_exports.fetchSwapRemove(anal_unit)) |info| | ||
| 3529 | .{ info.value.index, info.value.len } | ||
| 3530 | else | ||
| 3531 | return; | ||
| 3532 | |||
| 3533 | const exports = zcu.all_exports.items[exports_base..][0..exports_len]; | ||
| 3534 | |||
| 3535 | // In an only-c build, we're guaranteed to never use incremental compilation, so there are | ||
| 3536 | // guaranteed not to be any exports in the output file that need deleting (since we only call | ||
| 3537 | // `updateExports` on flush). | ||
| 3538 | // This case is needed because in some rare edge cases, `Sema` wants to add and delete exports | ||
| 3539 | // within a single update. | ||
| 3540 | if (dev.env.supports(.incremental)) { | ||
| 3541 | for (exports, exports_base..) |exp, export_index_usize| { | ||
| 3542 | const export_idx: Export.Index = @enumFromInt(export_index_usize); | ||
| 3543 | if (zcu.comp.bin_file) |lf| { | ||
| 3544 | lf.deleteExport(exp.exported, exp.opts.name); | ||
| 3545 | } | ||
| 3546 | if (zcu.failed_exports.fetchSwapRemove(export_idx)) |failed_kv| { | ||
| 3547 | failed_kv.value.destroy(gpa); | ||
| 3548 | } | ||
| 3549 | } | ||
| 3550 | } | ||
| 3551 | |||
| 3552 | zcu.free_exports.ensureUnusedCapacity(gpa, exports_len) catch { | ||
| 3553 | // This space will be reused eventually, so we need not propagate this error. | ||
| 3554 | // Just leak it for now, and let GC reclaim it later on. | ||
| 3555 | return; | ||
| 3556 | }; | ||
| 3557 | for (exports_base..exports_base + exports_len) |export_idx| { | ||
| 3558 | zcu.free_exports.appendAssumeCapacity(@enumFromInt(export_idx)); | ||
| 3559 | } | ||
| 3560 | } | ||
| 3561 | |||
| 3562 | /// Prepares `unit` for re-analysis by clearing all of the following state: | 3521 | /// Prepares `unit` for re-analysis by clearing all of the following state: |
| 3563 | /// * Compile errors associated with `unit` | 3522 | /// * Compile errors associated with `unit` |
| 3564 | /// * Compile logs associated with `unit` | 3523 | /// * Compile logs associated with `unit` |
| 3524 | /// * Exports performed by `unit` | ||
| 3565 | /// * Dependencies from `unit` on other things | 3525 | /// * Dependencies from `unit` on other things |
| 3566 | /// * References from `unit` to other units | 3526 | /// * References from `unit` to other units |
| 3567 | /// Delete all references in `reference_table` which are caused by `unit`, and all dependencies it | 3527 | /// Delete all references in `reference_table` which are caused by `unit`, and all dependencies it |
| ... | @@ -3593,6 +3553,36 @@ pub fn resetUnit(zcu: *Zcu, unit: AnalUnit) void { | ... | @@ -3593,6 +3553,36 @@ pub fn resetUnit(zcu: *Zcu, unit: AnalUnit) void { |
| 3593 | } | 3553 | } |
| 3594 | } | 3554 | } |
| 3595 | 3555 | ||
| 3556 | // Exports | ||
| 3557 | exports: { | ||
| 3558 | const base: u32, const len: u32 = index: { | ||
| 3559 | if (zcu.single_exports.fetchSwapRemove(unit)) |kv| { | ||
| 3560 | break :index .{ @intFromEnum(kv.value), 1 }; | ||
| 3561 | } | ||
| 3562 | if (zcu.multi_exports.fetchSwapRemove(unit)) |kv| { | ||
| 3563 | break :index .{ kv.value.index, kv.value.len }; | ||
| 3564 | } | ||
| 3565 | break :exports; | ||
| 3566 | }; | ||
| 3567 | for (zcu.all_exports.items[base..][0..len], base..) |exp, exp_index_usize| { | ||
| 3568 | const exp_index: Export.Index = @enumFromInt(exp_index_usize); | ||
| 3569 | if (zcu.comp.bin_file) |lf| { | ||
| 3570 | lf.deleteExport(exp.exported, exp.opts.name); | ||
| 3571 | } | ||
| 3572 | if (zcu.failed_exports.fetchSwapRemove(exp_index)) |failed_kv| { | ||
| 3573 | failed_kv.value.destroy(gpa); | ||
| 3574 | } | ||
| 3575 | } | ||
| 3576 | zcu.free_exports.ensureUnusedCapacity(gpa, len) catch { | ||
| 3577 | // This space will be reused eventually, so we need not propagate this error. | ||
| 3578 | // Just leak it for now, and let GC reclaim it later on. | ||
| 3579 | break :exports; | ||
| 3580 | }; | ||
| 3581 | for (base..base + len) |exp_index| { | ||
| 3582 | zcu.free_exports.appendAssumeCapacity(@enumFromInt(exp_index)); | ||
| 3583 | } | ||
| 3584 | } | ||
| 3585 | |||
| 3596 | // Dependencies | 3586 | // Dependencies |
| 3597 | zcu.intern_pool.removeDependenciesForDepender(gpa, unit); | 3587 | zcu.intern_pool.removeDependenciesForDepender(gpa, unit); |
| 3598 | 3588 |
src/Zcu/PerThread.zig+2-12| ... | @@ -752,7 +752,6 @@ pub fn ensureMemoizedStateUpToDate( | ... | @@ -752,7 +752,6 @@ pub fn ensureMemoizedStateUpToDate( |
| 752 | if (was_outdated) { | 752 | if (was_outdated) { |
| 753 | dev.check(.incremental); | 753 | dev.check(.incremental); |
| 754 | _ = zcu.outdated_ready.swapRemove(unit); | 754 | _ = zcu.outdated_ready.swapRemove(unit); |
| 755 | // No need for `deleteUnitExports` because we never export anything. | ||
| 756 | zcu.resetUnit(unit); | 755 | zcu.resetUnit(unit); |
| 757 | } else { | 756 | } else { |
| 758 | if (prev_failed) return error.AnalysisFail; | 757 | if (prev_failed) return error.AnalysisFail; |
| ... | @@ -874,7 +873,6 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU | ... | @@ -874,7 +873,6 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU |
| 874 | _ = zcu.outdated_ready.swapRemove(anal_unit); | 873 | _ = zcu.outdated_ready.swapRemove(anal_unit); |
| 875 | // `was_outdated` can be true in the initial update for comptime units, so this isn't a `dev.check`. | 874 | // `was_outdated` can be true in the initial update for comptime units, so this isn't a `dev.check`. |
| 876 | if (dev.env.supports(.incremental)) { | 875 | if (dev.env.supports(.incremental)) { |
| 877 | zcu.deleteUnitExports(anal_unit); | ||
| 878 | zcu.resetUnit(anal_unit); | 876 | zcu.resetUnit(anal_unit); |
| 879 | } | 877 | } |
| 880 | } else { | 878 | } else { |
| ... | @@ -1033,7 +1031,6 @@ pub fn ensureTypeLayoutUpToDate( | ... | @@ -1033,7 +1031,6 @@ pub fn ensureTypeLayoutUpToDate( |
| 1033 | _ = zcu.outdated_ready.swapRemove(anal_unit); | 1031 | _ = zcu.outdated_ready.swapRemove(anal_unit); |
| 1034 | // `was_outdated` is true in the initial update, so this isn't a `dev.check`. | 1032 | // `was_outdated` is true in the initial update, so this isn't a `dev.check`. |
| 1035 | if (dev.env.supports(.incremental)) { | 1033 | if (dev.env.supports(.incremental)) { |
| 1036 | zcu.deleteUnitExports(anal_unit); | ||
| 1037 | zcu.resetUnit(anal_unit); | 1034 | zcu.resetUnit(anal_unit); |
| 1038 | } | 1035 | } |
| 1039 | // For types, we already know that we have to invalidate all dependees. | 1036 | // For types, we already know that we have to invalidate all dependees. |
| ... | @@ -1151,7 +1148,6 @@ pub fn ensureNavValUpToDate( | ... | @@ -1151,7 +1148,6 @@ pub fn ensureNavValUpToDate( |
| 1151 | if (was_outdated) { | 1148 | if (was_outdated) { |
| 1152 | dev.check(.incremental); | 1149 | dev.check(.incremental); |
| 1153 | _ = zcu.outdated_ready.swapRemove(anal_unit); | 1150 | _ = zcu.outdated_ready.swapRemove(anal_unit); |
| 1154 | zcu.deleteUnitExports(anal_unit); | ||
| 1155 | zcu.resetUnit(anal_unit); | 1151 | zcu.resetUnit(anal_unit); |
| 1156 | } else { | 1152 | } else { |
| 1157 | // We can trust the current information about this unit. | 1153 | // We can trust the current information about this unit. |
| ... | @@ -1238,7 +1234,7 @@ fn analyzeNavVal( | ... | @@ -1238,7 +1234,7 @@ fn analyzeNavVal( |
| 1238 | const zir_decl = zir.getDeclaration(inst_resolved.inst); | 1234 | const zir_decl = zir.getDeclaration(inst_resolved.inst); |
| 1239 | 1235 | ||
| 1240 | try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, reason); | 1236 | try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, reason); |
| 1241 | errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit); | 1237 | defer assert(zcu.analysis_in_progress.swapRemove(anal_unit)); |
| 1242 | 1238 | ||
| 1243 | var analysis_arena: std.heap.ArenaAllocator = .init(gpa); | 1239 | var analysis_arena: std.heap.ArenaAllocator = .init(gpa); |
| 1244 | defer analysis_arena.deinit(); | 1240 | defer analysis_arena.deinit(); |
| ... | @@ -1443,15 +1439,11 @@ fn analyzeNavVal( | ... | @@ -1443,15 +1439,11 @@ fn analyzeNavVal( |
| 1443 | .@"addrspace" = modifiers.@"addrspace", | 1439 | .@"addrspace" = modifiers.@"addrspace", |
| 1444 | }); | 1440 | }); |
| 1445 | 1441 | ||
| 1446 | // Mark the unit as completed before evaluating the export! | ||
| 1447 | // MLUGG TODO: do we really need to do this? | ||
| 1448 | assert(zcu.analysis_in_progress.swapRemove(anal_unit)); | ||
| 1449 | |||
| 1450 | if (zir_decl.linkage == .@"export") { | 1442 | if (zir_decl.linkage == .@"export") { |
| 1451 | const export_src = block.src(.{ .token_offset = @enumFromInt(@intFromBool(zir_decl.is_pub)) }); | 1443 | const export_src = block.src(.{ .token_offset = @enumFromInt(@intFromBool(zir_decl.is_pub)) }); |
| 1452 | const name_slice = zir.nullTerminatedString(zir_decl.name); | 1444 | const name_slice = zir.nullTerminatedString(zir_decl.name); |
| 1453 | const name_ip = try ip.getOrPutString(gpa, io, pt.tid, name_slice, .no_embedded_nulls); | 1445 | const name_ip = try ip.getOrPutString(gpa, io, pt.tid, name_slice, .no_embedded_nulls); |
| 1454 | try sema.analyzeExport(&block, export_src, .{ .name = name_ip }, nav_id); | 1446 | try sema.analyzeExportSelfNav(&block, export_src, name_ip); |
| 1455 | } | 1447 | } |
| 1456 | 1448 | ||
| 1457 | try sema.flushExports(); | 1449 | try sema.flushExports(); |
| ... | @@ -1514,7 +1506,6 @@ pub fn ensureNavTypeUpToDate( | ... | @@ -1514,7 +1506,6 @@ pub fn ensureNavTypeUpToDate( |
| 1514 | if (was_outdated) { | 1506 | if (was_outdated) { |
| 1515 | dev.check(.incremental); | 1507 | dev.check(.incremental); |
| 1516 | _ = zcu.outdated_ready.swapRemove(anal_unit); | 1508 | _ = zcu.outdated_ready.swapRemove(anal_unit); |
| 1517 | zcu.deleteUnitExports(anal_unit); | ||
| 1518 | zcu.resetUnit(anal_unit); | 1509 | zcu.resetUnit(anal_unit); |
| 1519 | } else { | 1510 | } else { |
| 1520 | // We can trust the current information about this unit. | 1511 | // We can trust the current information about this unit. |
| ... | @@ -1751,7 +1742,6 @@ pub fn ensureFuncBodyUpToDate( | ... | @@ -1751,7 +1742,6 @@ pub fn ensureFuncBodyUpToDate( |
| 1751 | if (was_outdated) { | 1742 | if (was_outdated) { |
| 1752 | dev.check(.incremental); | 1743 | dev.check(.incremental); |
| 1753 | _ = zcu.outdated_ready.swapRemove(anal_unit); | 1744 | _ = zcu.outdated_ready.swapRemove(anal_unit); |
| 1754 | zcu.deleteUnitExports(anal_unit); | ||
| 1755 | zcu.resetUnit(anal_unit); | 1745 | zcu.resetUnit(anal_unit); |
| 1756 | } else { | 1746 | } else { |
| 1757 | // We can trust the current information about this function. | 1747 | // We can trust the current information about this function. |