authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-07 18:52:11-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-07 18:52:11-07:00
log81d5104e228dc30184b31158c1b36ec0ec371b0b
tree396f2bd67ffac87f6de0d9eacb7e83e496ddc41b
parente7c4d545cd34321c61b85f1ce286d46976293617

stage2: implement global variables

* Sema: implement global variables - Improved global constants to stop needlessly creating a Var structure; they can just store the value directly. - This required making memory management a bit more sophisticated to detect when a Decl owns the Namespace associated with it, for the purposes of deinitialization. * Decl.name and Namespace decl table keys no longer directly reference ZIR; instead they have heap-duped names, so that deleted decls, which no longer have any ZIR to reference for their names, can be removed from the parent Namespace table. - In the future I would like to explore going a different direction with this, where the strings would still point to the ZIR however they would be removed from their owner Namespace objects during the update detection. The design principle here is that the existence of incremental compilation as a feature should not incur any cost for the use case when it is not used. In this example Decl names could simply point to ZIR string table memory, and it is only because of incremental compilation that we duplicate their names. * AstGen: implement threadlocal variables * CLI: call cleanExit after building a compilation so that in release modes we don't bother freeing memory or closing file descriptors, allowing the OS to do it more efficiently. * Avoid calling `freeDecl` in the linker for unreferenced Decl objects. * Fix CBE test case expecting the compile error to point to the wrong column.

8 files changed, 157 insertions(+), 103 deletions(-)

