authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-23 22:23:03-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-23 22:42:31-07:00
log7b8cb881df7e034a8626caabf355055ee81a0fef
treee56858cd22ccf90217a49c51c7d8ff7df49ab0f3
parentf9798108f8434f277de6089502446f2544ee98b3

stage2: improvements towards `zig test`

* There is now a main_pkg in addition to root_pkg. They are usually the same. When using `zig test`, main_pkg is the user's source file and root_pkg has the test runner. * scanDecl no longer looks for test decls outside the package being tested. honoring `--test-filter` is still TODO. * test runner main function has a void return value rather than `anyerror!void` * Sema is improved to generate better AIR for for loops on slices. * Sema: fix incorrect capacity calculation in zirBoolBr * Sema: add compile errors for trying to use slice fields as an lvalue. * Sema: fix type coercion for error unions * Sema: fix analyzeVarRef generating garbage AIR * C codegen: fix renderValue for error unions with 0 bit payload * C codegen: implement function pointer calls * CLI: fix usage text Adds 4 new AIR instructions: * slice_len, slice_ptr: to get the ptr and len fields of a slice. * slice_elem_val, ptr_slice_elem_val: to get the element value of a slice, and a pointer to a slice. AstGen gains a new functionality: * One of the unused flags of struct decls is now used to indicate structs that are known to have non-zero size based on the AST alone.

25 files changed, 610 insertions(+), 173 deletions(-)