BRANCH_TODO+4-1
...@@ -58,5 +58,8 @@...@@ -58,5 +58,8 @@
58 natural alignment for fields and do not have any comptime fields. this58 natural alignment for fields and do not have any comptime fields. this
59 will save 16 bytes per struct field in the compilation.59 will save 16 bytes per struct field in the compilation.
6060
61 * AstGen threadlocal
62 * extern "foo" for vars61 * extern "foo" for vars
62
63 * use ZIR memory for decl names where possible and also for keys
64 - this will require more sophisticated changelist detection which does some
65 pre-emptive deletion of decls from the parent namespace
src/AstGen.zig+4
...@@ -3009,6 +3009,7 @@ fn globalVarDecl(...@@ -3009,6 +3009,7 @@ fn globalVarDecl(
3009 .align_inst = .none, // passed via the decls data3009 .align_inst = .none, // passed via the decls data
3010 .init = init_inst,3010 .init = init_inst,
3011 .is_extern = false,3011 .is_extern = false,
3012 .is_threadlocal = is_threadlocal,
3012 });3013 });
3013 break :vi var_inst;3014 break :vi var_inst;
3014 } else {3015 } else {
...@@ -3026,6 +3027,7 @@ fn globalVarDecl(...@@ -3026,6 +3027,7 @@ fn globalVarDecl(
3026 .align_inst = .none, // passed via the decls data3027 .align_inst = .none, // passed via the decls data
3027 .init = .none,3028 .init = .none,
3028 .is_extern = true,3029 .is_extern = true,
3030 .is_threadlocal = is_threadlocal,
3029 });3031 });
3030 break :vi var_inst;3032 break :vi var_inst;
3031 } else {3033 } else {
...@@ -8100,6 +8102,7 @@ const GenZir = struct {...@@ -8100,6 +8102,7 @@ const GenZir = struct {
8100 var_type: Zir.Inst.Ref,8102 var_type: Zir.Inst.Ref,
8101 init: Zir.Inst.Ref,8103 init: Zir.Inst.Ref,
8102 is_extern: bool,8104 is_extern: bool,
8105 is_threadlocal: bool,
8103 }) !Zir.Inst.Ref {8106 }) !Zir.Inst.Ref {
8104 const astgen = gz.astgen;8107 const astgen = gz.astgen;
8105 const gpa = astgen.gpa;8108 const gpa = astgen.gpa;
...@@ -8137,6 +8140,7 @@ const GenZir = struct {...@@ -8137,6 +8140,7 @@ const GenZir = struct {
8137 .has_align = args.align_inst != .none,8140 .has_align = args.align_inst != .none,
8138 .has_init = args.init != .none,8141 .has_init = args.init != .none,
8139 .is_extern = args.is_extern,8142 .is_extern = args.is_extern,
8143 .is_threadlocal = args.is_threadlocal,
8140 }),8144 }),
8141 .operand = payload_index,8145 .operand = payload_index,
8142 } },8146 } },
src/Module.zig+88-91
...@@ -154,9 +154,7 @@ pub const DeclPlusEmitH = struct {...@@ -154,9 +154,7 @@ pub const DeclPlusEmitH = struct {
154};154};
155155
156pub const Decl = struct {156pub const Decl = struct {
157 /// For declarations that have corresponding source code, this is identical to157 /// Allocated with Module's allocator; outlives the ZIR code.
158 /// `getName().?`. For anonymous declarations this is allocated with Module's
159 /// allocator.
160 name: [*:0]const u8,158 name: [*:0]const u8,
161 /// The most recent Type of the Decl after a successful semantic analysis.159 /// The most recent Type of the Decl after a successful semantic analysis.
162 /// Populated when `has_tv`.160 /// Populated when `has_tv`.
...@@ -270,13 +268,7 @@ pub const Decl = struct {...@@ -270,13 +268,7 @@ pub const Decl = struct {
270 );268 );
271269
272 pub fn clearName(decl: *Decl, gpa: *Allocator) void {270 pub fn clearName(decl: *Decl, gpa: *Allocator) void {
273 // name could be allocated in the ZIR or it could be owned by gpa.271 gpa.free(mem.spanZ(decl.name));
274 const file = decl.namespace.file_scope;
275 const string_table_start = @ptrToInt(file.zir.string_bytes.ptr);
276 const string_table_end = string_table_start + file.zir.string_bytes.len;
277 if (@ptrToInt(decl.name) < string_table_start or @ptrToInt(decl.name) >= string_table_end) {
278 gpa.free(mem.spanZ(decl.name));
279 }
280 decl.name = undefined;272 decl.name = undefined;
281 }273 }
282274
...@@ -285,7 +277,7 @@ pub const Decl = struct {...@@ -285,7 +277,7 @@ pub const Decl = struct {
285 log.debug("destroy {*} ({s})", .{ decl, decl.name });277 log.debug("destroy {*} ({s})", .{ decl, decl.name });
286 decl.clearName(gpa);278 decl.clearName(gpa);
287 if (decl.has_tv) {279 if (decl.has_tv) {
288 if (decl.val.getTypeNamespace()) |namespace| {280 if (decl.getInnerNamespace()) |namespace| {
289 if (namespace.getDecl() == decl) {281 if (namespace.getDecl() == decl) {
290 namespace.clearDecls(module);282 namespace.clearDecls(module);
291 }283 }
...@@ -308,6 +300,9 @@ pub const Decl = struct {...@@ -308,6 +300,9 @@ pub const Decl = struct {
308 func.deinit(gpa);300 func.deinit(gpa);
309 gpa.destroy(func);301 gpa.destroy(func);
310 }302 }
303 if (decl.getVariable()) |variable| {
304 gpa.destroy(variable);
305 }
311 if (decl.value_arena) |arena_state| {306 if (decl.value_arena) |arena_state| {
312 arena_state.promote(gpa).deinit();307 arena_state.promote(gpa).deinit();
313 decl.value_arena = null;308 decl.value_arena = null;
...@@ -472,6 +467,47 @@ pub const Decl = struct {...@@ -472,6 +467,47 @@ pub const Decl = struct {
472 return func;467 return func;
473 }468 }
474469
470 pub fn getVariable(decl: *Decl) ?*Var {
471 if (!decl.has_tv) return null;
472 const variable = (decl.val.castTag(.variable) orelse return null).data;
473 if (variable.owner_decl != decl) return null;
474 return variable;
475 }
476
477 /// Gets the namespace that this Decl creates by being a struct, union,
478 /// enum, or opaque.
479 /// Only returns it if the Decl is the owner.
480 pub fn getInnerNamespace(decl: *Decl) ?*Scope.Namespace {
481 if (!decl.has_tv) return null;
482 const ty = (decl.val.castTag(.ty) orelse return null).data;
483 switch (ty.tag()) {
484 .@"struct" => {
485 const struct_obj = ty.castTag(.@"struct").?.data;
486 if (struct_obj.owner_decl != decl) return null;
487 return &struct_obj.namespace;
488 },
489 .enum_full => {
490 const enum_obj = ty.castTag(.enum_full).?.data;
491 if (enum_obj.owner_decl != decl) return null;
492 return &enum_obj.namespace;
493 },
494 .empty_struct => {
495 // design flaw, can't verify the owner is this decl
496 @panic("TODO can't implement getInnerNamespace for this type");
497 },
498 .@"opaque" => {
499 @panic("TODO opaque types");
500 },
501 .@"union", .union_tagged => {
502 const union_obj = ty.cast(Type.Payload.Union).?.data;
503 if (union_obj.owner_decl != decl) return null;
504 return &union_obj.namespace;
505 },
506
507 else => return null,
508 }
509 }
510
475 pub fn dump(decl: *Decl) void {511 pub fn dump(decl: *Decl) void {
476 const loc = std.zig.findLineColumn(decl.scope.source.bytes, decl.src);512 const loc = std.zig.findLineColumn(decl.scope.source.bytes, decl.src);
477 std.debug.print("{s}:{d}:{d} name={s} status={s}", .{513 std.debug.print("{s}:{d}:{d} name={s} status={s}", .{
...@@ -504,6 +540,23 @@ pub const Decl = struct {...@@ -504,6 +540,23 @@ pub const Decl = struct {
504 fn removeDependency(decl: *Decl, other: *Decl) void {540 fn removeDependency(decl: *Decl, other: *Decl) void {
505 decl.dependencies.removeAssertDiscard(other);541 decl.dependencies.removeAssertDiscard(other);
506 }542 }
543
544 fn hasLinkAllocation(decl: Decl) bool {
545 return switch (decl.analysis) {
546 .unreferenced,
547 .in_progress,
548 .dependency_failure,
549 .sema_failure,
550 .sema_failure_retryable,
551 .codegen_failure,
552 .codegen_failure_retryable,
553 => false,
554
555 .complete,
556 .outdated,
557 => true,
558 };
559 }
507};560};
508561
509/// This state is attached to every Decl when Module emit_h is non-null.562/// This state is attached to every Decl when Module emit_h is non-null.
...@@ -831,9 +884,8 @@ pub const Scope = struct {...@@ -831,9 +884,8 @@ pub const Scope = struct {
831 /// Direct children of the namespace. Used during an update to detect884 /// Direct children of the namespace. Used during an update to detect
832 /// which decls have been added/removed from source.885 /// which decls have been added/removed from source.
833 /// Declaration order is preserved via entry order.886 /// Declaration order is preserved via entry order.
834 /// Key memory references the string table of the containing `File` ZIR.887 /// Key memory is owned by `decl.name`.
835 /// TODO save memory with https://github.com/ziglang/zig/issues/8619.888 /// TODO save memory with https://github.com/ziglang/zig/issues/8619.
836 /// Does not contain anonymous decls.
837 decls: std.StringArrayHashMapUnmanaged(*Decl) = .{},889 decls: std.StringArrayHashMapUnmanaged(*Decl) = .{},
838890
839 pub fn deinit(ns: *Namespace, mod: *Module) void {891 pub fn deinit(ns: *Namespace, mod: *Module) void {
...@@ -2468,8 +2520,6 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node...@@ -2468,8 +2520,6 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
2468/// * Decl.zir_index2520/// * Decl.zir_index
2469/// * Fn.zir_body_inst2521/// * Fn.zir_body_inst
2470/// * Decl.zir_decl_index2522/// * Decl.zir_decl_index
2471/// * Decl.name
2472/// * Namespace.decl keys
2473fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !void {2523fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !void {
2474 const new_zir = file.zir;2524 const new_zir = file.zir;
24752525
...@@ -2484,18 +2534,6 @@ fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !void {...@@ -2484,18 +2534,6 @@ fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !void {
24842534
2485 try mapOldZirToNew(gpa, old_zir, new_zir, &inst_map, &extra_map);2535 try mapOldZirToNew(gpa, old_zir, new_zir, &inst_map, &extra_map);
24862536
2487 // Build string table for new ZIR.
2488 var string_table: std.StringHashMapUnmanaged(u32) = .{};
2489 defer string_table.deinit(gpa);
2490 {
2491 var i: usize = 2;
2492 while (i < new_zir.string_bytes.len) {
2493 const string = new_zir.nullTerminatedString(i);
2494 try string_table.put(gpa, string, @intCast(u32, i));
2495 i += string.len + 1;
2496 }
2497 }
2498
2499 // Walk the Decl graph, updating ZIR indexes, strings, and populating2537 // Walk the Decl graph, updating ZIR indexes, strings, and populating
2500 // the deleted and outdated lists.2538 // the deleted and outdated lists.
25012539
...@@ -2523,12 +2561,6 @@ fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !void {...@@ -2523,12 +2561,6 @@ fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !void {
2523 try file.deleted_decls.append(gpa, decl);2561 try file.deleted_decls.append(gpa, decl);
2524 continue;2562 continue;
2525 };2563 };
2526 const new_name_index = string_table.get(mem.spanZ(decl.name)) orelse {
2527 try file.deleted_decls.append(gpa, decl);
2528 continue;
2529 };
2530 decl.name = new_zir.nullTerminatedString(new_name_index).ptr;
2531
2532 const new_hash = decl.contentsHashZir(new_zir);2564 const new_hash = decl.contentsHashZir(new_zir);
2533 if (!std.zig.srcHashEql(old_hash, new_hash)) {2565 if (!std.zig.srcHashEql(old_hash, new_hash)) {
2534 try file.outdated_decls.append(gpa, decl);2566 try file.outdated_decls.append(gpa, decl);
...@@ -2558,16 +2590,9 @@ fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !void {...@@ -2558,16 +2590,9 @@ fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !void {
2558 };2590 };
2559 }2591 }
25602592
2561 if (decl.val.getTypeNamespace()) |namespace| {2593 if (decl.getInnerNamespace()) |namespace| {
2562 for (namespace.decls.items()) |*entry| {2594 for (namespace.decls.items()) |*entry| {
2563 const sub_decl = entry.value;2595 const sub_decl = entry.value;
2564 if (sub_decl.zir_decl_index != 0) {
2565 const new_key_index = string_table.get(entry.key) orelse {
2566 try file.deleted_decls.append(gpa, sub_decl);
2567 continue;
2568 };
2569 entry.key = new_zir.nullTerminatedString(new_key_index);
2570 }
2571 try decl_stack.append(gpa, sub_decl);2596 try decl_stack.append(gpa, sub_decl);
2572 }2597 }
2573 }2598 }
...@@ -2936,46 +2961,14 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -2936,46 +2961,14 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
2936 }2961 }
2937 return type_changed or is_inline != prev_is_inline;2962 return type_changed or is_inline != prev_is_inline;
2938 } else {2963 } else {
2939 const is_mutable = decl_tv.val.tag() == .variable;
2940
2941 var is_threadlocal = false; // TODO implement threadlocal variables
2942 var is_extern = false; // TODO implement extern variables
2943
2944 if (is_mutable and !decl_tv.ty.isValidVarType(is_extern)) {
2945 return mod.fail(
2946 &block_scope.base,
2947 src, // TODO point at the mut token
2948 "variable of type '{}' must be const",
2949 .{decl_tv.ty},
2950 );
2951 }
2952
2953 var type_changed = true;2964 var type_changed = true;
2954 if (decl.has_tv) {2965 if (decl.has_tv) {
2955 type_changed = !decl.ty.eql(decl_tv.ty);2966 type_changed = !decl.ty.eql(decl_tv.ty);
2956 decl.clearValues(gpa);2967 decl.clearValues(gpa);
2957 }2968 }
29582969
2959 const copied_val = try decl_tv.val.copy(&decl_arena.allocator);
2960 const is_extern_fn = copied_val.tag() == .extern_fn;
2961
2962 // TODO: also avoid allocating this Var structure if `!is_mutable`.
2963 // I think this will require adjusting Sema to copy the value or something
2964 // like that; otherwise it causes use of undefined value when freeing resources.
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);
2975 };
2976
2977 decl.ty = try decl_tv.ty.copy(&decl_arena.allocator);2970 decl.ty = try decl_tv.ty.copy(&decl_arena.allocator);
2978 decl.val = decl_val;2971 decl.val = try decl_tv.val.copy(&decl_arena.allocator);
2979 decl.align_val = try align_val.copy(&decl_arena.allocator);2972 decl.align_val = try align_val.copy(&decl_arena.allocator);
2980 decl.linksection_val = try linksection_val.copy(&decl_arena.allocator);2973 decl.linksection_val = try linksection_val.copy(&decl_arena.allocator);
2981 decl.has_tv = true;2974 decl.has_tv = true;
...@@ -3211,7 +3204,8 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) InnerError!vo...@@ -3211,7 +3204,8 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) InnerError!vo
3211 const decl_node = iter.parent_decl.relativeToNodeIndex(decl_block_inst_data.src_node);3204 const decl_node = iter.parent_decl.relativeToNodeIndex(decl_block_inst_data.src_node);
32123205
3213 // Every Decl needs a name.3206 // Every Decl needs a name.
3214 const raw_decl_name: [:0]const u8 = switch (decl_name_index) {3207 var is_named_test = false;
3208 const decl_name: [:0]const u8 = switch (decl_name_index) {
3215 0 => name: {3209 0 => name: {
3216 if (is_exported) {3210 if (is_exported) {
3217 const i = iter.usingnamespace_index;3211 const i = iter.usingnamespace_index;
...@@ -3228,24 +3222,28 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) InnerError!vo...@@ -3228,24 +3222,28 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) InnerError!vo
3228 iter.unnamed_test_index += 1;3222 iter.unnamed_test_index += 1;
3229 break :name try std.fmt.allocPrintZ(gpa, "test_{d}", .{i});3223 break :name try std.fmt.allocPrintZ(gpa, "test_{d}", .{i});
3230 },3224 },
3231 else => zir.nullTerminatedString(decl_name_index),3225 else => name: {
3232 };3226 const raw_name = zir.nullTerminatedString(decl_name_index);
3233 const decl_name = if (raw_decl_name.len != 0) raw_decl_name else name: {3227 if (raw_name.len == 0) {
3234 const test_name = zir.nullTerminatedString(decl_name_index + 1);3228 is_named_test = true;
3235 break :name try std.fmt.allocPrintZ(gpa, "test.{s}", .{test_name});3229 const test_name = zir.nullTerminatedString(decl_name_index + 1);
3230 break :name try std.fmt.allocPrintZ(gpa, "test.{s}", .{test_name});
3231 } else {
3232 break :name try gpa.dupeZ(u8, raw_name);
3233 }
3234 },
3236 };3235 };
32373236
3238 // We create a Decl for it regardless of analysis status.3237 // We create a Decl for it regardless of analysis status.
3239 const gop = try namespace.decls.getOrPut(gpa, decl_name);3238 const gop = try namespace.decls.getOrPut(gpa, decl_name);
3240 if (!gop.found_existing) {3239 if (!gop.found_existing) {
3241 const new_decl = try mod.allocateNewDecl(namespace, decl_node);3240 const new_decl = try mod.allocateNewDecl(namespace, decl_node);
3242 log.debug("scan new decl {*} ({s}) into {*}", .{ new_decl, decl_name, namespace });3241 log.debug("scan new {*} ({s}) into {*}", .{ new_decl, decl_name, namespace });
3243 new_decl.src_line = line;3242 new_decl.src_line = line;
3244 new_decl.name = decl_name;3243 new_decl.name = decl_name;
3245 gop.entry.value = new_decl;3244 gop.entry.value = new_decl;
3246 // Exported decls, comptime decls, usingnamespace decls, and3245 // Exported decls, comptime decls, usingnamespace decls, and
3247 // test decls if in test mode, get analyzed.3246 // test decls if in test mode, get analyzed.
3248 const is_named_test = raw_decl_name.len == 0;
3249 const want_analysis = is_exported or switch (decl_name_index) {3247 const want_analysis = is_exported or switch (decl_name_index) {
3250 0 => true, // comptime decl3248 0 => true, // comptime decl
3251 1 => mod.comp.bin_file.options.is_test, // test decl3249 1 => mod.comp.bin_file.options.is_test, // test decl
...@@ -3261,17 +3259,15 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) InnerError!vo...@@ -3261,17 +3259,15 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) InnerError!vo
3261 new_decl.zir_decl_index = @intCast(u32, decl_sub_index);3259 new_decl.zir_decl_index = @intCast(u32, decl_sub_index);
3262 return;3260 return;
3263 }3261 }
3262 gpa.free(decl_name);
3264 const decl = gop.entry.value;3263 const decl = gop.entry.value;
3265 log.debug("scan existing decl {*} ({s}) of {*}", .{ decl, decl_name, namespace });3264 log.debug("scan existing {*} ({s}) of {*}", .{ decl, decl_name, namespace });
3266 // Update the AST node of the decl; even if its contents are unchanged, it may3265 // Update the AST node of the decl; even if its contents are unchanged, it may
3267 // have been re-ordered.3266 // have been re-ordered.
3268 const prev_src_node = decl.src_node;3267 const prev_src_node = decl.src_node;
3269 decl.src_node = decl_node;3268 decl.src_node = decl_node;
3270 decl.src_line = line;3269 decl.src_line = line;
32713270
3272 decl.clearName(gpa);
3273 decl.name = decl_name;
3274
3275 decl.is_pub = is_pub;3271 decl.is_pub = is_pub;
3276 decl.is_exported = is_exported;3272 decl.is_exported = is_exported;
3277 decl.has_align = has_align;3273 decl.has_align = has_align;
...@@ -3305,14 +3301,13 @@ pub fn deleteDecl(...@@ -3305,14 +3301,13 @@ pub fn deleteDecl(
3305 const tracy = trace(@src());3301 const tracy = trace(@src());
3306 defer tracy.end();3302 defer tracy.end();
33073303
3308 log.debug("deleting decl '{s}'", .{decl.name});3304 log.debug("deleting {*} ({s})", .{ decl, decl.name });
33093305
3310 if (outdated_decls) |map| {3306 if (outdated_decls) |map| {
3311 _ = map.swapRemove(decl);3307 _ = map.swapRemove(decl);
3312 try map.ensureCapacity(map.count() + decl.dependants.count());3308 try map.ensureUnusedCapacity(decl.dependants.count());
3313 }3309 }
3314 try mod.deletion_set.ensureCapacity(mod.gpa, mod.deletion_set.count() +3310 try mod.deletion_set.ensureUnusedCapacity(mod.gpa, decl.dependencies.count());
3315 decl.dependencies.count());
33163311
3317 // Remove from the namespace it resides in.3312 // Remove from the namespace it resides in.
3318 decl.namespace.removeDecl(decl);3313 decl.namespace.removeDecl(decl);
...@@ -3354,7 +3349,9 @@ pub fn deleteDecl(...@@ -3354,7 +3349,9 @@ pub fn deleteDecl(
3354 }3349 }
3355 _ = mod.compile_log_decls.swapRemove(decl);3350 _ = mod.compile_log_decls.swapRemove(decl);
3356 mod.deleteDeclExports(decl);3351 mod.deleteDeclExports(decl);
3357 mod.comp.bin_file.freeDecl(decl);3352 if (decl.hasLinkAllocation()) {
3353 mod.comp.bin_file.freeDecl(decl);
3354 }
33583355
3359 decl.destroy(mod);3356 decl.destroy(mod);
3360}3357}
src/Sema.zig+56-1
...@@ -5742,8 +5742,63 @@ fn zirVarExtended(...@@ -5742,8 +5742,63 @@ fn zirVarExtended(
5742) InnerError!*Inst {5742) InnerError!*Inst {
5743 const extra = sema.code.extraData(Zir.Inst.ExtendedVar, extended.operand);5743 const extra = sema.code.extraData(Zir.Inst.ExtendedVar, extended.operand);
5744 const src = sema.src;5744 const src = sema.src;
5745 const align_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at align
5746 const ty_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at type
5747 const mut_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at mut token
5748 const init_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at init expr
5749 const small = @bitCast(Zir.Inst.ExtendedVar.Small, extended.small);
5750 const var_ty = try sema.resolveType(block, ty_src, extra.data.var_type);
5751
5752 var extra_index: usize = extra.end;
5753
5754 const lib_name: ?[]const u8 = if (small.has_lib_name) blk: {
5755 const lib_name = sema.code.nullTerminatedString(sema.code.extra[extra_index]);
5756 extra_index += 1;
5757 break :blk lib_name;
5758 } else null;
5759
5760 // ZIR supports encoding this information but it is not used; the information
5761 // is encoded via the Decl entry.
5762 assert(!small.has_align);
5763 //const align_val: Value = if (small.has_align) blk: {
5764 // const align_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
5765 // extra_index += 1;
5766 // const align_tv = try sema.resolveInstConst(block, align_src, align_ref);
5767 // break :blk align_tv.val;
5768 //} else Value.initTag(.null_value);
5769
5770 const init_val: Value = if (small.has_init) blk: {
5771 const init_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
5772 extra_index += 1;
5773 const init_tv = try sema.resolveInstConst(block, init_src, init_ref);
5774 break :blk init_tv.val;
5775 } else Value.initTag(.null_value);
5776
5777 if (!var_ty.isValidVarType(small.is_extern)) {
5778 return sema.mod.fail(&block.base, mut_src, "variable of type '{}' must be const", .{
5779 var_ty,
5780 });
5781 }
5782
5783 if (lib_name != null) {
5784 // Look at the sema code for functions which has this logic, it just needs to
5785 // be extracted and shared by both var and func
5786 return sema.mod.fail(&block.base, src, "TODO: handle var with lib_name in Sema", .{});
5787 }
57455788
5746 return sema.mod.fail(&block.base, src, "TODO implement Sema.zirVarExtended", .{});5789 const new_var = try sema.gpa.create(Module.Var);
5790 new_var.* = .{
5791 .owner_decl = sema.owner_decl,
5792 .init = init_val,
5793 .is_extern = small.is_extern,
5794 .is_mutable = true, // TODO get rid of this unused field
5795 .is_threadlocal = small.is_threadlocal,
5796 };
5797 const result = try sema.mod.constInst(sema.arena, src, .{
5798 .ty = var_ty,
5799 .val = try Value.Tag.variable.create(sema.arena, new_var),
5800 });
5801 return result;
5747}5802}
57485803
5749fn zirFuncExtended(5804fn zirFuncExtended(
src/Zir.zig+2-1
...@@ -2235,7 +2235,8 @@ pub const Inst = struct {...@@ -2235,7 +2235,8 @@ pub const Inst = struct {
2235 has_align: bool,2235 has_align: bool,
2236 has_init: bool,2236 has_init: bool,
2237 is_extern: bool,2237 is_extern: bool,
2238 _: u12 = undefined,2238 is_threadlocal: bool,
2239 _: u11 = undefined,
2239 };2240 };
2240 };2241 };
22412242
src/main.zig+2
...@@ -2086,6 +2086,8 @@ fn buildOutputType(...@@ -2086,6 +2086,8 @@ fn buildOutputType(
2086 break;2086 break;
2087 }2087 }
2088 }2088 }
2089 // Skip resource deallocation in release builds; let the OS do it.
2090 return cleanExit();
2089}2091}
20902092
2091fn runOrTest(2093fn runOrTest(
src/value.zig-8
...@@ -626,14 +626,6 @@ pub const Value = extern union {...@@ -626,14 +626,6 @@ pub const Value = extern union {
626 unreachable;626 unreachable;
627 }627 }
628628
629 /// Returns null if not a type or if the type has no namespace.
630 pub fn getTypeNamespace(self: Value) ?*Module.Scope.Namespace {
631 return switch (self.tag()) {
632 .ty => self.castTag(.ty).?.data.getNamespace(),
633 else => null,
634 };
635 }
636
637 /// Asserts that the value is representable as a type.629 /// Asserts that the value is representable as a type.
638 pub fn toType(self: Value, allocator: *Allocator) !Type {630 pub fn toType(self: Value, allocator: *Allocator) !Type {
639 return switch (self.tag()) {631 return switch (self.tag()) {
test/stage2/cbe.zig+1-1
...@@ -51,7 +51,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -51,7 +51,7 @@ pub fn addCases(ctx: *TestContext) !void {
51 \\}51 \\}
52 \\var y: i32 = 1234;52 \\var y: i32 = 1234;
53 , &.{53 , &.{
54 ":2:18: error: unable to resolve comptime value",54 ":2:22: error: unable to resolve comptime value",
55 ":5:26: error: unable to resolve comptime value",55 ":5:26: error: unable to resolve comptime value",
56 });56 });
57 }57 }