lib/std/special/test_runner.zig+2-2
...@@ -21,9 +21,9 @@ fn processArgs() void {...@@ -21,9 +21,9 @@ fn processArgs() void {
21 std.testing.zig_exe_path = args[1];21 std.testing.zig_exe_path = args[1];
22}22}
2323
24pub fn main() anyerror!void {24pub fn main() void {
25 if (builtin.zig_is_stage2) {25 if (builtin.zig_is_stage2) {
26 return main2();26 return main2() catch @panic("test failure");
27 }27 }
28 processArgs();28 processArgs();
29 const test_fn_list = builtin.test_functions;29 const test_fn_list = builtin.test_functions;
src/Air.zig+29-1
...@@ -247,6 +247,21 @@ pub const Inst = struct {...@@ -247,6 +247,21 @@ pub const Inst = struct {
247 /// Given a pointer to a struct and a field index, returns a pointer to the field.247 /// Given a pointer to a struct and a field index, returns a pointer to the field.
248 /// Uses the `ty_pl` field, payload is `StructField`.248 /// Uses the `ty_pl` field, payload is `StructField`.
249 struct_field_ptr,249 struct_field_ptr,
250 /// Given a slice value, return the length.
251 /// Result type is always usize.
252 /// Uses the `ty_op` field.
253 slice_len,
254 /// Given a slice value, return the pointer.
255 /// Uses the `ty_op` field.
256 slice_ptr,
257 /// Given a slice value, and element index, return the element value at that index.
258 /// Result type is the element type of the slice operand.
259 /// Uses the `bin_op` field.
260 slice_elem_val,
261 /// Given a pointer to a slice, and element index, return the element value at that index.
262 /// Result type is the element type of the slice operand (2 element type operations).
263 /// Uses the `bin_op` field.
264 ptr_slice_elem_val,
250265
251 pub fn fromCmpOp(op: std.math.CompareOperator) Tag {266 pub fn fromCmpOp(op: std.math.CompareOperator) Tag {
252 return switch (op) {267 return switch (op) {
...@@ -450,6 +465,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -450,6 +465,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
450 .unwrap_errunion_err_ptr,465 .unwrap_errunion_err_ptr,
451 .wrap_errunion_payload,466 .wrap_errunion_payload,
452 .wrap_errunion_err,467 .wrap_errunion_err,
468 .slice_ptr,
453 => return air.getRefType(datas[inst].ty_op.ty),469 => return air.getRefType(datas[inst].ty_op.ty),
454470
455 .loop,471 .loop,
...@@ -465,12 +481,24 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -465,12 +481,24 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
465 .store,481 .store,
466 => return Type.initTag(.void),482 => return Type.initTag(.void),
467483
468 .ptrtoint => return Type.initTag(.usize),484 .ptrtoint,
485 .slice_len,
486 => return Type.initTag(.usize),
469487
470 .call => {488 .call => {
471 const callee_ty = air.typeOf(datas[inst].pl_op.operand);489 const callee_ty = air.typeOf(datas[inst].pl_op.operand);
472 return callee_ty.fnReturnType();490 return callee_ty.fnReturnType();
473 },491 },
492
493 .slice_elem_val => {
494 const slice_ty = air.typeOf(datas[inst].bin_op.lhs);
495 return slice_ty.elemType();
496 },
497 .ptr_slice_elem_val => {
498 const ptr_slice_ty = air.typeOf(datas[inst].bin_op.lhs);
499 const slice_ty = ptr_slice_ty.elemType();
500 return slice_ty.elemType();
501 },
474 }502 }
475}503}
476504
src/AstGen.zig+190
...@@ -3470,6 +3470,7 @@ fn structDeclInner(...@@ -3470,6 +3470,7 @@ fn structDeclInner(
3470 .fields_len = 0,3470 .fields_len = 0,
3471 .body_len = 0,3471 .body_len = 0,
3472 .decls_len = 0,3472 .decls_len = 0,
3473 .known_has_bits = false,
3473 });3474 });
3474 return indexToRef(decl_inst);3475 return indexToRef(decl_inst);
3475 }3476 }
...@@ -3510,6 +3511,7 @@ fn structDeclInner(...@@ -3510,6 +3511,7 @@ fn structDeclInner(
3510 var bit_bag = ArrayListUnmanaged(u32){};3511 var bit_bag = ArrayListUnmanaged(u32){};
3511 defer bit_bag.deinit(gpa);3512 defer bit_bag.deinit(gpa);
35123513
3514 var known_has_bits = false;
3513 var cur_bit_bag: u32 = 0;3515 var cur_bit_bag: u32 = 0;
3514 var field_index: usize = 0;3516 var field_index: usize = 0;
3515 for (container_decl.ast.members) |member_node| {3517 for (container_decl.ast.members) |member_node| {
...@@ -3657,6 +3659,8 @@ fn structDeclInner(...@@ -3657,6 +3659,8 @@ fn structDeclInner(
3657 try typeExpr(&block_scope, &block_scope.base, member.ast.type_expr);3659 try typeExpr(&block_scope, &block_scope.base, member.ast.type_expr);
3658 fields_data.appendAssumeCapacity(@enumToInt(field_type));3660 fields_data.appendAssumeCapacity(@enumToInt(field_type));
36593661
3662 known_has_bits = known_has_bits or nodeImpliesRuntimeBits(tree, member.ast.type_expr);
3663
3660 const have_align = member.ast.align_expr != 0;3664 const have_align = member.ast.align_expr != 0;
3661 const have_value = member.ast.value_expr != 0;3665 const have_value = member.ast.value_expr != 0;
3662 const is_comptime = member.comptime_token != null;3666 const is_comptime = member.comptime_token != null;
...@@ -3706,6 +3710,7 @@ fn structDeclInner(...@@ -3706,6 +3710,7 @@ fn structDeclInner(
3706 .body_len = @intCast(u32, block_scope.instructions.items.len),3710 .body_len = @intCast(u32, block_scope.instructions.items.len),
3707 .fields_len = @intCast(u32, field_index),3711 .fields_len = @intCast(u32, field_index),
3708 .decls_len = @intCast(u32, wip_decls.decl_index),3712 .decls_len = @intCast(u32, wip_decls.decl_index),
3713 .known_has_bits = known_has_bits,
3709 });3714 });
37103715
3711 try astgen.extra.ensureUnusedCapacity(gpa, bit_bag.items.len +3716 try astgen.extra.ensureUnusedCapacity(gpa, bit_bag.items.len +
...@@ -8150,6 +8155,189 @@ fn nodeMayEvalToError(tree: *const ast.Tree, start_node: ast.Node.Index) enum {...@@ -8150,6 +8155,189 @@ fn nodeMayEvalToError(tree: *const ast.Tree, start_node: ast.Node.Index) enum {
8150 }8155 }
8151}8156}
81528157
8158fn nodeImpliesRuntimeBits(tree: *const ast.Tree, start_node: ast.Node.Index) bool {
8159 const node_tags = tree.nodes.items(.tag);
8160 const node_datas = tree.nodes.items(.data);
8161
8162 var node = start_node;
8163 while (true) {
8164 switch (node_tags[node]) {
8165 .root,
8166 .@"usingnamespace",
8167 .test_decl,
8168 .switch_case,
8169 .switch_case_one,
8170 .container_field_init,
8171 .container_field_align,
8172 .container_field,
8173 .asm_output,
8174 .asm_input,
8175 .global_var_decl,
8176 .local_var_decl,
8177 .simple_var_decl,
8178 .aligned_var_decl,
8179 => unreachable,
8180
8181 .@"return",
8182 .@"break",
8183 .@"continue",
8184 .bit_not,
8185 .bool_not,
8186 .@"defer",
8187 .@"errdefer",
8188 .address_of,
8189 .negation,
8190 .negation_wrap,
8191 .@"resume",
8192 .array_type,
8193 .@"suspend",
8194 .@"anytype",
8195 .fn_decl,
8196 .anyframe_literal,
8197 .integer_literal,
8198 .float_literal,
8199 .enum_literal,
8200 .string_literal,
8201 .multiline_string_literal,
8202 .char_literal,
8203 .true_literal,
8204 .false_literal,
8205 .null_literal,
8206 .undefined_literal,
8207 .unreachable_literal,
8208 .identifier,
8209 .error_set_decl,
8210 .container_decl,
8211 .container_decl_trailing,
8212 .container_decl_two,
8213 .container_decl_two_trailing,
8214 .container_decl_arg,
8215 .container_decl_arg_trailing,
8216 .tagged_union,
8217 .tagged_union_trailing,
8218 .tagged_union_two,
8219 .tagged_union_two_trailing,
8220 .tagged_union_enum_tag,
8221 .tagged_union_enum_tag_trailing,
8222 .@"asm",
8223 .asm_simple,
8224 .add,
8225 .add_wrap,
8226 .array_cat,
8227 .array_mult,
8228 .assign,
8229 .assign_bit_and,
8230 .assign_bit_or,
8231 .assign_bit_shift_left,
8232 .assign_bit_shift_right,
8233 .assign_bit_xor,
8234 .assign_div,
8235 .assign_sub,
8236 .assign_sub_wrap,
8237 .assign_mod,
8238 .assign_add,
8239 .assign_add_wrap,
8240 .assign_mul,
8241 .assign_mul_wrap,
8242 .bang_equal,
8243 .bit_and,
8244 .bit_or,
8245 .bit_shift_left,
8246 .bit_shift_right,
8247 .bit_xor,
8248 .bool_and,
8249 .bool_or,
8250 .div,
8251 .equal_equal,
8252 .error_union,
8253 .greater_or_equal,
8254 .greater_than,
8255 .less_or_equal,
8256 .less_than,
8257 .merge_error_sets,
8258 .mod,
8259 .mul,
8260 .mul_wrap,
8261 .switch_range,
8262 .field_access,
8263 .sub,
8264 .sub_wrap,
8265 .slice,
8266 .slice_open,
8267 .slice_sentinel,
8268 .deref,
8269 .array_access,
8270 .error_value,
8271 .while_simple,
8272 .while_cont,
8273 .for_simple,
8274 .if_simple,
8275 .@"catch",
8276 .@"orelse",
8277 .array_init_one,
8278 .array_init_one_comma,
8279 .array_init_dot_two,
8280 .array_init_dot_two_comma,
8281 .array_init_dot,
8282 .array_init_dot_comma,
8283 .array_init,
8284 .array_init_comma,
8285 .struct_init_one,
8286 .struct_init_one_comma,
8287 .struct_init_dot_two,
8288 .struct_init_dot_two_comma,
8289 .struct_init_dot,
8290 .struct_init_dot_comma,
8291 .struct_init,
8292 .struct_init_comma,
8293 .@"while",
8294 .@"if",
8295 .@"for",
8296 .@"switch",
8297 .switch_comma,
8298 .call_one,
8299 .call_one_comma,
8300 .async_call_one,
8301 .async_call_one_comma,
8302 .call,
8303 .call_comma,
8304 .async_call,
8305 .async_call_comma,
8306 .block_two,
8307 .block_two_semicolon,
8308 .block,
8309 .block_semicolon,
8310 .builtin_call,
8311 .builtin_call_comma,
8312 .builtin_call_two,
8313 .builtin_call_two_comma,
8314 => return false,
8315
8316 // Forward the question to the LHS sub-expression.
8317 .grouped_expression,
8318 .@"try",
8319 .@"await",
8320 .@"comptime",
8321 .@"nosuspend",
8322 .unwrap_optional,
8323 => node = node_datas[node].lhs,
8324
8325 .fn_proto_simple,
8326 .fn_proto_multi,
8327 .fn_proto_one,
8328 .fn_proto,
8329 .ptr_type_aligned,
8330 .ptr_type_sentinel,
8331 .ptr_type,
8332 .ptr_type_bit_range,
8333 .optional_type,
8334 .anyframe_type,
8335 .array_type_sentinel,
8336 => return true,
8337 }
8338 }
8339}
8340
8153/// Applies `rl` semantics to `inst`. Expressions which do not do their own handling of8341/// Applies `rl` semantics to `inst`. Expressions which do not do their own handling of
8154/// result locations must call this function on their result.8342/// result locations must call this function on their result.
8155/// As an example, if the `ResultLoc` is `ptr`, it will write the result to the pointer.8343/// As an example, if the `ResultLoc` is `ptr`, it will write the result to the pointer.
...@@ -9556,6 +9744,7 @@ const GenZir = struct {...@@ -9556,6 +9744,7 @@ const GenZir = struct {
9556 fields_len: u32,9744 fields_len: u32,
9557 decls_len: u32,9745 decls_len: u32,
9558 layout: std.builtin.TypeInfo.ContainerLayout,9746 layout: std.builtin.TypeInfo.ContainerLayout,
9747 known_has_bits: bool,
9559 }) !void {9748 }) !void {
9560 const astgen = gz.astgen;9749 const astgen = gz.astgen;
9561 const gpa = astgen.gpa;9750 const gpa = astgen.gpa;
...@@ -9585,6 +9774,7 @@ const GenZir = struct {...@@ -9585,6 +9774,7 @@ const GenZir = struct {
9585 .has_body_len = args.body_len != 0,9774 .has_body_len = args.body_len != 0,
9586 .has_fields_len = args.fields_len != 0,9775 .has_fields_len = args.fields_len != 0,
9587 .has_decls_len = args.decls_len != 0,9776 .has_decls_len = args.decls_len != 0,
9777 .known_has_bits = args.known_has_bits,
9588 .name_strategy = gz.anon_name_strategy,9778 .name_strategy = gz.anon_name_strategy,
9589 .layout = args.layout,9779 .layout = args.layout,
9590 }),9780 }),
src/Compilation.zig+44-26
...@@ -622,7 +622,7 @@ pub const InitOptions = struct {...@@ -622,7 +622,7 @@ pub const InitOptions = struct {
622 global_cache_directory: Directory,622 global_cache_directory: Directory,
623 target: Target,623 target: Target,
624 root_name: []const u8,624 root_name: []const u8,
625 root_pkg: ?*Package,625 main_pkg: ?*Package,
626 output_mode: std.builtin.OutputMode,626 output_mode: std.builtin.OutputMode,
627 thread_pool: *ThreadPool,627 thread_pool: *ThreadPool,
628 dynamic_linker: ?[]const u8 = null,628 dynamic_linker: ?[]const u8 = null,
...@@ -826,7 +826,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -826,7 +826,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
826 const ofmt = options.object_format orelse options.target.getObjectFormat();826 const ofmt = options.object_format orelse options.target.getObjectFormat();
827827
828 const use_stage1 = options.use_stage1 orelse blk: {828 const use_stage1 = options.use_stage1 orelse blk: {
829 // Even though we may have no Zig code to compile (depending on `options.root_pkg`),829 // Even though we may have no Zig code to compile (depending on `options.main_pkg`),
830 // we may need to use stage1 for building compiler-rt and other dependencies.830 // we may need to use stage1 for building compiler-rt and other dependencies.
831831
832 if (build_options.omit_stage2)832 if (build_options.omit_stage2)
...@@ -846,7 +846,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -846,7 +846,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
846 break :blk explicit;846 break :blk explicit;
847847
848 // If we have no zig code to compile, no need for LLVM.848 // If we have no zig code to compile, no need for LLVM.
849 if (options.root_pkg == null)849 if (options.main_pkg == null)
850 break :blk false;850 break :blk false;
851851
852 // If we are outputting .c code we must use Zig backend.852 // If we are outputting .c code we must use Zig backend.
...@@ -929,7 +929,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -929,7 +929,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
929 if (use_llvm) {929 if (use_llvm) {
930 // If stage1 generates an object file, self-hosted linker is not930 // If stage1 generates an object file, self-hosted linker is not
931 // yet sophisticated enough to handle that.931 // yet sophisticated enough to handle that.
932 break :blk options.root_pkg != null;932 break :blk options.main_pkg != null;
933 }933 }
934934
935 break :blk false;935 break :blk false;
...@@ -1159,7 +1159,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -1159,7 +1159,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
1159 if (options.target.os.tag == .wasi) cache.hash.add(wasi_exec_model);1159 if (options.target.os.tag == .wasi) cache.hash.add(wasi_exec_model);
1160 // TODO audit this and make sure everything is in it1160 // TODO audit this and make sure everything is in it
11611161
1162 const module: ?*Module = if (options.root_pkg) |root_pkg| blk: {1162 const module: ?*Module = if (options.main_pkg) |main_pkg| blk: {
1163 // Options that are specific to zig source files, that cannot be1163 // Options that are specific to zig source files, that cannot be
1164 // modified between incremental updates.1164 // modified between incremental updates.
1165 var hash = cache.hash;1165 var hash = cache.hash;
...@@ -1169,13 +1169,13 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -1169,13 +1169,13 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
1169 // incremental compilation will handle it, but we do want to namespace different1169 // incremental compilation will handle it, but we do want to namespace different
1170 // source file names because they are likely different compilations and therefore this1170 // source file names because they are likely different compilations and therefore this
1171 // would be likely to cause cache hits.1171 // would be likely to cause cache hits.
1172 hash.addBytes(root_pkg.root_src_path);1172 hash.addBytes(main_pkg.root_src_path);
1173 hash.addOptionalBytes(root_pkg.root_src_directory.path);1173 hash.addOptionalBytes(main_pkg.root_src_directory.path);
1174 {1174 {
1175 var local_arena = std.heap.ArenaAllocator.init(gpa);1175 var local_arena = std.heap.ArenaAllocator.init(gpa);
1176 defer local_arena.deinit();1176 defer local_arena.deinit();
1177 var seen_table = std.AutoHashMap(*Package, void).init(&local_arena.allocator);1177 var seen_table = std.AutoHashMap(*Package, void).init(&local_arena.allocator);
1178 try addPackageTableToCacheHash(&hash, &local_arena, root_pkg.table, &seen_table, .path_bytes);1178 try addPackageTableToCacheHash(&hash, &local_arena, main_pkg.table, &seen_table, .path_bytes);
1179 }1179 }
1180 hash.add(valgrind);1180 hash.add(valgrind);
1181 hash.add(single_threaded);1181 hash.add(single_threaded);
...@@ -1212,9 +1212,26 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -1212,9 +1212,26 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
1212 );1212 );
1213 errdefer std_pkg.destroy(gpa);1213 errdefer std_pkg.destroy(gpa);
12141214
1215 try root_pkg.addAndAdopt(gpa, "builtin", builtin_pkg);1215 const root_pkg = if (options.is_test) root_pkg: {
1216 try root_pkg.add(gpa, "root", root_pkg);1216 const test_pkg = try Package.createWithDir(
1217 try root_pkg.addAndAdopt(gpa, "std", std_pkg);1217 gpa,
1218 options.zig_lib_directory,
1219 "std" ++ std.fs.path.sep_str ++ "special",
1220 "test_runner.zig",
1221 );
1222 errdefer test_pkg.destroy(gpa);
1223
1224 try test_pkg.add(gpa, "builtin", builtin_pkg);
1225 try test_pkg.add(gpa, "root", test_pkg);
1226 try test_pkg.add(gpa, "std", std_pkg);
1227
1228 break :root_pkg test_pkg;
1229 } else main_pkg;
1230 errdefer if (options.is_test) root_pkg.destroy(gpa);
1231
1232 try main_pkg.addAndAdopt(gpa, "builtin", builtin_pkg);
1233 try main_pkg.add(gpa, "root", root_pkg);
1234 try main_pkg.addAndAdopt(gpa, "std", std_pkg);
12181235
1219 try std_pkg.add(gpa, "builtin", builtin_pkg);1236 try std_pkg.add(gpa, "builtin", builtin_pkg);
1220 try std_pkg.add(gpa, "root", root_pkg);1237 try std_pkg.add(gpa, "root", root_pkg);
...@@ -1258,6 +1275,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -1258,6 +1275,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
1258 module.* = .{1275 module.* = .{
1259 .gpa = gpa,1276 .gpa = gpa,
1260 .comp = comp,1277 .comp = comp,
1278 .main_pkg = main_pkg,
1261 .root_pkg = root_pkg,1279 .root_pkg = root_pkg,
1262 .zig_cache_artifact_directory = zig_cache_artifact_directory,1280 .zig_cache_artifact_directory = zig_cache_artifact_directory,
1263 .global_zir_cache = global_zir_cache,1281 .global_zir_cache = global_zir_cache,
...@@ -1684,7 +1702,7 @@ pub fn update(self: *Compilation) !void {...@@ -1684,7 +1702,7 @@ pub fn update(self: *Compilation) !void {
16841702
1685 // Make sure std.zig is inside the import_table. We unconditionally need1703 // Make sure std.zig is inside the import_table. We unconditionally need
1686 // it for start.zig.1704 // it for start.zig.
1687 const std_pkg = module.root_pkg.table.get("std").?;1705 const std_pkg = module.main_pkg.table.get("std").?;
1688 _ = try module.importPkg(std_pkg);1706 _ = try module.importPkg(std_pkg);
16891707
1690 // Normally we rely on importing std to in turn import the root source file1708 // Normally we rely on importing std to in turn import the root source file
...@@ -1692,7 +1710,7 @@ pub fn update(self: *Compilation) !void {...@@ -1692,7 +1710,7 @@ pub fn update(self: *Compilation) !void {
1692 // so in order to run AstGen on the root source file we put it into the1710 // so in order to run AstGen on the root source file we put it into the
1693 // import_table here.1711 // import_table here.
1694 if (use_stage1) {1712 if (use_stage1) {
1695 _ = try module.importPkg(module.root_pkg);1713 _ = try module.importPkg(module.main_pkg);
1696 }1714 }
16971715
1698 // Put a work item in for every known source file to detect if1716 // Put a work item in for every known source file to detect if
...@@ -3873,7 +3891,7 @@ fn buildOutputFromZig(...@@ -3873,7 +3891,7 @@ fn buildOutputFromZig(
3873 var special_dir = try comp.zig_lib_directory.handle.openDir(special_sub, .{});3891 var special_dir = try comp.zig_lib_directory.handle.openDir(special_sub, .{});
3874 defer special_dir.close();3892 defer special_dir.close();
38753893
3876 var root_pkg: Package = .{3894 var main_pkg: Package = .{
3877 .root_src_directory = .{3895 .root_src_directory = .{
3878 .path = special_path,3896 .path = special_path,
3879 .handle = special_dir,3897 .handle = special_dir,
...@@ -3899,7 +3917,7 @@ fn buildOutputFromZig(...@@ -3899,7 +3917,7 @@ fn buildOutputFromZig(
3899 .zig_lib_directory = comp.zig_lib_directory,3917 .zig_lib_directory = comp.zig_lib_directory,
3900 .target = target,3918 .target = target,
3901 .root_name = root_name,3919 .root_name = root_name,
3902 .root_pkg = &root_pkg,3920 .main_pkg = &main_pkg,
3903 .output_mode = output_mode,3921 .output_mode = output_mode,
3904 .thread_pool = comp.thread_pool,3922 .thread_pool = comp.thread_pool,
3905 .libc_installation = comp.bin_file.options.libc_installation,3923 .libc_installation = comp.bin_file.options.libc_installation,
...@@ -3969,8 +3987,8 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node...@@ -3969,8 +3987,8 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
3969 // Here we use the legacy stage1 C++ compiler to compile Zig code.3987 // Here we use the legacy stage1 C++ compiler to compile Zig code.
3970 const mod = comp.bin_file.options.module.?;3988 const mod = comp.bin_file.options.module.?;
3971 const directory = mod.zig_cache_artifact_directory; // Just an alias to make it shorter to type.3989 const directory = mod.zig_cache_artifact_directory; // Just an alias to make it shorter to type.
3972 const main_zig_file = try mod.root_pkg.root_src_directory.join(arena, &[_][]const u8{3990 const main_zig_file = try mod.main_pkg.root_src_directory.join(arena, &[_][]const u8{
3973 mod.root_pkg.root_src_path,3991 mod.main_pkg.root_src_path,
3974 });3992 });
3975 const zig_lib_dir = comp.zig_lib_directory.path.?;3993 const zig_lib_dir = comp.zig_lib_directory.path.?;
3976 const builtin_zig_path = try directory.join(arena, &[_][]const u8{"builtin.zig"});3994 const builtin_zig_path = try directory.join(arena, &[_][]const u8{"builtin.zig"});
...@@ -4002,7 +4020,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node...@@ -4002,7 +4020,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
4002 _ = try man.addFile(main_zig_file, null);4020 _ = try man.addFile(main_zig_file, null);
4003 {4021 {
4004 var seen_table = std.AutoHashMap(*Package, void).init(&arena_allocator.allocator);4022 var seen_table = std.AutoHashMap(*Package, void).init(&arena_allocator.allocator);
4005 try addPackageTableToCacheHash(&man.hash, &arena_allocator, mod.root_pkg.table, &seen_table, .{ .files = &man });4023 try addPackageTableToCacheHash(&man.hash, &arena_allocator, mod.main_pkg.table, &seen_table, .{ .files = &man });
4006 }4024 }
4007 man.hash.add(comp.bin_file.options.valgrind);4025 man.hash.add(comp.bin_file.options.valgrind);
4008 man.hash.add(comp.bin_file.options.single_threaded);4026 man.hash.add(comp.bin_file.options.single_threaded);
...@@ -4045,7 +4063,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node...@@ -4045,7 +4063,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
4045 &prev_digest_buf,4063 &prev_digest_buf,
4046 ) catch |err| blk: {4064 ) catch |err| blk: {
4047 log.debug("stage1 {s} new_digest={s} error: {s}", .{4065 log.debug("stage1 {s} new_digest={s} error: {s}", .{
4048 mod.root_pkg.root_src_path,4066 mod.main_pkg.root_src_path,
4049 std.fmt.fmtSliceHexLower(&digest),4067 std.fmt.fmtSliceHexLower(&digest),
4050 @errorName(err),4068 @errorName(err),
4051 });4069 });
...@@ -4057,7 +4075,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node...@@ -4057,7 +4075,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
4057 break :hit;4075 break :hit;
40584076
4059 log.debug("stage1 {s} digest={s} match - skipping invocation", .{4077 log.debug("stage1 {s} digest={s} match - skipping invocation", .{
4060 mod.root_pkg.root_src_path,4078 mod.main_pkg.root_src_path,
4061 std.fmt.fmtSliceHexLower(&digest),4079 std.fmt.fmtSliceHexLower(&digest),
4062 });4080 });
4063 var flags_bytes: [1]u8 = undefined;4081 var flags_bytes: [1]u8 = undefined;
...@@ -4083,7 +4101,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node...@@ -4083,7 +4101,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
4083 return;4101 return;
4084 }4102 }
4085 log.debug("stage1 {s} prev_digest={s} new_digest={s}", .{4103 log.debug("stage1 {s} prev_digest={s} new_digest={s}", .{
4086 mod.root_pkg.root_src_path,4104 mod.main_pkg.root_src_path,
4087 std.fmt.fmtSliceHexLower(prev_digest),4105 std.fmt.fmtSliceHexLower(prev_digest),
4088 std.fmt.fmtSliceHexLower(&digest),4106 std.fmt.fmtSliceHexLower(&digest),
4089 });4107 });
...@@ -4109,7 +4127,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node...@@ -4109,7 +4127,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
41094127
4110 comp.stage1_cache_manifest = &man;4128 comp.stage1_cache_manifest = &man;
41114129
4112 const main_pkg_path = mod.root_pkg.root_src_directory.path orelse "";4130 const main_pkg_path = mod.main_pkg.root_src_directory.path orelse "";
41134131
4114 const stage1_module = stage1.create(4132 const stage1_module = stage1.create(
4115 @enumToInt(comp.bin_file.options.optimize_mode),4133 @enumToInt(comp.bin_file.options.optimize_mode),
...@@ -4142,7 +4160,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node...@@ -4142,7 +4160,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
4142 const emit_llvm_bc_path = try stage1LocPath(arena, comp.emit_llvm_bc, directory);4160 const emit_llvm_bc_path = try stage1LocPath(arena, comp.emit_llvm_bc, directory);
4143 const emit_analysis_path = try stage1LocPath(arena, comp.emit_analysis, directory);4161 const emit_analysis_path = try stage1LocPath(arena, comp.emit_analysis, directory);
4144 const emit_docs_path = try stage1LocPath(arena, comp.emit_docs, directory);4162 const emit_docs_path = try stage1LocPath(arena, comp.emit_docs, directory);
4145 const stage1_pkg = try createStage1Pkg(arena, "root", mod.root_pkg, null);4163 const stage1_pkg = try createStage1Pkg(arena, "root", mod.main_pkg, null);
4146 const test_filter = comp.test_filter orelse ""[0..0];4164 const test_filter = comp.test_filter orelse ""[0..0];
4147 const test_name_prefix = comp.test_name_prefix orelse ""[0..0];4165 const test_name_prefix = comp.test_name_prefix orelse ""[0..0];
4148 const subsystem = if (comp.bin_file.options.subsystem) |s|4166 const subsystem = if (comp.bin_file.options.subsystem) |s|
...@@ -4173,7 +4191,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node...@@ -4173,7 +4191,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
4173 .test_name_prefix_ptr = test_name_prefix.ptr,4191 .test_name_prefix_ptr = test_name_prefix.ptr,
4174 .test_name_prefix_len = test_name_prefix.len,4192 .test_name_prefix_len = test_name_prefix.len,
4175 .userdata = @ptrToInt(comp),4193 .userdata = @ptrToInt(comp),
4176 .root_pkg = stage1_pkg,4194 .main_pkg = stage1_pkg,
4177 .code_model = @enumToInt(comp.bin_file.options.machine_code_model),4195 .code_model = @enumToInt(comp.bin_file.options.machine_code_model),
4178 .subsystem = subsystem,4196 .subsystem = subsystem,
4179 .err_color = @enumToInt(comp.color),4197 .err_color = @enumToInt(comp.color),
...@@ -4239,7 +4257,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node...@@ -4239,7 +4257,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
4239 // means that the next invocation will have an unnecessary cache miss.4257 // means that the next invocation will have an unnecessary cache miss.
4240 const stage1_flags_byte = @bitCast(u8, mod.stage1_flags);4258 const stage1_flags_byte = @bitCast(u8, mod.stage1_flags);
4241 log.debug("stage1 {s} final digest={s} flags={x}", .{4259 log.debug("stage1 {s} final digest={s} flags={x}", .{
4242 mod.root_pkg.root_src_path, std.fmt.fmtSliceHexLower(&digest), stage1_flags_byte,4260 mod.main_pkg.root_src_path, std.fmt.fmtSliceHexLower(&digest), stage1_flags_byte,
4243 });4261 });
4244 var digest_plus_flags: [digest.len + 2]u8 = undefined;4262 var digest_plus_flags: [digest.len + 2]u8 = undefined;
4245 digest_plus_flags[0..digest.len].* = digest;4263 digest_plus_flags[0..digest.len].* = digest;
...@@ -4333,7 +4351,7 @@ pub fn build_crt_file(...@@ -4333,7 +4351,7 @@ pub fn build_crt_file(
4333 .zig_lib_directory = comp.zig_lib_directory,4351 .zig_lib_directory = comp.zig_lib_directory,
4334 .target = target,4352 .target = target,
4335 .root_name = root_name,4353 .root_name = root_name,
4336 .root_pkg = null,4354 .main_pkg = null,
4337 .output_mode = output_mode,4355 .output_mode = output_mode,
4338 .thread_pool = comp.thread_pool,4356 .thread_pool = comp.thread_pool,
4339 .libc_installation = comp.bin_file.options.libc_installation,4357 .libc_installation = comp.bin_file.options.libc_installation,
src/Liveness.zig+4
...@@ -243,6 +243,8 @@ fn analyzeInst(...@@ -243,6 +243,8 @@ fn analyzeInst(
243 .bool_and,243 .bool_and,
244 .bool_or,244 .bool_or,
245 .store,245 .store,
246 .slice_elem_val,
247 .ptr_slice_elem_val,
246 => {248 => {
247 const o = inst_datas[inst].bin_op;249 const o = inst_datas[inst].bin_op;
248 return trackOperands(a, new_set, inst, main_tomb, .{ o.lhs, o.rhs, .none });250 return trackOperands(a, new_set, inst, main_tomb, .{ o.lhs, o.rhs, .none });
...@@ -273,6 +275,8 @@ fn analyzeInst(...@@ -273,6 +275,8 @@ fn analyzeInst(
273 .unwrap_errunion_err_ptr,275 .unwrap_errunion_err_ptr,
274 .wrap_errunion_payload,276 .wrap_errunion_payload,
275 .wrap_errunion_err,277 .wrap_errunion_err,
278 .slice_ptr,
279 .slice_len,
276 => {280 => {
277 const o = inst_datas[inst].ty_op;281 const o = inst_datas[inst].ty_op;
278 return trackOperands(a, new_set, inst, main_tomb, .{ o.operand, .none, .none });282 return trackOperands(a, new_set, inst, main_tomb, .{ o.operand, .none, .none });
src/Module.zig+31-8
...@@ -35,8 +35,11 @@ comp: *Compilation,...@@ -35,8 +35,11 @@ comp: *Compilation,
3535
36/// Where our incremental compilation metadata serialization will go.36/// Where our incremental compilation metadata serialization will go.
37zig_cache_artifact_directory: Compilation.Directory,37zig_cache_artifact_directory: Compilation.Directory,
38/// Pointer to externally managed resource. `null` if there is no zig file being compiled.38/// Pointer to externally managed resource.
39root_pkg: *Package,39root_pkg: *Package,
40/// Normally, `main_pkg` and `root_pkg` are the same. The exception is `zig test`, in which
41/// `root_pkg` is the test runner, and `main_pkg` is the user's source file which has the tests.
42main_pkg: *Package,
4043
41/// Used by AstGen worker to load and store ZIR cache.44/// Used by AstGen worker to load and store ZIR cache.
42global_zir_cache: Compilation.Directory,45global_zir_cache: Compilation.Directory,
...@@ -598,6 +601,9 @@ pub const Struct = struct {...@@ -598,6 +601,9 @@ pub const Struct = struct {
598 layout_wip,601 layout_wip,
599 have_layout,602 have_layout,
600 },603 },
604 /// If true, definitely nonzero size at runtime. If false, resolving the fields
605 /// is necessary to determine whether it has bits at runtime.
606 known_has_bits: bool,
601607
602 pub const Field = struct {608 pub const Field = struct {
603 /// Uses `noreturn` to indicate `anytype`.609 /// Uses `noreturn` to indicate `anytype`.
...@@ -2048,19 +2054,22 @@ pub fn deinit(mod: *Module) void {...@@ -2048,19 +2054,22 @@ pub fn deinit(mod: *Module) void {
20482054
2049 mod.deletion_set.deinit(gpa);2055 mod.deletion_set.deinit(gpa);
20502056
2051 // The callsite of `Compilation.create` owns the `root_pkg`, however2057 // The callsite of `Compilation.create` owns the `main_pkg`, however
2052 // Module owns the builtin and std packages that it adds.2058 // Module owns the builtin and std packages that it adds.
2053 if (mod.root_pkg.table.fetchRemove("builtin")) |kv| {2059 if (mod.main_pkg.table.fetchRemove("builtin")) |kv| {
2054 gpa.free(kv.key);2060 gpa.free(kv.key);
2055 kv.value.destroy(gpa);2061 kv.value.destroy(gpa);
2056 }2062 }
2057 if (mod.root_pkg.table.fetchRemove("std")) |kv| {2063 if (mod.main_pkg.table.fetchRemove("std")) |kv| {
2058 gpa.free(kv.key);2064 gpa.free(kv.key);
2059 kv.value.destroy(gpa);2065 kv.value.destroy(gpa);
2060 }2066 }
2061 if (mod.root_pkg.table.fetchRemove("root")) |kv| {2067 if (mod.main_pkg.table.fetchRemove("root")) |kv| {
2062 gpa.free(kv.key);2068 gpa.free(kv.key);
2063 }2069 }
2070 if (mod.root_pkg != mod.main_pkg) {
2071 mod.root_pkg.destroy(gpa);
2072 }
20642073
2065 mod.compile_log_text.deinit(gpa);2074 mod.compile_log_text.deinit(gpa);
20662075
...@@ -2148,7 +2157,7 @@ pub fn astGenFile(mod: *Module, file: *Scope.File) !void {...@@ -2148,7 +2157,7 @@ pub fn astGenFile(mod: *Module, file: *Scope.File) !void {
21482157
2149 const stat = try source_file.stat();2158 const stat = try source_file.stat();
21502159
2151 const want_local_cache = file.pkg == mod.root_pkg;2160 const want_local_cache = file.pkg == mod.main_pkg;
2152 const digest = hash: {2161 const digest = hash: {
2153 var path_hash: Cache.HashHelper = .{};2162 var path_hash: Cache.HashHelper = .{};
2154 path_hash.addBytes(build_options.version);2163 path_hash.addBytes(build_options.version);
...@@ -2792,6 +2801,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {...@@ -2792,6 +2801,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {
2792 .zir_index = undefined, // set below2801 .zir_index = undefined, // set below
2793 .layout = .Auto,2802 .layout = .Auto,
2794 .status = .none,2803 .status = .none,
2804 .known_has_bits = undefined,
2795 .namespace = .{2805 .namespace = .{
2796 .parent = null,2806 .parent = null,
2797 .ty = struct_ty,2807 .ty = struct_ty,
...@@ -3301,10 +3311,23 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi...@@ -3301,10 +3311,23 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi
3301 gop.value_ptr.* = new_decl;3311 gop.value_ptr.* = new_decl;
3302 // Exported decls, comptime decls, usingnamespace decls, and3312 // Exported decls, comptime decls, usingnamespace decls, and
3303 // test decls if in test mode, get analyzed.3313 // test decls if in test mode, get analyzed.
3314 const decl_pkg = namespace.file_scope.pkg;
3304 const want_analysis = is_exported or switch (decl_name_index) {3315 const want_analysis = is_exported or switch (decl_name_index) {
3305 0 => true, // comptime decl3316 0 => true, // comptime decl
3306 1 => mod.comp.bin_file.options.is_test, // test decl3317 1 => blk: {
3307 else => is_named_test and mod.comp.bin_file.options.is_test,3318 // test decl with no name. Skip the part where we check against
3319 // the test name filter.
3320 if (!mod.comp.bin_file.options.is_test) break :blk false;
3321 if (decl_pkg != mod.main_pkg) break :blk false;
3322 break :blk true;
3323 },
3324 else => blk: {
3325 if (!is_named_test) break :blk false;
3326 if (!mod.comp.bin_file.options.is_test) break :blk false;
3327 if (decl_pkg != mod.main_pkg) break :blk false;
3328 // TODO check the name against --test-filter
3329 break :blk true;
3330 },
3308 };3331 };
3309 if (want_analysis) {3332 if (want_analysis) {
3310 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });3333 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
src/Sema.zig+125-49
...@@ -768,6 +768,8 @@ pub fn analyzeStructDecl(...@@ -768,6 +768,8 @@ pub fn analyzeStructDecl(
768 assert(extended.opcode == .struct_decl);768 assert(extended.opcode == .struct_decl);
769 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);769 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
770770
771 struct_obj.known_has_bits = small.known_has_bits;
772
771 var extra_index: usize = extended.operand;773 var extra_index: usize = extended.operand;
772 extra_index += @boolToInt(small.has_src_node);774 extra_index += @boolToInt(small.has_src_node);
773 extra_index += @boolToInt(small.has_body_len);775 extra_index += @boolToInt(small.has_body_len);
...@@ -812,6 +814,7 @@ fn zirStructDecl(...@@ -812,6 +814,7 @@ fn zirStructDecl(
812 .zir_index = inst,814 .zir_index = inst,
813 .layout = small.layout,815 .layout = small.layout,
814 .status = .none,816 .status = .none,
817 .known_has_bits = undefined,
815 .namespace = .{818 .namespace = .{
816 .parent = sema.owner_decl.namespace,819 .parent = sema.owner_decl.namespace,
817 .ty = struct_ty,820 .ty = struct_ty,
...@@ -1259,8 +1262,13 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Co...@@ -1259,8 +1262,13 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Co
1259 const inst_data = sema.code.instructions.items(.data)[inst].un_node;1262 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
1260 const src = inst_data.src();1263 const src = inst_data.src();
1261 const array_ptr = sema.resolveInst(inst_data.operand);1264 const array_ptr = sema.resolveInst(inst_data.operand);
1265 const array_ptr_src = src;
12621266
1263 const elem_ty = sema.typeOf(array_ptr).elemType();1267 const elem_ty = sema.typeOf(array_ptr).elemType();
1268 if (elem_ty.isSlice()) {
1269 const slice_inst = try sema.analyzeLoad(block, src, array_ptr, array_ptr_src);
1270 return sema.analyzeSliceLen(block, src, slice_inst);
1271 }
1264 if (!elem_ty.isIndexable()) {1272 if (!elem_ty.isIndexable()) {
1265 const cond_src: LazySrcLoc = .{ .node_offset_for_cond = inst_data.src_node };1273 const cond_src: LazySrcLoc = .{ .node_offset_for_cond = inst_data.src_node };
1266 const msg = msg: {1274 const msg = msg: {
...@@ -1283,7 +1291,7 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Co...@@ -1283,7 +1291,7 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Co
1283 return sema.mod.failWithOwnedErrorMsg(&block.base, msg);1291 return sema.mod.failWithOwnedErrorMsg(&block.base, msg);
1284 }1292 }
1285 const result_ptr = try sema.namedFieldPtr(block, src, array_ptr, "len", src);1293 const result_ptr = try sema.namedFieldPtr(block, src, array_ptr, "len", src);
1286 const result_ptr_src = src;1294 const result_ptr_src = array_ptr_src;
1287 return sema.analyzeLoad(block, src, result_ptr, result_ptr_src);1295 return sema.analyzeLoad(block, src, result_ptr, result_ptr_src);
1288}1296}
12891297
...@@ -2928,17 +2936,15 @@ fn zirErrUnionPayload(...@@ -2928,17 +2936,15 @@ fn zirErrUnionPayload(
2928 return sema.mod.fail(&block.base, src, "caught unexpected error '{s}'", .{name});2936 return sema.mod.fail(&block.base, src, "caught unexpected error '{s}'", .{name});
2929 }2937 }
2930 const data = val.castTag(.error_union).?.data;2938 const data = val.castTag(.error_union).?.data;
2931 return sema.addConstant(2939 const result_ty = operand_ty.errorUnionPayload();
2932 operand_ty.castTag(.error_union).?.data.payload,2940 return sema.addConstant(result_ty, data);
2933 data,
2934 );
2935 }2941 }
2936 try sema.requireRuntimeBlock(block, src);2942 try sema.requireRuntimeBlock(block, src);
2937 if (safety_check and block.wantSafety()) {2943 if (safety_check and block.wantSafety()) {
2938 const is_non_err = try block.addUnOp(.is_err, operand);2944 const is_non_err = try block.addUnOp(.is_err, operand);
2939 try sema.addSafetyCheck(block, is_non_err, .unwrap_errunion);2945 try sema.addSafetyCheck(block, is_non_err, .unwrap_errunion);
2940 }2946 }
2941 const result_ty = operand_ty.castTag(.error_union).?.data.payload;2947 const result_ty = operand_ty.errorUnionPayload();
2942 return block.addTyOp(.unwrap_errunion_payload, result_ty, operand);2948 return block.addTyOp(.unwrap_errunion_payload, result_ty, operand);
2943}2949}
29442950
...@@ -2961,7 +2967,8 @@ fn zirErrUnionPayloadPtr(...@@ -2961,7 +2967,8 @@ fn zirErrUnionPayloadPtr(
2961 if (operand_ty.elemType().zigTypeTag() != .ErrorUnion)2967 if (operand_ty.elemType().zigTypeTag() != .ErrorUnion)
2962 return sema.mod.fail(&block.base, src, "expected error union type, found {}", .{operand_ty.elemType()});2968 return sema.mod.fail(&block.base, src, "expected error union type, found {}", .{operand_ty.elemType()});
29632969
2964 const operand_pointer_ty = try Module.simplePtrType(sema.arena, operand_ty.elemType().castTag(.error_union).?.data.payload, !operand_ty.isConstPtr(), .One);2970 const payload_ty = operand_ty.elemType().errorUnionPayload();
2971 const operand_pointer_ty = try Module.simplePtrType(sema.arena, payload_ty, !operand_ty.isConstPtr(), .One);
29652972
2966 if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| {2973 if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| {
2967 const val = try pointer_val.pointerDeref(sema.arena);2974 const val = try pointer_val.pointerDeref(sema.arena);
...@@ -2999,7 +3006,7 @@ fn zirErrUnionCode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Compi...@@ -2999,7 +3006,7 @@ fn zirErrUnionCode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Compi
2999 if (operand_ty.zigTypeTag() != .ErrorUnion)3006 if (operand_ty.zigTypeTag() != .ErrorUnion)
3000 return sema.mod.fail(&block.base, src, "expected error union type, found '{}'", .{operand_ty});3007 return sema.mod.fail(&block.base, src, "expected error union type, found '{}'", .{operand_ty});
30013008
3002 const result_ty = operand_ty.castTag(.error_union).?.data.error_set;3009 const result_ty = operand_ty.errorUnionSet();
30033010
3004 if (try sema.resolveDefinedValue(block, src, operand)) |val| {3011 if (try sema.resolveDefinedValue(block, src, operand)) |val| {
3005 assert(val.getError() != null);3012 assert(val.getError() != null);
...@@ -3025,7 +3032,7 @@ fn zirErrUnionCodePtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Co...@@ -3025,7 +3032,7 @@ fn zirErrUnionCodePtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Co
3025 if (operand_ty.elemType().zigTypeTag() != .ErrorUnion)3032 if (operand_ty.elemType().zigTypeTag() != .ErrorUnion)
3026 return sema.mod.fail(&block.base, src, "expected error union type, found {}", .{operand_ty.elemType()});3033 return sema.mod.fail(&block.base, src, "expected error union type, found {}", .{operand_ty.elemType()});
30273034
3028 const result_ty = operand_ty.elemType().castTag(.error_union).?.data.error_set;3035 const result_ty = operand_ty.elemType().errorUnionSet();
30293036
3030 if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| {3037 if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| {
3031 const val = try pointer_val.pointerDeref(sema.arena);3038 const val = try pointer_val.pointerDeref(sema.arena);
...@@ -3048,7 +3055,7 @@ fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Inde...@@ -3048,7 +3055,7 @@ fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Inde
3048 const operand_ty = sema.typeOf(operand);3055 const operand_ty = sema.typeOf(operand);
3049 if (operand_ty.zigTypeTag() != .ErrorUnion)3056 if (operand_ty.zigTypeTag() != .ErrorUnion)
3050 return sema.mod.fail(&block.base, src, "expected error union type, found '{}'", .{operand_ty});3057 return sema.mod.fail(&block.base, src, "expected error union type, found '{}'", .{operand_ty});
3051 if (operand_ty.castTag(.error_union).?.data.payload.zigTypeTag() != .Void) {3058 if (operand_ty.errorUnionPayload().zigTypeTag() != .Void) {
3052 return sema.mod.fail(&block.base, src, "expression value is ignored", .{});3059 return sema.mod.fail(&block.base, src, "expression value is ignored", .{});
3053 }3060 }
3054}3061}
...@@ -3460,14 +3467,8 @@ fn zirElemVal(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr...@@ -3460,14 +3467,8 @@ fn zirElemVal(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr
34603467
3461 const bin_inst = sema.code.instructions.items(.data)[inst].bin;3468 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
3462 const array = sema.resolveInst(bin_inst.lhs);3469 const array = sema.resolveInst(bin_inst.lhs);
3463 const array_ty = sema.typeOf(array);
3464 const array_ptr = if (array_ty.zigTypeTag() == .Pointer)
3465 array
3466 else
3467 try sema.analyzeRef(block, sema.src, array);
3468 const elem_index = sema.resolveInst(bin_inst.rhs);3470 const elem_index = sema.resolveInst(bin_inst.rhs);
3469 const result_ptr = try sema.elemPtr(block, sema.src, array_ptr, elem_index, sema.src);3471 return sema.elemVal(block, sema.src, array, elem_index, sema.src);
3470 return sema.analyzeLoad(block, sema.src, result_ptr, sema.src);
3471}3472}
34723473
3473fn zirElemValNode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {3474fn zirElemValNode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -3479,14 +3480,8 @@ fn zirElemValNode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Compil...@@ -3479,14 +3480,8 @@ fn zirElemValNode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Compil
3479 const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node };3480 const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node };
3480 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;3481 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
3481 const array = sema.resolveInst(extra.lhs);3482 const array = sema.resolveInst(extra.lhs);
3482 const array_ty = sema.typeOf(array);
3483 const array_ptr = if (array_ty.zigTypeTag() == .Pointer)
3484 array
3485 else
3486 try sema.analyzeRef(block, src, array);
3487 const elem_index = sema.resolveInst(extra.rhs);3483 const elem_index = sema.resolveInst(extra.rhs);
3488 const result_ptr = try sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src);3484 return sema.elemVal(block, src, array, elem_index, elem_index_src);
3489 return sema.analyzeLoad(block, src, result_ptr, src);
3490}3485}
34913486
3492fn zirElemPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {3487fn zirElemPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -5338,7 +5333,7 @@ fn zirBoolBr(...@@ -5338,7 +5333,7 @@ fn zirBoolBr(
53385333
5339 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +5334 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +
5340 then_block.instructions.items.len + else_block.instructions.items.len +5335 then_block.instructions.items.len + else_block.instructions.items.len +
5341 @typeInfo(Air.Block).Struct.fields.len + child_block.instructions.items.len);5336 @typeInfo(Air.Block).Struct.fields.len + child_block.instructions.items.len + 1);
53425337
5343 const cond_br_payload = sema.addExtraAssumeCapacity(Air.CondBr{5338 const cond_br_payload = sema.addExtraAssumeCapacity(Air.CondBr{
5344 .then_body_len = @intCast(u32, then_block.instructions.items.len),5339 .then_body_len = @intCast(u32, then_block.instructions.items.len),
...@@ -6217,8 +6212,9 @@ fn zirVarExtended(...@@ -6217,8 +6212,9 @@ fn zirVarExtended(
6217 const init_val: Value = if (small.has_init) blk: {6212 const init_val: Value = if (small.has_init) blk: {
6218 const init_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);6213 const init_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
6219 extra_index += 1;6214 extra_index += 1;
6220 const init_tv = try sema.resolveInstConst(block, init_src, init_ref);6215 const init_air_inst = sema.resolveInst(init_ref);
6221 break :blk init_tv.val;6216 break :blk (try sema.resolvePossiblyUndefinedValue(block, init_src, init_air_inst)) orelse
6217 return sema.failWithNeededComptime(block, init_src);
6222 } else Value.initTag(.unreachable_value);6218 } else Value.initTag(.unreachable_value);
62236219
6224 if (!var_ty.isValidVarType(small.is_extern)) {6220 if (!var_ty.isValidVarType(small.is_extern)) {
...@@ -6586,7 +6582,30 @@ fn namedFieldPtr(...@@ -6586,7 +6582,30 @@ fn namedFieldPtr(
6586 },6582 },
6587 .Pointer => {6583 .Pointer => {
6588 const ptr_child = elem_ty.elemType();6584 const ptr_child = elem_ty.elemType();
6589 switch (ptr_child.zigTypeTag()) {6585 if (ptr_child.isSlice()) {
6586 if (mem.eql(u8, field_name, "ptr")) {
6587 return mod.fail(
6588 &block.base,
6589 field_name_src,
6590 "cannot obtain reference to pointer field of slice '{}'",
6591 .{elem_ty},
6592 );
6593 } else if (mem.eql(u8, field_name, "len")) {
6594 return mod.fail(
6595 &block.base,
6596 field_name_src,
6597 "cannot obtain reference to length field of slice '{}'",
6598 .{elem_ty},
6599 );
6600 } else {
6601 return mod.fail(
6602 &block.base,
6603 field_name_src,
6604 "no member named '{s}' in '{}'",
6605 .{ field_name, elem_ty },
6606 );
6607 }
6608 } else switch (ptr_child.zigTypeTag()) {
6590 .Array => {6609 .Array => {
6591 if (mem.eql(u8, field_name, "len")) {6610 if (mem.eql(u8, field_name, "len")) {
6592 return sema.addConstant(6611 return sema.addConstant(
...@@ -6836,6 +6855,50 @@ fn elemPtr(...@@ -6836,6 +6855,50 @@ fn elemPtr(
6836 return sema.mod.fail(&block.base, src, "TODO implement more analyze elemptr", .{});6855 return sema.mod.fail(&block.base, src, "TODO implement more analyze elemptr", .{});
6837}6856}
68386857
6858fn elemVal(
6859 sema: *Sema,
6860 block: *Scope.Block,
6861 src: LazySrcLoc,
6862 array_maybe_ptr: Air.Inst.Ref,
6863 elem_index: Air.Inst.Ref,
6864 elem_index_src: LazySrcLoc,
6865) CompileError!Air.Inst.Ref {
6866 const array_ptr_src = src; // TODO better source location
6867 const maybe_ptr_ty = sema.typeOf(array_maybe_ptr);
6868 if (maybe_ptr_ty.isSinglePointer()) {
6869 const indexable_ty = maybe_ptr_ty.elemType();
6870 if (indexable_ty.isSlice()) {
6871 // We have a pointer to a slice and we want an element value.
6872 if (try sema.isComptimeKnown(block, src, array_maybe_ptr)) {
6873 const slice = try sema.analyzeLoad(block, src, array_maybe_ptr, array_ptr_src);
6874 if (try sema.resolveDefinedValue(block, src, slice)) |slice_val| {
6875 _ = slice_val;
6876 return sema.mod.fail(&block.base, src, "TODO implement Sema for elemVal for comptime known slice", .{});
6877 }
6878 try sema.requireRuntimeBlock(block, src);
6879 return block.addBinOp(.slice_elem_val, slice, elem_index);
6880 }
6881 try sema.requireRuntimeBlock(block, src);
6882 return block.addBinOp(.ptr_slice_elem_val, array_maybe_ptr, elem_index);
6883 }
6884 }
6885 if (maybe_ptr_ty.isSlice()) {
6886 if (try sema.resolveDefinedValue(block, src, array_maybe_ptr)) |slice_val| {
6887 _ = slice_val;
6888 return sema.mod.fail(&block.base, src, "TODO implement Sema for elemVal for comptime known slice", .{});
6889 }
6890 try sema.requireRuntimeBlock(block, src);
6891 return block.addBinOp(.slice_elem_val, array_maybe_ptr, elem_index);
6892 }
6893
6894 const array_ptr = if (maybe_ptr_ty.zigTypeTag() == .Pointer)
6895 array_maybe_ptr
6896 else
6897 try sema.analyzeRef(block, src, array_maybe_ptr);
6898 const ptr = try sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src);
6899 return sema.analyzeLoad(block, src, ptr, elem_index_src);
6900}
6901
6839fn elemPtrArray(6902fn elemPtrArray(
6840 sema: *Sema,6903 sema: *Sema,
6841 block: *Scope.Block,6904 block: *Scope.Block,
...@@ -6896,11 +6959,6 @@ fn coerce(...@@ -6896,11 +6959,6 @@ fn coerce(
6896 }6959 }
6897 assert(inst_ty.zigTypeTag() != .Undefined);6960 assert(inst_ty.zigTypeTag() != .Undefined);
68986961
6899 // T to E!T or E to E!T
6900 if (dest_type.tag() == .error_union) {
6901 return try sema.wrapErrorUnion(block, dest_type, inst, inst_src);
6902 }
6903
6904 // comptime known number to other number6962 // comptime known number to other number
6905 if (try sema.coerceNum(block, dest_type, inst, inst_src)) |some|6963 if (try sema.coerceNum(block, dest_type, inst, inst_src)) |some|
6906 return some;6964 return some;
...@@ -7028,6 +7086,10 @@ fn coerce(...@@ -7028,6 +7086,10 @@ fn coerce(
7028 );7086 );
7029 }7087 }
7030 },7088 },
7089 .ErrorUnion => {
7090 // T to E!T or E to E!T
7091 return sema.wrapErrorUnion(block, dest_type, inst, inst_src);
7092 },
7031 else => {},7093 else => {},
7032 }7094 }
70337095
...@@ -7257,16 +7319,13 @@ fn analyzeVarRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, tv: TypedVal...@@ -7257,16 +7319,13 @@ fn analyzeVarRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, tv: TypedVal
7257 const gpa = sema.gpa;7319 const gpa = sema.gpa;
7258 try sema.requireRuntimeBlock(block, src);7320 try sema.requireRuntimeBlock(block, src);
7259 try sema.air_variables.append(gpa, variable);7321 try sema.air_variables.append(gpa, variable);
7260 const result_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);7322 return block.addInst(.{
7261 try sema.air_instructions.append(gpa, .{
7262 .tag = .varptr,7323 .tag = .varptr,
7263 .data = .{ .ty_pl = .{7324 .data = .{ .ty_pl = .{
7264 .ty = try sema.addType(ty),7325 .ty = try sema.addType(ty),
7265 .payload = @intCast(u32, sema.air_variables.items.len - 1),7326 .payload = @intCast(u32, sema.air_variables.items.len - 1),
7266 } },7327 } },
7267 });7328 });
7268 try block.instructions.append(gpa, result_inst);
7269 return Air.indexToRef(result_inst);
7270}7329}
72717330
7272fn analyzeRef(7331fn analyzeRef(
...@@ -7309,6 +7368,22 @@ fn analyzeLoad(...@@ -7309,6 +7368,22 @@ fn analyzeLoad(
7309 return block.addTyOp(.load, elem_ty, ptr);7368 return block.addTyOp(.load, elem_ty, ptr);
7310}7369}
73117370
7371fn analyzeSliceLen(
7372 sema: *Sema,
7373 block: *Scope.Block,
7374 src: LazySrcLoc,
7375 slice_inst: Air.Inst.Ref,
7376) CompileError!Air.Inst.Ref {
7377 if (try sema.resolvePossiblyUndefinedValue(block, src, slice_inst)) |slice_val| {
7378 if (slice_val.isUndef()) {
7379 return sema.addConstUndef(Type.initTag(.usize));
7380 }
7381 return sema.mod.fail(&block.base, src, "TODO implement Sema analyzeSliceLen on comptime slice", .{});
7382 }
7383 try sema.requireRuntimeBlock(block, src);
7384 return block.addTyOp(.slice_len, Type.initTag(.usize), slice_inst);
7385}
7386
7312fn analyzeIsNull(7387fn analyzeIsNull(
7313 sema: *Sema,7388 sema: *Sema,
7314 block: *Scope.Block,7389 block: *Scope.Block,
...@@ -7645,27 +7720,28 @@ fn wrapErrorUnion(...@@ -7645,27 +7720,28 @@ fn wrapErrorUnion(
7645 inst_src: LazySrcLoc,7720 inst_src: LazySrcLoc,
7646) !Air.Inst.Ref {7721) !Air.Inst.Ref {
7647 const inst_ty = sema.typeOf(inst);7722 const inst_ty = sema.typeOf(inst);
7648 const err_union = dest_type.castTag(.error_union).?;7723 const dest_err_set_ty = dest_type.errorUnionSet();
7724 const dest_payload_ty = dest_type.errorUnionPayload();
7649 if (try sema.resolvePossiblyUndefinedValue(block, inst_src, inst)) |val| {7725 if (try sema.resolvePossiblyUndefinedValue(block, inst_src, inst)) |val| {
7650 if (inst_ty.zigTypeTag() != .ErrorSet) {7726 if (inst_ty.zigTypeTag() != .ErrorSet) {
7651 _ = try sema.coerce(block, err_union.data.payload, inst, inst_src);7727 _ = try sema.coerce(block, dest_payload_ty, inst, inst_src);
7652 } else switch (err_union.data.error_set.tag()) {7728 } else switch (dest_err_set_ty.tag()) {
7653 .anyerror => {},7729 .anyerror => {},
7654 .error_set_single => {7730 .error_set_single => {
7655 const expected_name = val.castTag(.@"error").?.data.name;7731 const expected_name = val.castTag(.@"error").?.data.name;
7656 const n = err_union.data.error_set.castTag(.error_set_single).?.data;7732 const n = dest_err_set_ty.castTag(.error_set_single).?.data;
7657 if (!mem.eql(u8, expected_name, n)) {7733 if (!mem.eql(u8, expected_name, n)) {
7658 return sema.mod.fail(7734 return sema.mod.fail(
7659 &block.base,7735 &block.base,
7660 inst_src,7736 inst_src,
7661 "expected type '{}', found type '{}'",7737 "expected type '{}', found type '{}'",
7662 .{ err_union.data.error_set, inst_ty },7738 .{ dest_err_set_ty, inst_ty },
7663 );7739 );
7664 }7740 }
7665 },7741 },
7666 .error_set => {7742 .error_set => {
7667 const expected_name = val.castTag(.@"error").?.data.name;7743 const expected_name = val.castTag(.@"error").?.data.name;
7668 const error_set = err_union.data.error_set.castTag(.error_set).?.data;7744 const error_set = dest_err_set_ty.castTag(.error_set).?.data;
7669 const names = error_set.names_ptr[0..error_set.names_len];7745 const names = error_set.names_ptr[0..error_set.names_len];
7670 // TODO this is O(N). I'm putting off solving this until we solve inferred7746 // TODO this is O(N). I'm putting off solving this until we solve inferred
7671 // error sets at the same time.7747 // error sets at the same time.
...@@ -7677,19 +7753,19 @@ fn wrapErrorUnion(...@@ -7677,19 +7753,19 @@ fn wrapErrorUnion(
7677 &block.base,7753 &block.base,
7678 inst_src,7754 inst_src,
7679 "expected type '{}', found type '{}'",7755 "expected type '{}', found type '{}'",
7680 .{ err_union.data.error_set, inst_ty },7756 .{ dest_err_set_ty, inst_ty },
7681 );7757 );
7682 }7758 }
7683 },7759 },
7684 .error_set_inferred => {7760 .error_set_inferred => {
7685 const expected_name = val.castTag(.@"error").?.data.name;7761 const expected_name = val.castTag(.@"error").?.data.name;
7686 const map = &err_union.data.error_set.castTag(.error_set_inferred).?.data.map;7762 const map = &dest_err_set_ty.castTag(.error_set_inferred).?.data.map;
7687 if (!map.contains(expected_name)) {7763 if (!map.contains(expected_name)) {
7688 return sema.mod.fail(7764 return sema.mod.fail(
7689 &block.base,7765 &block.base,
7690 inst_src,7766 inst_src,
7691 "expected type '{}', found type '{}'",7767 "expected type '{}', found type '{}'",
7692 .{ err_union.data.error_set, inst_ty },7768 .{ dest_err_set_ty, inst_ty },
7693 );7769 );
7694 }7770 }
7695 },7771 },
...@@ -7704,10 +7780,10 @@ fn wrapErrorUnion(...@@ -7704,10 +7780,10 @@ fn wrapErrorUnion(
77047780
7705 // we are coercing from E to E!T7781 // we are coercing from E to E!T
7706 if (inst_ty.zigTypeTag() == .ErrorSet) {7782 if (inst_ty.zigTypeTag() == .ErrorSet) {
7707 var coerced = try sema.coerce(block, err_union.data.error_set, inst, inst_src);7783 var coerced = try sema.coerce(block, dest_err_set_ty, inst, inst_src);
7708 return block.addTyOp(.wrap_errunion_err, dest_type, coerced);7784 return block.addTyOp(.wrap_errunion_err, dest_type, coerced);
7709 } else {7785 } else {
7710 var coerced = try sema.coerce(block, err_union.data.payload, inst, inst_src);7786 var coerced = try sema.coerce(block, dest_payload_ty, inst, inst_src);
7711 return block.addTyOp(.wrap_errunion_payload, dest_type, coerced);7787 return block.addTyOp(.wrap_errunion_payload, dest_type, coerced);
7712 }7788 }
7713}7789}
...@@ -7857,7 +7933,7 @@ fn getBuiltin(...@@ -7857,7 +7933,7 @@ fn getBuiltin(
7857 name: []const u8,7933 name: []const u8,
7858) CompileError!Air.Inst.Ref {7934) CompileError!Air.Inst.Ref {
7859 const mod = sema.mod;7935 const mod = sema.mod;
7860 const std_pkg = mod.root_pkg.table.get("std").?;7936 const std_pkg = mod.main_pkg.table.get("std").?;
7861 const std_file = (mod.importPkg(std_pkg) catch unreachable).file;7937 const std_file = (mod.importPkg(std_pkg) catch unreachable).file;
7862 const opt_builtin_inst = try sema.analyzeNamespaceLookup(7938 const opt_builtin_inst = try sema.analyzeNamespaceLookup(
7863 block,7939 block,
src/Zir.zig+3-1
...@@ -2462,9 +2462,10 @@ pub const Inst = struct {...@@ -2462,9 +2462,10 @@ pub const Inst = struct {
2462 has_body_len: bool,2462 has_body_len: bool,
2463 has_fields_len: bool,2463 has_fields_len: bool,
2464 has_decls_len: bool,2464 has_decls_len: bool,
2465 known_has_bits: bool,
2465 name_strategy: NameStrategy,2466 name_strategy: NameStrategy,
2466 layout: std.builtin.TypeInfo.ContainerLayout,2467 layout: std.builtin.TypeInfo.ContainerLayout,
2467 _: u8 = undefined,2468 _: u7 = undefined,
2468 };2469 };
2469 };2470 };
24702471
...@@ -3543,6 +3544,7 @@ const Writer = struct {...@@ -3543,6 +3544,7 @@ const Writer = struct {
3543 break :blk decls_len;3544 break :blk decls_len;
3544 } else 0;3545 } else 0;
35453546
3547 try self.writeFlag(stream, "known_has_bits, ", small.known_has_bits);
3546 try stream.print("{s}, {s}, ", .{3548 try stream.print("{s}, {s}, ", .{
3547 @tagName(small.name_strategy), @tagName(small.layout),3549 @tagName(small.name_strategy), @tagName(small.layout),
3548 });3550 });
src/codegen.zig+37
...@@ -853,6 +853,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -853,6 +853,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
853 .struct_field_ptr=> try self.airStructFieldPtr(inst),853 .struct_field_ptr=> try self.airStructFieldPtr(inst),
854 .switch_br => try self.airSwitch(inst),854 .switch_br => try self.airSwitch(inst),
855 .varptr => try self.airVarPtr(inst),855 .varptr => try self.airVarPtr(inst),
856 .slice_ptr => try self.airSlicePtr(inst),
857 .slice_len => try self.airSliceLen(inst),
858
859 .slice_elem_val => try self.airSliceElemVal(inst),
860 .ptr_slice_elem_val => try self.airPtrSliceElemVal(inst),
856861
857 .constant => unreachable, // excluded from function bodies862 .constant => unreachable, // excluded from function bodies
858 .const_ty => unreachable, // excluded from function bodies863 .const_ty => unreachable, // excluded from function bodies
...@@ -1333,6 +1338,38 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1333,6 +1338,38 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1333 return self.finishAir(inst, result, .{ .none, .none, .none });1338 return self.finishAir(inst, result, .{ .none, .none, .none });
1334 }1339 }
13351340
1341 fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
1342 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1343 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
1344 else => return self.fail("TODO implement slice_ptr for {}", .{self.target.cpu.arch}),
1345 };
1346 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1347 }
1348
1349 fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
1350 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1351 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
1352 else => return self.fail("TODO implement slice_len for {}", .{self.target.cpu.arch}),
1353 };
1354 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1355 }
1356
1357 fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
1358 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1359 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
1360 else => return self.fail("TODO implement slice_elem_val for {}", .{self.target.cpu.arch}),
1361 };
1362 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1363 }
1364
1365 fn airPtrSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
1366 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1367 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
1368 else => return self.fail("TODO implement ptr_slice_elem_val for {}", .{self.target.cpu.arch}),
1369 };
1370 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1371 }
1372
1336 fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_index: Liveness.OperandInt, mcv: MCValue) bool {1373 fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_index: Liveness.OperandInt, mcv: MCValue) bool {
1337 if (!self.liveness.operandDies(inst, op_index))1374 if (!self.liveness.operandDies(inst, op_index))
1338 return false;1375 return false;
src/codegen/c.zig+89-41
...@@ -237,7 +237,8 @@ pub const DeclGen = struct {...@@ -237,7 +237,8 @@ pub const DeclGen = struct {
237 // This should lower to 0xaa bytes in safe modes, and for unsafe modes should237 // This should lower to 0xaa bytes in safe modes, and for unsafe modes should
238 // lower to leaving variables uninitialized (that might need to be implemented238 // lower to leaving variables uninitialized (that might need to be implemented
239 // outside of this function).239 // outside of this function).
240 return dg.fail("TODO: C backend: implement renderValue undef", .{});240 return writer.writeAll("{}");
241 //return dg.fail("TODO: C backend: implement renderValue undef", .{});
241 }242 }
242 switch (t.zigTypeTag()) {243 switch (t.zigTypeTag()) {
243 .Int => {244 .Int => {
...@@ -361,18 +362,27 @@ pub const DeclGen = struct {...@@ -361,18 +362,27 @@ pub const DeclGen = struct {
361 }362 }
362 },363 },
363 .ErrorSet => {364 .ErrorSet => {
364 const payload = val.castTag(.@"error").?;365 switch (val.tag()) {
365 // error values will be #defined at the top of the file366 .@"error" => {
366 return writer.print("zig_error_{s}", .{payload.data.name});367 const payload = val.castTag(.@"error").?;
368 // error values will be #defined at the top of the file
369 return writer.print("zig_error_{s}", .{payload.data.name});
370 },
371 else => {
372 // In this case we are rendering an error union which has a
373 // 0 bits payload.
374 return writer.writeAll("0");
375 },
376 }
367 },377 },
368 .ErrorUnion => {378 .ErrorUnion => {
369 const error_type = t.errorUnionSet();379 const error_type = t.errorUnionSet();
370 const payload_type = t.errorUnionChild();380 const payload_type = t.errorUnionPayload();
371 const data = val.castTag(.error_union).?.data;381 const sub_val = val.castTag(.error_union).?.data;
372382
373 if (!payload_type.hasCodeGenBits()) {383 if (!payload_type.hasCodeGenBits()) {
374 // We use the error type directly as the type.384 // We use the error type directly as the type.
375 return dg.renderValue(writer, error_type, data);385 return dg.renderValue(writer, error_type, sub_val);
376 }386 }
377387
378 try writer.writeByte('(');388 try writer.writeByte('(');
...@@ -383,7 +393,7 @@ pub const DeclGen = struct {...@@ -383,7 +393,7 @@ pub const DeclGen = struct {
383 try dg.renderValue(393 try dg.renderValue(
384 writer,394 writer,
385 error_type,395 error_type,
386 data,396 sub_val,
387 );397 );
388 try writer.writeAll(" }");398 try writer.writeAll(" }");
389 } else {399 } else {
...@@ -391,7 +401,7 @@ pub const DeclGen = struct {...@@ -391,7 +401,7 @@ pub const DeclGen = struct {
391 try dg.renderValue(401 try dg.renderValue(
392 writer,402 writer,
393 payload_type,403 payload_type,
394 data,404 sub_val,
395 );405 );
396 try writer.writeAll(", .error = 0 }");406 try writer.writeAll(", .error = 0 }");
397 }407 }
...@@ -616,7 +626,7 @@ pub const DeclGen = struct {...@@ -616,7 +626,7 @@ pub const DeclGen = struct {
616 if (dg.typedefs.get(t)) |some| {626 if (dg.typedefs.get(t)) |some| {
617 return w.writeAll(some.name);627 return w.writeAll(some.name);
618 }628 }
619 const child_type = t.errorUnionChild();629 const child_type = t.errorUnionPayload();
620 const err_set_type = t.errorUnionSet();630 const err_set_type = t.errorUnionSet();
621631
622 if (!child_type.hasCodeGenBits()) {632 if (!child_type.hasCodeGenBits()) {
...@@ -926,6 +936,11 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM...@@ -926,6 +936,11 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM
926 .ref => try airRef(o, inst),936 .ref => try airRef(o, inst),
927 .struct_field_ptr => try airStructFieldPtr(o, inst),937 .struct_field_ptr => try airStructFieldPtr(o, inst),
928 .varptr => try airVarPtr(o, inst),938 .varptr => try airVarPtr(o, inst),
939 .slice_ptr => try airSliceField(o, inst, ".ptr;\n"),
940 .slice_len => try airSliceField(o, inst, ".len;\n"),
941
942 .slice_elem_val => try airSliceElemVal(o, inst, "["),
943 .ptr_slice_elem_val => try airSliceElemVal(o, inst, "[0]["),
929944
930 .unwrap_errunion_payload => try airUnwrapErrUnionPay(o, inst),945 .unwrap_errunion_payload => try airUnwrapErrUnionPay(o, inst),
931 .unwrap_errunion_err => try airUnwrapErrUnionErr(o, inst),946 .unwrap_errunion_err => try airUnwrapErrUnionErr(o, inst),
...@@ -948,6 +963,37 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM...@@ -948,6 +963,37 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM
948 try writer.writeAll("}");963 try writer.writeAll("}");
949}964}
950965
966fn airSliceField(o: *Object, inst: Air.Inst.Index, suffix: []const u8) !CValue {
967 if (o.liveness.isUnused(inst))
968 return CValue.none;
969
970 const ty_op = o.air.instructions.items(.data)[inst].ty_op;
971 const operand = try o.resolveInst(ty_op.operand);
972 const writer = o.writer();
973 const local = try o.allocLocal(Type.initTag(.usize), .Const);
974 try writer.writeAll(" = ");
975 try o.writeCValue(writer, operand);
976 try writer.writeAll(suffix);
977 return local;
978}
979
980fn airSliceElemVal(o: *Object, inst: Air.Inst.Index, prefix: []const u8) !CValue {
981 if (o.liveness.isUnused(inst))
982 return CValue.none;
983
984 const bin_op = o.air.instructions.items(.data)[inst].bin_op;
985 const slice = try o.resolveInst(bin_op.lhs);
986 const index = try o.resolveInst(bin_op.rhs);
987 const writer = o.writer();
988 const local = try o.allocLocal(o.air.typeOfIndex(inst), .Const);
989 try writer.writeAll(" = ");
990 try o.writeCValue(writer, slice);
991 try writer.writeAll(prefix);
992 try o.writeCValue(writer, index);
993 try writer.writeAll("];\n");
994 return local;
995}
996
951fn airVarPtr(o: *Object, inst: Air.Inst.Index) !CValue {997fn airVarPtr(o: *Object, inst: Air.Inst.Index) !CValue {
952 const ty_pl = o.air.instructions.items(.data)[inst].ty_pl;998 const ty_pl = o.air.instructions.items(.data)[inst].ty_pl;
953 const variable = o.air.variables[ty_pl.payload];999 const variable = o.air.variables[ty_pl.payload];
...@@ -1233,6 +1279,20 @@ fn airCall(o: *Object, inst: Air.Inst.Index) !CValue {...@@ -1233,6 +1279,20 @@ fn airCall(o: *Object, inst: Air.Inst.Index) !CValue {
1233 const pl_op = o.air.instructions.items(.data)[inst].pl_op;1279 const pl_op = o.air.instructions.items(.data)[inst].pl_op;
1234 const extra = o.air.extraData(Air.Call, pl_op.payload);1280 const extra = o.air.extraData(Air.Call, pl_op.payload);
1235 const args = @bitCast([]const Air.Inst.Ref, o.air.extra[extra.end..][0..extra.data.args_len]);1281 const args = @bitCast([]const Air.Inst.Ref, o.air.extra[extra.end..][0..extra.data.args_len]);
1282 const fn_ty = o.air.typeOf(pl_op.operand);
1283 const ret_ty = fn_ty.fnReturnType();
1284 const unused_result = o.liveness.isUnused(inst);
1285 const writer = o.writer();
1286
1287 var result_local: CValue = .none;
1288 if (unused_result) {
1289 if (ret_ty.hasCodeGenBits()) {
1290 try writer.print("(void)", .{});
1291 }
1292 } else {
1293 result_local = try o.allocLocal(ret_ty, .Const);
1294 try writer.writeAll(" = ");
1295 }
12361296
1237 if (o.air.value(pl_op.operand)) |func_val| {1297 if (o.air.value(pl_op.operand)) |func_val| {
1238 const fn_decl = if (func_val.castTag(.extern_fn)) |extern_fn|1298 const fn_decl = if (func_val.castTag(.extern_fn)) |extern_fn|
...@@ -1242,38 +1302,26 @@ fn airCall(o: *Object, inst: Air.Inst.Index) !CValue {...@@ -1242,38 +1302,26 @@ fn airCall(o: *Object, inst: Air.Inst.Index) !CValue {
1242 else1302 else
1243 unreachable;1303 unreachable;
12441304
1245 const fn_ty = fn_decl.ty;1305 try writer.writeAll(mem.spanZ(fn_decl.name));
1246 const ret_ty = fn_ty.fnReturnType();1306 } else {
1247 const unused_result = o.liveness.isUnused(inst);1307 const callee = try o.resolveInst(pl_op.operand);
1248 var result_local: CValue = .none;1308 try o.writeCValue(writer, callee);
1309 }
12491310
1250 const writer = o.writer();1311 try writer.writeAll("(");
1251 if (unused_result) {1312 for (args) |arg, i| {
1252 if (ret_ty.hasCodeGenBits()) {1313 if (i != 0) {
1253 try writer.print("(void)", .{});1314 try writer.writeAll(", ");
1254 }
1255 } else {
1256 result_local = try o.allocLocal(ret_ty, .Const);
1257 try writer.writeAll(" = ");
1258 }1315 }
1259 const fn_name = mem.spanZ(fn_decl.name);1316 if (o.air.value(arg)) |val| {
1260 try writer.print("{s}(", .{fn_name});1317 try o.dg.renderValue(writer, o.air.typeOf(arg), val);
1261 for (args) |arg, i| {1318 } else {
1262 if (i != 0) {1319 const val = try o.resolveInst(arg);
1263 try writer.writeAll(", ");1320 try o.writeCValue(writer, val);
1264 }
1265 if (o.air.value(arg)) |val| {
1266 try o.dg.renderValue(writer, o.air.typeOf(arg), val);
1267 } else {
1268 const val = try o.resolveInst(arg);
1269 try o.writeCValue(writer, val);
1270 }
1271 }1321 }
1272 try writer.writeAll(");\n");
1273 return result_local;
1274 } else {
1275 return o.dg.fail("TODO: C backend: implement function pointers", .{});
1276 }1322 }
1323 try writer.writeAll(");\n");
1324 return result_local;
1277}1325}
12781326
1279fn airDbgStmt(o: *Object, inst: Air.Inst.Index) !CValue {1327fn airDbgStmt(o: *Object, inst: Air.Inst.Index) !CValue {
...@@ -1643,7 +1691,7 @@ fn airUnwrapErrUnionErr(o: *Object, inst: Air.Inst.Index) !CValue {...@@ -1643,7 +1691,7 @@ fn airUnwrapErrUnionErr(o: *Object, inst: Air.Inst.Index) !CValue {
1643 const operand = try o.resolveInst(ty_op.operand);1691 const operand = try o.resolveInst(ty_op.operand);
1644 const operand_ty = o.air.typeOf(ty_op.operand);1692 const operand_ty = o.air.typeOf(ty_op.operand);
16451693
1646 const payload_ty = operand_ty.errorUnionChild();1694 const payload_ty = operand_ty.errorUnionPayload();
1647 if (!payload_ty.hasCodeGenBits()) {1695 if (!payload_ty.hasCodeGenBits()) {
1648 if (operand_ty.zigTypeTag() == .Pointer) {1696 if (operand_ty.zigTypeTag() == .Pointer) {
1649 const local = try o.allocLocal(inst_ty, .Const);1697 const local = try o.allocLocal(inst_ty, .Const);
...@@ -1675,7 +1723,7 @@ fn airUnwrapErrUnionPay(o: *Object, inst: Air.Inst.Index) !CValue {...@@ -1675,7 +1723,7 @@ fn airUnwrapErrUnionPay(o: *Object, inst: Air.Inst.Index) !CValue {
1675 const operand = try o.resolveInst(ty_op.operand);1723 const operand = try o.resolveInst(ty_op.operand);
1676 const operand_ty = o.air.typeOf(ty_op.operand);1724 const operand_ty = o.air.typeOf(ty_op.operand);
16771725
1678 const payload_ty = operand_ty.errorUnionChild();1726 const payload_ty = operand_ty.errorUnionPayload();
1679 if (!payload_ty.hasCodeGenBits()) {1727 if (!payload_ty.hasCodeGenBits()) {
1680 return CValue.none;1728 return CValue.none;
1681 }1729 }
...@@ -1760,7 +1808,7 @@ fn airIsErr(...@@ -1760,7 +1808,7 @@ fn airIsErr(
1760 const operand = try o.resolveInst(un_op);1808 const operand = try o.resolveInst(un_op);
1761 const operand_ty = o.air.typeOf(un_op);1809 const operand_ty = o.air.typeOf(un_op);
1762 const local = try o.allocLocal(Type.initTag(.bool), .Const);1810 const local = try o.allocLocal(Type.initTag(.bool), .Const);
1763 const payload_ty = operand_ty.errorUnionChild();1811 const payload_ty = operand_ty.errorUnionPayload();
1764 if (!payload_ty.hasCodeGenBits()) {1812 if (!payload_ty.hasCodeGenBits()) {
1765 try writer.print(" = {s}", .{deref_prefix});1813 try writer.print(" = {s}", .{deref_prefix});
1766 try o.writeCValue(writer, operand);1814 try o.writeCValue(writer, operand);
src/codegen/wasm.zig+3-3
...@@ -646,7 +646,7 @@ pub const Context = struct {...@@ -646,7 +646,7 @@ pub const Context = struct {
646 } };646 } };
647 },647 },
648 .ErrorUnion => {648 .ErrorUnion => {
649 const payload_type = ty.errorUnionChild();649 const payload_type = ty.errorUnionPayload();
650 const val_type = try self.genValtype(payload_type);650 const val_type = try self.genValtype(payload_type);
651651
652 // we emit the error value as the first local, and the payload as the following.652 // we emit the error value as the first local, and the payload as the following.
...@@ -699,7 +699,7 @@ pub const Context = struct {...@@ -699,7 +699,7 @@ pub const Context = struct {
699 .Struct => return self.fail("TODO: Implement struct as return type for wasm", .{}),699 .Struct => return self.fail("TODO: Implement struct as return type for wasm", .{}),
700 .Optional => return self.fail("TODO: Implement optionals as return type for wasm", .{}),700 .Optional => return self.fail("TODO: Implement optionals as return type for wasm", .{}),
701 .ErrorUnion => {701 .ErrorUnion => {
702 const val_type = try self.genValtype(return_type.errorUnionChild());702 const val_type = try self.genValtype(return_type.errorUnionPayload());
703703
704 // write down the amount of return values704 // write down the amount of return values
705 try leb.writeULEB128(writer, @as(u32, 2));705 try leb.writeULEB128(writer, @as(u32, 2));
...@@ -1055,7 +1055,7 @@ pub const Context = struct {...@@ -1055,7 +1055,7 @@ pub const Context = struct {
1055 .ErrorUnion => {1055 .ErrorUnion => {
1056 const data = value.castTag(.error_union).?.data;1056 const data = value.castTag(.error_union).?.data;
1057 const error_type = ty.errorUnionSet();1057 const error_type = ty.errorUnionSet();
1058 const payload_type = ty.errorUnionChild();1058 const payload_type = ty.errorUnionPayload();
1059 if (value.getError()) |_| {1059 if (value.getError()) |_| {
1060 // write the error value1060 // write the error value
1061 try self.emitConstant(data, error_type);1061 try self.emitConstant(data, error_type);
src/glibc.zig+1-1
...@@ -943,7 +943,7 @@ fn buildSharedLib(...@@ -943,7 +943,7 @@ fn buildSharedLib(
943 .zig_lib_directory = comp.zig_lib_directory,943 .zig_lib_directory = comp.zig_lib_directory,
944 .target = comp.getTarget(),944 .target = comp.getTarget(),
945 .root_name = lib.name,945 .root_name = lib.name,
946 .root_pkg = null,946 .main_pkg = null,
947 .output_mode = .Lib,947 .output_mode = .Lib,
948 .link_mode = .Dynamic,948 .link_mode = .Dynamic,
949 .thread_pool = comp.thread_pool,949 .thread_pool = comp.thread_pool,
src/libcxx.zig+2-2
...@@ -169,7 +169,7 @@ pub fn buildLibCXX(comp: *Compilation) !void {...@@ -169,7 +169,7 @@ pub fn buildLibCXX(comp: *Compilation) !void {
169 .zig_lib_directory = comp.zig_lib_directory,169 .zig_lib_directory = comp.zig_lib_directory,
170 .target = target,170 .target = target,
171 .root_name = root_name,171 .root_name = root_name,
172 .root_pkg = null,172 .main_pkg = null,
173 .output_mode = output_mode,173 .output_mode = output_mode,
174 .thread_pool = comp.thread_pool,174 .thread_pool = comp.thread_pool,
175 .libc_installation = comp.bin_file.options.libc_installation,175 .libc_installation = comp.bin_file.options.libc_installation,
...@@ -301,7 +301,7 @@ pub fn buildLibCXXABI(comp: *Compilation) !void {...@@ -301,7 +301,7 @@ pub fn buildLibCXXABI(comp: *Compilation) !void {
301 .zig_lib_directory = comp.zig_lib_directory,301 .zig_lib_directory = comp.zig_lib_directory,
302 .target = target,302 .target = target,
303 .root_name = root_name,303 .root_name = root_name,
304 .root_pkg = null,304 .main_pkg = null,
305 .output_mode = output_mode,305 .output_mode = output_mode,
306 .thread_pool = comp.thread_pool,306 .thread_pool = comp.thread_pool,
307 .libc_installation = comp.bin_file.options.libc_installation,307 .libc_installation = comp.bin_file.options.libc_installation,
src/libtsan.zig+1-1
...@@ -201,7 +201,7 @@ pub fn buildTsan(comp: *Compilation) !void {...@@ -201,7 +201,7 @@ pub fn buildTsan(comp: *Compilation) !void {
201 .zig_lib_directory = comp.zig_lib_directory,201 .zig_lib_directory = comp.zig_lib_directory,
202 .target = target,202 .target = target,
203 .root_name = root_name,203 .root_name = root_name,
204 .root_pkg = null,204 .main_pkg = null,
205 .output_mode = output_mode,205 .output_mode = output_mode,
206 .thread_pool = comp.thread_pool,206 .thread_pool = comp.thread_pool,
207 .libc_installation = comp.bin_file.options.libc_installation,207 .libc_installation = comp.bin_file.options.libc_installation,
src/libunwind.zig+1-1
...@@ -101,7 +101,7 @@ pub fn buildStaticLib(comp: *Compilation) !void {...@@ -101,7 +101,7 @@ pub fn buildStaticLib(comp: *Compilation) !void {
101 .zig_lib_directory = comp.zig_lib_directory,101 .zig_lib_directory = comp.zig_lib_directory,
102 .target = target,102 .target = target,
103 .root_name = root_name,103 .root_name = root_name,
104 .root_pkg = null,104 .main_pkg = null,
105 .output_mode = output_mode,105 .output_mode = output_mode,
106 .thread_pool = comp.thread_pool,106 .thread_pool = comp.thread_pool,
107 .libc_installation = comp.bin_file.options.libc_installation,107 .libc_installation = comp.bin_file.options.libc_installation,
src/main.zig+15-15
...@@ -263,12 +263,12 @@ pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v...@@ -263,12 +263,12 @@ pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
263}263}
264264
265const usage_build_generic =265const usage_build_generic =
266 \\Usage: zig build-exe <options> [files]266 \\Usage: zig build-exe [options] [files]
267 \\ zig build-lib <options> [files]267 \\ zig build-lib [options] [files]
268 \\ zig build-obj <options> [files]268 \\ zig build-obj [options] [files]
269 \\ zig test <options> [files]269 \\ zig test [options] [files]
270 \\ zig run <options> [file] [-- [args]]270 \\ zig run [options] [files] [-- [args]]
271 \\ zig translate-c <options> [file]271 \\ zig translate-c [options] [file]
272 \\272 \\
273 \\Supported file types:273 \\Supported file types:
274 \\ .zig Zig source code274 \\ .zig Zig source code
...@@ -1915,7 +1915,7 @@ fn buildOutputType(...@@ -1915,7 +1915,7 @@ fn buildOutputType(
1915 };1915 };
1916 defer emit_docs_resolved.deinit();1916 defer emit_docs_resolved.deinit();
19171917
1918 const root_pkg: ?*Package = if (root_src_file) |src_path| blk: {1918 const main_pkg: ?*Package = if (root_src_file) |src_path| blk: {
1919 if (main_pkg_path) |p| {1919 if (main_pkg_path) |p| {
1920 const rel_src_path = try fs.path.relative(gpa, p, src_path);1920 const rel_src_path = try fs.path.relative(gpa, p, src_path);
1921 defer gpa.free(rel_src_path);1921 defer gpa.free(rel_src_path);
...@@ -1924,10 +1924,10 @@ fn buildOutputType(...@@ -1924,10 +1924,10 @@ fn buildOutputType(
1924 break :blk try Package.create(gpa, fs.path.dirname(src_path), fs.path.basename(src_path));1924 break :blk try Package.create(gpa, fs.path.dirname(src_path), fs.path.basename(src_path));
1925 }1925 }
1926 } else null;1926 } else null;
1927 defer if (root_pkg) |p| p.destroy(gpa);1927 defer if (main_pkg) |p| p.destroy(gpa);
19281928
1929 // Transfer packages added with --pkg-begin/--pkg-end to the root package1929 // Transfer packages added with --pkg-begin/--pkg-end to the root package
1930 if (root_pkg) |pkg| {1930 if (main_pkg) |pkg| {
1931 pkg.table = pkg_tree_root.table;1931 pkg.table = pkg_tree_root.table;
1932 pkg_tree_root.table = .{};1932 pkg_tree_root.table = .{};
1933 }1933 }
...@@ -1980,7 +1980,7 @@ fn buildOutputType(...@@ -1980,7 +1980,7 @@ fn buildOutputType(
1980 if (arg_mode == .run) {1980 if (arg_mode == .run) {
1981 break :l global_cache_directory;1981 break :l global_cache_directory;
1982 }1982 }
1983 if (root_pkg) |pkg| {1983 if (main_pkg) |pkg| {
1984 const cache_dir_path = try pkg.root_src_directory.join(arena, &[_][]const u8{"zig-cache"});1984 const cache_dir_path = try pkg.root_src_directory.join(arena, &[_][]const u8{"zig-cache"});
1985 const dir = try pkg.root_src_directory.handle.makeOpenPath("zig-cache", .{});1985 const dir = try pkg.root_src_directory.handle.makeOpenPath("zig-cache", .{});
1986 cleanup_local_cache_dir = dir;1986 cleanup_local_cache_dir = dir;
...@@ -2018,7 +2018,7 @@ fn buildOutputType(...@@ -2018,7 +2018,7 @@ fn buildOutputType(
2018 .dynamic_linker = target_info.dynamic_linker.get(),2018 .dynamic_linker = target_info.dynamic_linker.get(),
2019 .sysroot = sysroot,2019 .sysroot = sysroot,
2020 .output_mode = output_mode,2020 .output_mode = output_mode,
2021 .root_pkg = root_pkg,2021 .main_pkg = main_pkg,
2022 .emit_bin = emit_bin_loc,2022 .emit_bin = emit_bin_loc,
2023 .emit_h = emit_h_resolved.data,2023 .emit_h = emit_h_resolved.data,
2024 .emit_asm = emit_asm_resolved.data,2024 .emit_asm = emit_asm_resolved.data,
...@@ -2823,7 +2823,7 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v...@@ -2823,7 +2823,7 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
2823 const std_special = "std" ++ fs.path.sep_str ++ "special";2823 const std_special = "std" ++ fs.path.sep_str ++ "special";
2824 const special_dir_path = try zig_lib_directory.join(arena, &[_][]const u8{std_special});2824 const special_dir_path = try zig_lib_directory.join(arena, &[_][]const u8{std_special});
28252825
2826 var root_pkg: Package = .{2826 var main_pkg: Package = .{
2827 .root_src_directory = .{2827 .root_src_directory = .{
2828 .path = special_dir_path,2828 .path = special_dir_path,
2829 .handle = zig_lib_directory.handle.openDir(std_special, .{}) catch |err| {2829 .handle = zig_lib_directory.handle.openDir(std_special, .{}) catch |err| {
...@@ -2832,7 +2832,7 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v...@@ -2832,7 +2832,7 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
2832 },2832 },
2833 .root_src_path = "build_runner.zig",2833 .root_src_path = "build_runner.zig",
2834 };2834 };
2835 defer root_pkg.root_src_directory.handle.close();2835 defer main_pkg.root_src_directory.handle.close();
28362836
2837 var cleanup_build_dir: ?fs.Dir = null;2837 var cleanup_build_dir: ?fs.Dir = null;
2838 defer if (cleanup_build_dir) |*dir| dir.close();2838 defer if (cleanup_build_dir) |*dir| dir.close();
...@@ -2881,7 +2881,7 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v...@@ -2881,7 +2881,7 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
2881 .root_src_directory = build_directory,2881 .root_src_directory = build_directory,
2882 .root_src_path = build_zig_basename,2882 .root_src_path = build_zig_basename,
2883 };2883 };
2884 try root_pkg.addAndAdopt(arena, "@build", &build_pkg);2884 try main_pkg.addAndAdopt(arena, "@build", &build_pkg);
28852885
2886 var global_cache_directory: Compilation.Directory = l: {2886 var global_cache_directory: Compilation.Directory = l: {
2887 const p = override_global_cache_dir orelse try introspect.resolveGlobalCacheDir(arena);2887 const p = override_global_cache_dir orelse try introspect.resolveGlobalCacheDir(arena);
...@@ -2938,7 +2938,7 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v...@@ -2938,7 +2938,7 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
2938 .is_native_abi = cross_target.isNativeAbi(),2938 .is_native_abi = cross_target.isNativeAbi(),
2939 .dynamic_linker = target_info.dynamic_linker.get(),2939 .dynamic_linker = target_info.dynamic_linker.get(),
2940 .output_mode = .Exe,2940 .output_mode = .Exe,
2941 .root_pkg = &root_pkg,2941 .main_pkg = &main_pkg,
2942 .emit_bin = emit_bin,2942 .emit_bin = emit_bin,
2943 .emit_h = null,2943 .emit_h = null,
2944 .optimize_mode = .Debug,2944 .optimize_mode = .Debug,
src/musl.zig+1-1
...@@ -197,7 +197,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -197,7 +197,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
197 .zig_lib_directory = comp.zig_lib_directory,197 .zig_lib_directory = comp.zig_lib_directory,
198 .target = comp.getTarget(),198 .target = comp.getTarget(),
199 .root_name = "c",199 .root_name = "c",
200 .root_pkg = null,200 .main_pkg = null,
201 .output_mode = .Lib,201 .output_mode = .Lib,
202 .link_mode = .Dynamic,202 .link_mode = .Dynamic,
203 .thread_pool = comp.thread_pool,203 .thread_pool = comp.thread_pool,
src/print_air.zig+4
...@@ -124,6 +124,8 @@ const Writer = struct {...@@ -124,6 +124,8 @@ const Writer = struct {
124 .bool_and,124 .bool_and,
125 .bool_or,125 .bool_or,
126 .store,126 .store,
127 .slice_elem_val,
128 .ptr_slice_elem_val,
127 => try w.writeBinOp(s, inst),129 => try w.writeBinOp(s, inst),
128130
129 .is_null,131 .is_null,
...@@ -161,6 +163,8 @@ const Writer = struct {...@@ -161,6 +163,8 @@ const Writer = struct {
161 .unwrap_errunion_err_ptr,163 .unwrap_errunion_err_ptr,
162 .wrap_errunion_payload,164 .wrap_errunion_payload,
163 .wrap_errunion_err,165 .wrap_errunion_err,
166 .slice_ptr,
167 .slice_len,
164 => try w.writeTyOp(s, inst),168 => try w.writeTyOp(s, inst),
165169
166 .block,170 .block,
src/stage1.zig+1-1
...@@ -107,7 +107,7 @@ pub const Module = extern struct {...@@ -107,7 +107,7 @@ pub const Module = extern struct {
107 test_name_prefix_ptr: [*]const u8,107 test_name_prefix_ptr: [*]const u8,
108 test_name_prefix_len: usize,108 test_name_prefix_len: usize,
109 userdata: usize,109 userdata: usize,
110 root_pkg: *Pkg,110 main_pkg: *Pkg,
111 main_progress_node: ?*std.Progress.Node,111 main_progress_node: ?*std.Progress.Node,
112 code_model: CodeModel,112 code_model: CodeModel,
113 subsystem: TargetSubsystem,113 subsystem: TargetSubsystem,
src/stage1/stage1.cpp+1-1
...@@ -126,7 +126,7 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) {...@@ -126,7 +126,7 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) {
126126
127 g->main_progress_node = stage1->main_progress_node;127 g->main_progress_node = stage1->main_progress_node;
128128
129 add_package(g, stage1->root_pkg, g->main_pkg);129 add_package(g, stage1->main_pkg, g->main_pkg);
130130
131 codegen_build_object(g);131 codegen_build_object(g);
132}132}
src/stage1/stage1.h+1-1
...@@ -176,7 +176,7 @@ struct ZigStage1 {...@@ -176,7 +176,7 @@ struct ZigStage1 {
176 size_t test_name_prefix_len;176 size_t test_name_prefix_len;
177177
178 void *userdata;178 void *userdata;
179 struct ZigStage1Pkg *root_pkg;179 struct ZigStage1Pkg *main_pkg;
180 struct Stage2ProgressNode *main_progress_node;180 struct Stage2ProgressNode *main_progress_node;
181181
182 enum CodeModel code_model;182 enum CodeModel code_model;
src/stage1/zig0.cpp+1-1
...@@ -465,7 +465,7 @@ int main(int argc, char **argv) {...@@ -465,7 +465,7 @@ int main(int argc, char **argv) {
465 stage1->verbose_llvm_cpu_features = verbose_llvm_cpu_features;465 stage1->verbose_llvm_cpu_features = verbose_llvm_cpu_features;
466 stage1->emit_o_ptr = emit_bin_path;466 stage1->emit_o_ptr = emit_bin_path;
467 stage1->emit_o_len = strlen(emit_bin_path);467 stage1->emit_o_len = strlen(emit_bin_path);
468 stage1->root_pkg = cur_pkg;468 stage1->main_pkg = cur_pkg;
469 stage1->err_color = color;469 stage1->err_color = color;
470 stage1->link_libc = link_libc;470 stage1->link_libc = link_libc;
471 stage1->link_libcpp = link_libcpp;471 stage1->link_libcpp = link_libcpp;
src/test.zig+3-3
...@@ -848,11 +848,11 @@ pub const TestContext = struct {...@@ -848,11 +848,11 @@ pub const TestContext = struct {
848 .path = local_cache_path,848 .path = local_cache_path,
849 };849 };
850850
851 var root_pkg: Package = .{851 var main_pkg: Package = .{
852 .root_src_directory = .{ .path = tmp_dir_path, .handle = tmp.dir },852 .root_src_directory = .{ .path = tmp_dir_path, .handle = tmp.dir },
853 .root_src_path = tmp_src_path,853 .root_src_path = tmp_src_path,
854 };854 };
855 defer root_pkg.table.deinit(allocator);855 defer main_pkg.table.deinit(allocator);
856856
857 const bin_name = try std.zig.binNameAlloc(arena, .{857 const bin_name = try std.zig.binNameAlloc(arena, .{
858 .root_name = "test_case",858 .root_name = "test_case",
...@@ -896,7 +896,7 @@ pub const TestContext = struct {...@@ -896,7 +896,7 @@ pub const TestContext = struct {
896 .optimize_mode = case.optimize_mode,896 .optimize_mode = case.optimize_mode,
897 .emit_bin = emit_bin,897 .emit_bin = emit_bin,
898 .emit_h = emit_h,898 .emit_h = emit_h,
899 .root_pkg = &root_pkg,899 .main_pkg = &main_pkg,
900 .keep_source_files_loaded = true,900 .keep_source_files_loaded = true,
901 .object_format = case.object_format,901 .object_format = case.object_format,
902 .is_native_os = case.target.isNativeOs(),902 .is_native_os = case.target.isNativeOs(),
src/type.zig+20-13
...@@ -525,9 +525,19 @@ pub const Type = extern union {...@@ -525,9 +525,19 @@ pub const Type = extern union {
525 const b_data = b.castTag(.error_union).?.data;525 const b_data = b.castTag(.error_union).?.data;
526 return a_data.error_set.eql(b_data.error_set) and a_data.payload.eql(b_data.payload);526 return a_data.error_set.eql(b_data.error_set) and a_data.payload.eql(b_data.payload);
527 },527 },
528 .ErrorSet => {
529 const a_is_anyerror = a.tag() == .anyerror;
530 const b_is_anyerror = b.tag() == .anyerror;
531
532 if (a_is_anyerror and b_is_anyerror) return true;
533 if (a_is_anyerror or b_is_anyerror) return false;
534
535 std.debug.panic("TODO implement Type equality comparison of {} and {}", .{
536 a.tag(), b.tag(),
537 });
538 },
528 .Opaque,539 .Opaque,
529 .Float,540 .Float,
530 .ErrorSet,
531 .BoundFn,541 .BoundFn,
532 .Frame,542 .Frame,
533 => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }),543 => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }),
...@@ -1190,6 +1200,9 @@ pub const Type = extern union {...@@ -1190,6 +1200,9 @@ pub const Type = extern union {
1190 .@"struct" => {1200 .@"struct" => {
1191 // TODO introduce lazy value mechanism1201 // TODO introduce lazy value mechanism
1192 const struct_obj = self.castTag(.@"struct").?.data;1202 const struct_obj = self.castTag(.@"struct").?.data;
1203 if (struct_obj.known_has_bits) {
1204 return true;
1205 }
1193 assert(struct_obj.status == .have_field_types or1206 assert(struct_obj.status == .have_field_types or
1194 struct_obj.status == .layout_wip or1207 struct_obj.status == .layout_wip or
1195 struct_obj.status == .have_layout);1208 struct_obj.status == .have_layout);
...@@ -1645,7 +1658,7 @@ pub const Type = extern union {...@@ -1645,7 +1658,7 @@ pub const Type = extern union {
1645 } else if (!payload.payload.hasCodeGenBits()) {1658 } else if (!payload.payload.hasCodeGenBits()) {
1646 return payload.error_set.abiSize(target);1659 return payload.error_set.abiSize(target);
1647 }1660 }
1648 @panic("TODO abiSize error union");1661 std.debug.panic("TODO abiSize error union {}", .{self});
1649 },1662 },
1650 };1663 };
1651 }1664 }
...@@ -2038,7 +2051,7 @@ pub const Type = extern union {...@@ -2038,7 +2051,7 @@ pub const Type = extern union {
2038 return ty.optionalChild(&buf).isValidVarType(is_extern);2051 return ty.optionalChild(&buf).isValidVarType(is_extern);
2039 },2052 },
2040 .Pointer, .Array, .Vector => ty = ty.elemType(),2053 .Pointer, .Array, .Vector => ty = ty.elemType(),
2041 .ErrorUnion => ty = ty.errorUnionChild(),2054 .ErrorUnion => ty = ty.errorUnionPayload(),
20422055
2043 .Fn => @panic("TODO fn isValidVarType"),2056 .Fn => @panic("TODO fn isValidVarType"),
2044 .Struct => {2057 .Struct => {
...@@ -2119,13 +2132,10 @@ pub const Type = extern union {...@@ -2119,13 +2132,10 @@ pub const Type = extern union {
2119 }2132 }
21202133
2121 /// Asserts that the type is an error union.2134 /// Asserts that the type is an error union.
2122 pub fn errorUnionChild(self: Type) Type {2135 pub fn errorUnionPayload(self: Type) Type {
2123 return switch (self.tag()) {2136 return switch (self.tag()) {
2124 .anyerror_void_error_union => Type.initTag(.anyerror),2137 .anyerror_void_error_union => Type.initTag(.void),
2125 .error_union => {2138 .error_union => self.castTag(.error_union).?.data.payload,
2126 const payload = self.castTag(.error_union).?;
2127 return payload.data.payload;
2128 },
2129 else => unreachable,2139 else => unreachable,
2130 };2140 };
2131 }2141 }
...@@ -2133,10 +2143,7 @@ pub const Type = extern union {...@@ -2133,10 +2143,7 @@ pub const Type = extern union {
2133 pub fn errorUnionSet(self: Type) Type {2143 pub fn errorUnionSet(self: Type) Type {
2134 return switch (self.tag()) {2144 return switch (self.tag()) {
2135 .anyerror_void_error_union => Type.initTag(.anyerror),2145 .anyerror_void_error_union => Type.initTag(.anyerror),
2136 .error_union => {2146 .error_union => self.castTag(.error_union).?.data.error_set,
2137 const payload = self.castTag(.error_union).?;
2138 return payload.data.error_set;
2139 },
2140 else => unreachable,2147 else => unreachable,
2141 };2148 };
2142 }2149 }
test/behavior.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
22
3comptime {3test {
4 // Tests that pass for both.4 // Tests that pass for both.
5 {}5 {}
66