authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-25 12:42:52-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-01-25 12:42:52-05:00
log0817d6b2150a00ab0d552888fc4822fced8e0f5f
tree8c2d8c965339201c1427275f61f4fb05cabb7b02
parent0866fa9d1d46f3c66a4adcaf1d863e762f874c6c
parentf037029283050aa4c5342003b10585e2f6e4a788
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10656 from ziglang/fn-ptr-type

stage2: type system treats fn ptr and body separately

41 files changed, 1986 insertions(+), 836 deletions(-)

lib/std/builtin.zig+7-1
...@@ -730,10 +730,16 @@ pub const CompilerBackend = enum(u64) {...@@ -730,10 +730,16 @@ pub const CompilerBackend = enum(u64) {
730/// therefore must be kept in sync with the compiler implementation.730/// therefore must be kept in sync with the compiler implementation.
731pub const TestFn = struct {731pub const TestFn = struct {
732 name: []const u8,732 name: []const u8,
733 func: fn () anyerror!void,733 func: testFnProto,
734 async_frame_size: ?usize,734 async_frame_size: ?usize,
735};735};
736736
737/// stage1 is *wrong*. It is not yet updated to support the new function type semantics.
738const testFnProto = switch (builtin.zig_backend) {
739 .stage1 => fn () anyerror!void, // wrong!
740 else => *const fn () anyerror!void,
741};
742
737/// This function type is used by the Zig language code generation and743/// This function type is used by the Zig language code generation and
738/// therefore must be kept in sync with the compiler implementation.744/// therefore must be kept in sync with the compiler implementation.
739pub const PanicFn = fn ([]const u8, ?*StackTrace) noreturn;745pub const PanicFn = fn ([]const u8, ?*StackTrace) noreturn;
src/AstGen.zig+321-18
...@@ -3240,7 +3240,8 @@ fn fnDecl(...@@ -3240,7 +3240,8 @@ fn fnDecl(
3240 const doc_comment_index = try astgen.docCommentAsString(fn_proto.firstToken());3240 const doc_comment_index = try astgen.docCommentAsString(fn_proto.firstToken());
32413241
3242 const has_section_or_addrspace = fn_proto.ast.section_expr != 0 or fn_proto.ast.addrspace_expr != 0;3242 const has_section_or_addrspace = fn_proto.ast.section_expr != 0 or fn_proto.ast.addrspace_expr != 0;
3243 wip_members.nextDecl(is_pub, is_export, fn_proto.ast.align_expr != 0, has_section_or_addrspace);3243 // Alignment is passed in the func instruction in this case.
3244 wip_members.nextDecl(is_pub, is_export, false, has_section_or_addrspace);
32443245
3245 var params_scope = &fn_gz.base;3246 var params_scope = &fn_gz.base;
3246 const is_var_args = is_var_args: {3247 const is_var_args = is_var_args: {
...@@ -3380,7 +3381,7 @@ fn fnDecl(...@@ -3380,7 +3381,7 @@ fn fnDecl(
3380 .param_block = block_inst,3381 .param_block = block_inst,
3381 .body_gz = null,3382 .body_gz = null,
3382 .cc = cc,3383 .cc = cc,
3383 .align_inst = .none, // passed in the per-decl data3384 .align_inst = align_inst,
3384 .lib_name = lib_name,3385 .lib_name = lib_name,
3385 .is_var_args = is_var_args,3386 .is_var_args = is_var_args,
3386 .is_inferred_error = false,3387 .is_inferred_error = false,
...@@ -3423,7 +3424,7 @@ fn fnDecl(...@@ -3423,7 +3424,7 @@ fn fnDecl(
3423 .ret_br = ret_br,3424 .ret_br = ret_br,
3424 .body_gz = &fn_gz,3425 .body_gz = &fn_gz,
3425 .cc = cc,3426 .cc = cc,
3426 .align_inst = .none, // passed in the per-decl data3427 .align_inst = align_inst,
3427 .lib_name = lib_name,3428 .lib_name = lib_name,
3428 .is_var_args = is_var_args,3429 .is_var_args = is_var_args,
3429 .is_inferred_error = is_inferred_error,3430 .is_inferred_error = is_inferred_error,
...@@ -3449,9 +3450,6 @@ fn fnDecl(...@@ -3449,9 +3450,6 @@ fn fnDecl(
3449 wip_members.appendToDecl(fn_name_str_index);3450 wip_members.appendToDecl(fn_name_str_index);
3450 wip_members.appendToDecl(block_inst);3451 wip_members.appendToDecl(block_inst);
3451 wip_members.appendToDecl(doc_comment_index);3452 wip_members.appendToDecl(doc_comment_index);
3452 if (align_inst != .none) {
3453 wip_members.appendToDecl(@enumToInt(align_inst));
3454 }
3455 if (has_section_or_addrspace) {3453 if (has_section_or_addrspace) {
3456 wip_members.appendToDecl(@enumToInt(section_inst));3454 wip_members.appendToDecl(@enumToInt(section_inst));
3457 wip_members.appendToDecl(@enumToInt(addrspace_inst));3455 wip_members.appendToDecl(@enumToInt(addrspace_inst));
...@@ -3830,7 +3828,8 @@ fn structDeclInner(...@@ -3830,7 +3828,8 @@ fn structDeclInner(
3830 .fields_len = 0,3828 .fields_len = 0,
3831 .body_len = 0,3829 .body_len = 0,
3832 .decls_len = 0,3830 .decls_len = 0,
3833 .known_has_bits = false,3831 .known_non_opv = false,
3832 .known_comptime_only = false,
3834 });3833 });
3835 return indexToRef(decl_inst);3834 return indexToRef(decl_inst);
3836 }3835 }
...@@ -3871,7 +3870,8 @@ fn structDeclInner(...@@ -3871,7 +3870,8 @@ fn structDeclInner(
3871 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size);3870 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size);
3872 defer wip_members.deinit();3871 defer wip_members.deinit();
38733872
3874 var known_has_bits = false;3873 var known_non_opv = false;
3874 var known_comptime_only = false;
3875 for (container_decl.ast.members) |member_node| {3875 for (container_decl.ast.members) |member_node| {
3876 const member = switch (try containerMember(gz, &namespace.base, &wip_members, member_node)) {3876 const member = switch (try containerMember(gz, &namespace.base, &wip_members, member_node)) {
3877 .decl => continue,3877 .decl => continue,
...@@ -3894,7 +3894,10 @@ fn structDeclInner(...@@ -3894,7 +3894,10 @@ fn structDeclInner(
3894 const doc_comment_index = try astgen.docCommentAsString(member.firstToken());3894 const doc_comment_index = try astgen.docCommentAsString(member.firstToken());
3895 wip_members.appendToField(doc_comment_index);3895 wip_members.appendToField(doc_comment_index);
38963896
3897 known_has_bits = known_has_bits or nodeImpliesRuntimeBits(tree, member.ast.type_expr);3897 known_non_opv = known_non_opv or
3898 nodeImpliesMoreThanOnePossibleValue(tree, member.ast.type_expr);
3899 known_comptime_only = known_comptime_only or
3900 nodeImpliesComptimeOnly(tree, member.ast.type_expr);
38983901
3899 const have_align = member.ast.align_expr != 0;3902 const have_align = member.ast.align_expr != 0;
3900 const have_value = member.ast.value_expr != 0;3903 const have_value = member.ast.value_expr != 0;
...@@ -3928,7 +3931,8 @@ fn structDeclInner(...@@ -3928,7 +3931,8 @@ fn structDeclInner(
3928 .body_len = @intCast(u32, body.len),3931 .body_len = @intCast(u32, body.len),
3929 .fields_len = field_count,3932 .fields_len = field_count,
3930 .decls_len = decl_count,3933 .decls_len = decl_count,
3931 .known_has_bits = known_has_bits,3934 .known_non_opv = known_non_opv,
3935 .known_comptime_only = known_comptime_only,
3932 });3936 });
39333937
3934 wip_members.finishBits(bits_per_field);3938 wip_members.finishBits(bits_per_field);
...@@ -8197,7 +8201,9 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.Ev...@@ -8197,7 +8201,9 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.Ev
8197 }8201 }
8198}8202}
81998203
8200fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {8204/// Returns `true` if it is known the type expression has more than one possible value;
8205/// `false` otherwise.
8206fn nodeImpliesMoreThanOnePossibleValue(tree: *const Ast, start_node: Ast.Node.Index) bool {
8201 const node_tags = tree.nodes.items(.tag);8207 const node_tags = tree.nodes.items(.tag);
8202 const node_datas = tree.nodes.items(.data);8208 const node_datas = tree.nodes.items(.data);
82038209
...@@ -8243,7 +8249,6 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {...@@ -8243,7 +8249,6 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {
8243 .multiline_string_literal,8249 .multiline_string_literal,
8244 .char_literal,8250 .char_literal,
8245 .unreachable_literal,8251 .unreachable_literal,
8246 .identifier,
8247 .error_set_decl,8252 .error_set_decl,
8248 .container_decl,8253 .container_decl,
8249 .container_decl_trailing,8254 .container_decl_trailing,
...@@ -8357,6 +8362,11 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {...@@ -8357,6 +8362,11 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {
8357 .builtin_call_comma,8362 .builtin_call_comma,
8358 .builtin_call_two,8363 .builtin_call_two,
8359 .builtin_call_two_comma,8364 .builtin_call_two_comma,
8365 // these are function bodies, not pointers
8366 .fn_proto_simple,
8367 .fn_proto_multi,
8368 .fn_proto_one,
8369 .fn_proto,
8360 => return false,8370 => return false,
83618371
8362 // Forward the question to the LHS sub-expression.8372 // Forward the question to the LHS sub-expression.
...@@ -8368,10 +8378,6 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {...@@ -8368,10 +8378,6 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {
8368 .unwrap_optional,8378 .unwrap_optional,
8369 => node = node_datas[node].lhs,8379 => node = node_datas[node].lhs,
83708380
8371 .fn_proto_simple,
8372 .fn_proto_multi,
8373 .fn_proto_one,
8374 .fn_proto,
8375 .ptr_type_aligned,8381 .ptr_type_aligned,
8376 .ptr_type_sentinel,8382 .ptr_type_sentinel,
8377 .ptr_type,8383 .ptr_type,
...@@ -8380,6 +8386,301 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {...@@ -8380,6 +8386,301 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {
8380 .anyframe_type,8386 .anyframe_type,
8381 .array_type_sentinel,8387 .array_type_sentinel,
8382 => return true,8388 => return true,
8389
8390 .identifier => {
8391 const main_tokens = tree.nodes.items(.main_token);
8392 const ident_bytes = tree.tokenSlice(main_tokens[node]);
8393 if (primitives.get(ident_bytes)) |primitive| switch (primitive) {
8394 .anyerror_type,
8395 .anyframe_type,
8396 .anyopaque_type,
8397 .bool_type,
8398 .c_int_type,
8399 .c_long_type,
8400 .c_longdouble_type,
8401 .c_longlong_type,
8402 .c_short_type,
8403 .c_uint_type,
8404 .c_ulong_type,
8405 .c_ulonglong_type,
8406 .c_ushort_type,
8407 .comptime_float_type,
8408 .comptime_int_type,
8409 .f128_type,
8410 .f16_type,
8411 .f32_type,
8412 .f64_type,
8413 .i16_type,
8414 .i32_type,
8415 .i64_type,
8416 .i128_type,
8417 .i8_type,
8418 .isize_type,
8419 .type_type,
8420 .u16_type,
8421 .u32_type,
8422 .u64_type,
8423 .u128_type,
8424 .u1_type,
8425 .u8_type,
8426 .usize_type,
8427 => return true,
8428
8429 .void_type,
8430 .bool_false,
8431 .bool_true,
8432 .null_value,
8433 .undef,
8434 .noreturn_type,
8435 => return false,
8436
8437 else => unreachable, // that's all the values from `primitives`.
8438 } else {
8439 return false;
8440 }
8441 },
8442 }
8443 }
8444}
8445
8446/// Returns `true` if it is known the expression is a type that cannot be used at runtime;
8447/// `false` otherwise.
8448fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool {
8449 const node_tags = tree.nodes.items(.tag);
8450 const node_datas = tree.nodes.items(.data);
8451
8452 var node = start_node;
8453 while (true) {
8454 switch (node_tags[node]) {
8455 .root,
8456 .@"usingnamespace",
8457 .test_decl,
8458 .switch_case,
8459 .switch_case_one,
8460 .container_field_init,
8461 .container_field_align,
8462 .container_field,
8463 .asm_output,
8464 .asm_input,
8465 .global_var_decl,
8466 .local_var_decl,
8467 .simple_var_decl,
8468 .aligned_var_decl,
8469 => unreachable,
8470
8471 .@"return",
8472 .@"break",
8473 .@"continue",
8474 .bit_not,
8475 .bool_not,
8476 .@"defer",
8477 .@"errdefer",
8478 .address_of,
8479 .negation,
8480 .negation_wrap,
8481 .@"resume",
8482 .array_type,
8483 .@"suspend",
8484 .@"anytype",
8485 .fn_decl,
8486 .anyframe_literal,
8487 .integer_literal,
8488 .float_literal,
8489 .enum_literal,
8490 .string_literal,
8491 .multiline_string_literal,
8492 .char_literal,
8493 .unreachable_literal,
8494 .error_set_decl,
8495 .container_decl,
8496 .container_decl_trailing,
8497 .container_decl_two,
8498 .container_decl_two_trailing,
8499 .container_decl_arg,
8500 .container_decl_arg_trailing,
8501 .tagged_union,
8502 .tagged_union_trailing,
8503 .tagged_union_two,
8504 .tagged_union_two_trailing,
8505 .tagged_union_enum_tag,
8506 .tagged_union_enum_tag_trailing,
8507 .@"asm",
8508 .asm_simple,
8509 .add,
8510 .add_wrap,
8511 .add_sat,
8512 .array_cat,
8513 .array_mult,
8514 .assign,
8515 .assign_bit_and,
8516 .assign_bit_or,
8517 .assign_shl,
8518 .assign_shl_sat,
8519 .assign_shr,
8520 .assign_bit_xor,
8521 .assign_div,
8522 .assign_sub,
8523 .assign_sub_wrap,
8524 .assign_sub_sat,
8525 .assign_mod,
8526 .assign_add,
8527 .assign_add_wrap,
8528 .assign_add_sat,
8529 .assign_mul,
8530 .assign_mul_wrap,
8531 .assign_mul_sat,
8532 .bang_equal,
8533 .bit_and,
8534 .bit_or,
8535 .shl,
8536 .shl_sat,
8537 .shr,
8538 .bit_xor,
8539 .bool_and,
8540 .bool_or,
8541 .div,
8542 .equal_equal,
8543 .error_union,
8544 .greater_or_equal,
8545 .greater_than,
8546 .less_or_equal,
8547 .less_than,
8548 .merge_error_sets,
8549 .mod,
8550 .mul,
8551 .mul_wrap,
8552 .mul_sat,
8553 .switch_range,
8554 .field_access,
8555 .sub,
8556 .sub_wrap,
8557 .sub_sat,
8558 .slice,
8559 .slice_open,
8560 .slice_sentinel,
8561 .deref,
8562 .array_access,
8563 .error_value,
8564 .while_simple,
8565 .while_cont,
8566 .for_simple,
8567 .if_simple,
8568 .@"catch",
8569 .@"orelse",
8570 .array_init_one,
8571 .array_init_one_comma,
8572 .array_init_dot_two,
8573 .array_init_dot_two_comma,
8574 .array_init_dot,
8575 .array_init_dot_comma,
8576 .array_init,
8577 .array_init_comma,
8578 .struct_init_one,
8579 .struct_init_one_comma,
8580 .struct_init_dot_two,
8581 .struct_init_dot_two_comma,
8582 .struct_init_dot,
8583 .struct_init_dot_comma,
8584 .struct_init,
8585 .struct_init_comma,
8586 .@"while",
8587 .@"if",
8588 .@"for",
8589 .@"switch",
8590 .switch_comma,
8591 .call_one,
8592 .call_one_comma,
8593 .async_call_one,
8594 .async_call_one_comma,
8595 .call,
8596 .call_comma,
8597 .async_call,
8598 .async_call_comma,
8599 .block_two,
8600 .block_two_semicolon,
8601 .block,
8602 .block_semicolon,
8603 .builtin_call,
8604 .builtin_call_comma,
8605 .builtin_call_two,
8606 .builtin_call_two_comma,
8607 .ptr_type_aligned,
8608 .ptr_type_sentinel,
8609 .ptr_type,
8610 .ptr_type_bit_range,
8611 .optional_type,
8612 .anyframe_type,
8613 .array_type_sentinel,
8614 => return false,
8615
8616 // these are function bodies, not pointers
8617 .fn_proto_simple,
8618 .fn_proto_multi,
8619 .fn_proto_one,
8620 .fn_proto,
8621 => return true,
8622
8623 // Forward the question to the LHS sub-expression.
8624 .grouped_expression,
8625 .@"try",
8626 .@"await",
8627 .@"comptime",
8628 .@"nosuspend",
8629 .unwrap_optional,
8630 => node = node_datas[node].lhs,
8631
8632 .identifier => {
8633 const main_tokens = tree.nodes.items(.main_token);
8634 const ident_bytes = tree.tokenSlice(main_tokens[node]);
8635 if (primitives.get(ident_bytes)) |primitive| switch (primitive) {
8636 .anyerror_type,
8637 .anyframe_type,
8638 .anyopaque_type,
8639 .bool_type,
8640 .c_int_type,
8641 .c_long_type,
8642 .c_longdouble_type,
8643 .c_longlong_type,
8644 .c_short_type,
8645 .c_uint_type,
8646 .c_ulong_type,
8647 .c_ulonglong_type,
8648 .c_ushort_type,
8649 .f128_type,
8650 .f16_type,
8651 .f32_type,
8652 .f64_type,
8653 .i16_type,
8654 .i32_type,
8655 .i64_type,
8656 .i128_type,
8657 .i8_type,
8658 .isize_type,
8659 .u16_type,
8660 .u32_type,
8661 .u64_type,
8662 .u128_type,
8663 .u1_type,
8664 .u8_type,
8665 .usize_type,
8666 .void_type,
8667 .bool_false,
8668 .bool_true,
8669 .null_value,
8670 .undef,
8671 .noreturn_type,
8672 => return false,
8673
8674 .comptime_float_type,
8675 .comptime_int_type,
8676 .type_type,
8677 => return true,
8678
8679 else => unreachable, // that's all the values from `primitives`.
8680 } else {
8681 return false;
8682 }
8683 },
8383 }8684 }
8384 }8685 }
8385}8686}
...@@ -10120,7 +10421,8 @@ const GenZir = struct {...@@ -10120,7 +10421,8 @@ const GenZir = struct {
10120 fields_len: u32,10421 fields_len: u32,
10121 decls_len: u32,10422 decls_len: u32,
10122 layout: std.builtin.TypeInfo.ContainerLayout,10423 layout: std.builtin.TypeInfo.ContainerLayout,
10123 known_has_bits: bool,10424 known_non_opv: bool,
10425 known_comptime_only: bool,
10124 }) !void {10426 }) !void {
10125 const astgen = gz.astgen;10427 const astgen = gz.astgen;
10126 const gpa = astgen.gpa;10428 const gpa = astgen.gpa;
...@@ -10150,7 +10452,8 @@ const GenZir = struct {...@@ -10150,7 +10452,8 @@ const GenZir = struct {
10150 .has_body_len = args.body_len != 0,10452 .has_body_len = args.body_len != 0,
10151 .has_fields_len = args.fields_len != 0,10453 .has_fields_len = args.fields_len != 0,
10152 .has_decls_len = args.decls_len != 0,10454 .has_decls_len = args.decls_len != 0,
10153 .known_has_bits = args.known_has_bits,10455 .known_non_opv = args.known_non_opv,
10456 .known_comptime_only = args.known_comptime_only,
10154 .name_strategy = gz.anon_name_strategy,10457 .name_strategy = gz.anon_name_strategy,
10155 .layout = args.layout,10458 .layout = args.layout,
10156 }),10459 }),
src/Compilation.zig-1
...@@ -2703,7 +2703,6 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress...@@ -2703,7 +2703,6 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress
27032703
2704 const module = comp.bin_file.options.module.?;2704 const module = comp.bin_file.options.module.?;
2705 assert(decl.has_tv);2705 assert(decl.has_tv);
2706 assert(decl.ty.hasCodeGenBits());
27072706
2708 if (decl.alive) {2707 if (decl.alive) {
2709 try module.linkerUpdateDecl(decl);2708 try module.linkerUpdateDecl(decl);
src/Module.zig+141-17
...@@ -848,9 +848,11 @@ pub const Struct = struct {...@@ -848,9 +848,11 @@ pub const Struct = struct {
848 // which `have_layout` does not ensure.848 // which `have_layout` does not ensure.
849 fully_resolved,849 fully_resolved,
850 },850 },
851 /// If true, definitely nonzero size at runtime. If false, resolving the fields851 /// If true, has more than one possible value. However it may still be non-runtime type
852 /// is necessary to determine whether it has bits at runtime.852 /// if it is a comptime-only type.
853 known_has_bits: bool,853 /// If false, resolving the fields is necessary to determine whether the type has only
854 /// one possible value.
855 known_non_opv: bool,
854 requires_comptime: RequiresComptime = .unknown,856 requires_comptime: RequiresComptime = .unknown,
855857
856 pub const Fields = std.StringArrayHashMapUnmanaged(Field);858 pub const Fields = std.StringArrayHashMapUnmanaged(Field);
...@@ -898,6 +900,45 @@ pub const Struct = struct {...@@ -898,6 +900,45 @@ pub const Struct = struct {
898 };900 };
899 }901 }
900902
903 pub fn fieldSrcLoc(s: Struct, gpa: Allocator, query: FieldSrcQuery) SrcLoc {
904 @setCold(true);
905 const tree = s.owner_decl.getFileScope().getTree(gpa) catch |err| {
906 // In this case we emit a warning + a less precise source location.
907 log.warn("unable to load {s}: {s}", .{
908 s.owner_decl.getFileScope().sub_file_path, @errorName(err),
909 });
910 return s.srcLoc();
911 };
912 const node = s.owner_decl.relativeToNodeIndex(s.node_offset);
913 const node_tags = tree.nodes.items(.tag);
914 const file = s.owner_decl.getFileScope();
915 switch (node_tags[node]) {
916 .container_decl,
917 .container_decl_trailing,
918 => return queryFieldSrc(tree.*, query, file, tree.containerDecl(node)),
919 .container_decl_two, .container_decl_two_trailing => {
920 var buffer: [2]Ast.Node.Index = undefined;
921 return queryFieldSrc(tree.*, query, file, tree.containerDeclTwo(&buffer, node));
922 },
923 .container_decl_arg,
924 .container_decl_arg_trailing,
925 => return queryFieldSrc(tree.*, query, file, tree.containerDeclArg(node)),
926
927 .tagged_union,
928 .tagged_union_trailing,
929 => return queryFieldSrc(tree.*, query, file, tree.taggedUnion(node)),
930 .tagged_union_two, .tagged_union_two_trailing => {
931 var buffer: [2]Ast.Node.Index = undefined;
932 return queryFieldSrc(tree.*, query, file, tree.taggedUnionTwo(&buffer, node));
933 },
934 .tagged_union_enum_tag,
935 .tagged_union_enum_tag_trailing,
936 => return queryFieldSrc(tree.*, query, file, tree.taggedUnionEnumTag(node)),
937
938 else => unreachable,
939 }
940 }
941
901 pub fn haveFieldTypes(s: Struct) bool {942 pub fn haveFieldTypes(s: Struct) bool {
902 return switch (s.status) {943 return switch (s.status) {
903 .none,944 .none,
...@@ -1063,6 +1104,33 @@ pub const Union = struct {...@@ -1063,6 +1104,33 @@ pub const Union = struct {
1063 };1104 };
1064 }1105 }
10651106
1107 pub fn fieldSrcLoc(u: Union, gpa: Allocator, query: FieldSrcQuery) SrcLoc {
1108 @setCold(true);
1109 const tree = u.owner_decl.getFileScope().getTree(gpa) catch |err| {
1110 // In this case we emit a warning + a less precise source location.
1111 log.warn("unable to load {s}: {s}", .{
1112 u.owner_decl.getFileScope().sub_file_path, @errorName(err),
1113 });
1114 return u.srcLoc();
1115 };
1116 const node = u.owner_decl.relativeToNodeIndex(u.node_offset);
1117 const node_tags = tree.nodes.items(.tag);
1118 const file = u.owner_decl.getFileScope();
1119 switch (node_tags[node]) {
1120 .container_decl,
1121 .container_decl_trailing,
1122 => return queryFieldSrc(tree.*, query, file, tree.containerDecl(node)),
1123 .container_decl_two, .container_decl_two_trailing => {
1124 var buffer: [2]Ast.Node.Index = undefined;
1125 return queryFieldSrc(tree.*, query, file, tree.containerDeclTwo(&buffer, node));
1126 },
1127 .container_decl_arg,
1128 .container_decl_arg_trailing,
1129 => return queryFieldSrc(tree.*, query, file, tree.containerDeclArg(node)),
1130 else => unreachable,
1131 }
1132 }
1133
1066 pub fn haveFieldTypes(u: Union) bool {1134 pub fn haveFieldTypes(u: Union) bool {
1067 return switch (u.status) {1135 return switch (u.status) {
1068 .none,1136 .none,
...@@ -1080,7 +1148,7 @@ pub const Union = struct {...@@ -1080,7 +1148,7 @@ pub const Union = struct {
1080 pub fn hasAllZeroBitFieldTypes(u: Union) bool {1148 pub fn hasAllZeroBitFieldTypes(u: Union) bool {
1081 assert(u.haveFieldTypes());1149 assert(u.haveFieldTypes());
1082 for (u.fields.values()) |field| {1150 for (u.fields.values()) |field| {
1083 if (field.ty.hasCodeGenBits()) return false;1151 if (field.ty.hasRuntimeBits()) return false;
1084 }1152 }
1085 return true;1153 return true;
1086 }1154 }
...@@ -1090,7 +1158,7 @@ pub const Union = struct {...@@ -1090,7 +1158,7 @@ pub const Union = struct {
1090 var most_alignment: u32 = 0;1158 var most_alignment: u32 = 0;
1091 var most_index: usize = undefined;1159 var most_index: usize = undefined;
1092 for (u.fields.values()) |field, i| {1160 for (u.fields.values()) |field, i| {
1093 if (!field.ty.hasCodeGenBits()) continue;1161 if (!field.ty.hasRuntimeBits()) continue;
10941162
1095 const field_align = a: {1163 const field_align = a: {
1096 if (field.abi_align.tag() == .abi_align_default) {1164 if (field.abi_align.tag() == .abi_align_default) {
...@@ -1111,7 +1179,7 @@ pub const Union = struct {...@@ -1111,7 +1179,7 @@ pub const Union = struct {
1111 var max_align: u32 = 0;1179 var max_align: u32 = 0;
1112 if (have_tag) max_align = u.tag_ty.abiAlignment(target);1180 if (have_tag) max_align = u.tag_ty.abiAlignment(target);
1113 for (u.fields.values()) |field| {1181 for (u.fields.values()) |field| {
1114 if (!field.ty.hasCodeGenBits()) continue;1182 if (!field.ty.hasRuntimeBits()) continue;
11151183
1116 const field_align = a: {1184 const field_align = a: {
1117 if (field.abi_align.tag() == .abi_align_default) {1185 if (field.abi_align.tag() == .abi_align_default) {
...@@ -1164,7 +1232,7 @@ pub const Union = struct {...@@ -1164,7 +1232,7 @@ pub const Union = struct {
1164 var payload_size: u64 = 0;1232 var payload_size: u64 = 0;
1165 var payload_align: u32 = 0;1233 var payload_align: u32 = 0;
1166 for (u.fields.values()) |field, i| {1234 for (u.fields.values()) |field, i| {
1167 if (!field.ty.hasCodeGenBits()) continue;1235 if (!field.ty.hasRuntimeBits()) continue;
11681236
1169 const field_align = a: {1237 const field_align = a: {
1170 if (field.abi_align.tag() == .abi_align_default) {1238 if (field.abi_align.tag() == .abi_align_default) {
...@@ -3391,7 +3459,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {...@@ -3391,7 +3459,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
3391 .zir_index = undefined, // set below3459 .zir_index = undefined, // set below
3392 .layout = .Auto,3460 .layout = .Auto,
3393 .status = .none,3461 .status = .none,
3394 .known_has_bits = undefined,3462 .known_non_opv = undefined,
3395 .namespace = .{3463 .namespace = .{
3396 .parent = null,3464 .parent = null,
3397 .ty = struct_ty,3465 .ty = struct_ty,
...@@ -3628,7 +3696,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -3628,7 +3696,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
3628 var type_changed = true;3696 var type_changed = true;
36293697
3630 if (decl.has_tv) {3698 if (decl.has_tv) {
3631 prev_type_has_bits = decl.ty.hasCodeGenBits();3699 prev_type_has_bits = decl.ty.isFnOrHasRuntimeBits();
3632 type_changed = !decl.ty.eql(decl_tv.ty);3700 type_changed = !decl.ty.eql(decl_tv.ty);
3633 if (decl.getFunction()) |prev_func| {3701 if (decl.getFunction()) |prev_func| {
3634 prev_is_inline = prev_func.state == .inline_only;3702 prev_is_inline = prev_func.state == .inline_only;
...@@ -3648,8 +3716,9 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -3648,8 +3716,9 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
3648 decl.analysis = .complete;3716 decl.analysis = .complete;
3649 decl.generation = mod.generation;3717 decl.generation = mod.generation;
36503718
3651 const is_inline = decl_tv.ty.fnCallingConvention() == .Inline;3719 const has_runtime_bits = try sema.fnHasRuntimeBits(&block_scope, src, decl.ty);
3652 if (!is_inline and decl_tv.ty.hasCodeGenBits()) {3720
3721 if (has_runtime_bits) {
3653 // We don't fully codegen the decl until later, but we do need to reserve a global3722 // We don't fully codegen the decl until later, but we do need to reserve a global
3654 // offset table index for it. This allows us to codegen decls out of dependency3723 // offset table index for it. This allows us to codegen decls out of dependency
3655 // order, increasing how many computations can be done in parallel.3724 // order, increasing how many computations can be done in parallel.
...@@ -3662,6 +3731,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -3662,6 +3731,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
3662 mod.comp.bin_file.freeDecl(decl);3731 mod.comp.bin_file.freeDecl(decl);
3663 }3732 }
36643733
3734 const is_inline = decl.ty.fnCallingConvention() == .Inline;
3665 if (decl.is_exported) {3735 if (decl.is_exported) {
3666 const export_src = src; // TODO make this point at `export` token3736 const export_src = src; // TODO make this point at `export` token
3667 if (is_inline) {3737 if (is_inline) {
...@@ -3682,6 +3752,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -3682,6 +3752,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
36823752
3683 decl.owns_tv = false;3753 decl.owns_tv = false;
3684 var queue_linker_work = false;3754 var queue_linker_work = false;
3755 var is_extern = false;
3685 switch (decl_tv.val.tag()) {3756 switch (decl_tv.val.tag()) {
3686 .variable => {3757 .variable => {
3687 const variable = decl_tv.val.castTag(.variable).?.data;3758 const variable = decl_tv.val.castTag(.variable).?.data;
...@@ -3698,6 +3769,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -3698,6 +3769,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
3698 if (decl == owner_decl) {3769 if (decl == owner_decl) {
3699 decl.owns_tv = true;3770 decl.owns_tv = true;
3700 queue_linker_work = true;3771 queue_linker_work = true;
3772 is_extern = true;
3701 }3773 }
3702 },3774 },
37033775
...@@ -3723,7 +3795,10 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -3723,7 +3795,10 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
3723 decl.analysis = .complete;3795 decl.analysis = .complete;
3724 decl.generation = mod.generation;3796 decl.generation = mod.generation;
37253797
3726 if (queue_linker_work and decl.ty.hasCodeGenBits()) {3798 const has_runtime_bits = is_extern or
3799 (queue_linker_work and try sema.typeHasRuntimeBits(&block_scope, src, decl.ty));
3800
3801 if (has_runtime_bits) {
3727 log.debug("queue linker work for {*} ({s})", .{ decl, decl.name });3802 log.debug("queue linker work for {*} ({s})", .{ decl, decl.name });
37283803
3729 try mod.comp.bin_file.allocateDeclIndexes(decl);3804 try mod.comp.bin_file.allocateDeclIndexes(decl);
...@@ -4224,7 +4299,7 @@ pub fn clearDecl(...@@ -4224,7 +4299,7 @@ pub fn clearDecl(
4224 mod.deleteDeclExports(decl);4299 mod.deleteDeclExports(decl);
42254300
4226 if (decl.has_tv) {4301 if (decl.has_tv) {
4227 if (decl.ty.hasCodeGenBits()) {4302 if (decl.ty.isFnOrHasRuntimeBits()) {
4228 mod.comp.bin_file.freeDecl(decl);4303 mod.comp.bin_file.freeDecl(decl);
42294304
4230 // TODO instead of a union, put this memory trailing Decl objects,4305 // TODO instead of a union, put this memory trailing Decl objects,
...@@ -4277,7 +4352,7 @@ pub fn deleteUnusedDecl(mod: *Module, decl: *Decl) void {...@@ -4277,7 +4352,7 @@ pub fn deleteUnusedDecl(mod: *Module, decl: *Decl) void {
4277 switch (mod.comp.bin_file.tag) {4352 switch (mod.comp.bin_file.tag) {
4278 .c => {}, // this linker backend has already migrated to the new API4353 .c => {}, // this linker backend has already migrated to the new API
4279 else => if (decl.has_tv) {4354 else => if (decl.has_tv) {
4280 if (decl.ty.hasCodeGenBits()) {4355 if (decl.ty.isFnOrHasRuntimeBits()) {
4281 mod.comp.bin_file.freeDecl(decl);4356 mod.comp.bin_file.freeDecl(decl);
4282 }4357 }
4283 },4358 },
...@@ -4662,8 +4737,8 @@ pub fn createAnonymousDeclFromDeclNamed(...@@ -4662,8 +4737,8 @@ pub fn createAnonymousDeclFromDeclNamed(
4662 new_decl.src_line = src_decl.src_line;4737 new_decl.src_line = src_decl.src_line;
4663 new_decl.ty = typed_value.ty;4738 new_decl.ty = typed_value.ty;
4664 new_decl.val = typed_value.val;4739 new_decl.val = typed_value.val;
4665 new_decl.align_val = Value.initTag(.null_value);4740 new_decl.align_val = Value.@"null";
4666 new_decl.linksection_val = Value.initTag(.null_value);4741 new_decl.linksection_val = Value.@"null";
4667 new_decl.has_tv = true;4742 new_decl.has_tv = true;
4668 new_decl.analysis = .complete;4743 new_decl.analysis = .complete;
4669 new_decl.generation = mod.generation;4744 new_decl.generation = mod.generation;
...@@ -4674,7 +4749,7 @@ pub fn createAnonymousDeclFromDeclNamed(...@@ -4674,7 +4749,7 @@ pub fn createAnonymousDeclFromDeclNamed(
4674 // if the Decl is referenced by an instruction or another constant. Otherwise,4749 // if the Decl is referenced by an instruction or another constant. Otherwise,
4675 // the Decl will be garbage collected by the `codegen_decl` task instead of sent4750 // the Decl will be garbage collected by the `codegen_decl` task instead of sent
4676 // to the linker.4751 // to the linker.
4677 if (typed_value.ty.hasCodeGenBits()) {4752 if (typed_value.ty.isFnOrHasRuntimeBits()) {
4678 try mod.comp.bin_file.allocateDeclIndexes(new_decl);4753 try mod.comp.bin_file.allocateDeclIndexes(new_decl);
4679 try mod.comp.anon_work_queue.writeItem(.{ .codegen_decl = new_decl });4754 try mod.comp.anon_work_queue.writeItem(.{ .codegen_decl = new_decl });
4680 }4755 }
...@@ -4905,6 +4980,55 @@ pub const PeerTypeCandidateSrc = union(enum) {...@@ -4905,6 +4980,55 @@ pub const PeerTypeCandidateSrc = union(enum) {
4905 }4980 }
4906};4981};
49074982
4983const FieldSrcQuery = struct {
4984 index: usize,
4985 range: enum { name, type, value, alignment },
4986};
4987
4988fn queryFieldSrc(
4989 tree: Ast,
4990 query: FieldSrcQuery,
4991 file_scope: *File,
4992 container_decl: Ast.full.ContainerDecl,
4993) SrcLoc {
4994 const node_tags = tree.nodes.items(.tag);
4995 var field_index: usize = 0;
4996 for (container_decl.ast.members) |member_node| {
4997 const field = switch (node_tags[member_node]) {
4998 .container_field_init => tree.containerFieldInit(member_node),
4999 .container_field_align => tree.containerFieldAlign(member_node),
5000 .container_field => tree.containerField(member_node),
5001 else => continue,
5002 };
5003 if (field_index == query.index) {
5004 return switch (query.range) {
5005 .name => .{
5006 .file_scope = file_scope,
5007 .parent_decl_node = 0,
5008 .lazy = .{ .token_abs = field.ast.name_token },
5009 },
5010 .type => .{
5011 .file_scope = file_scope,
5012 .parent_decl_node = 0,
5013 .lazy = .{ .node_abs = field.ast.type_expr },
5014 },
5015 .value => .{
5016 .file_scope = file_scope,
5017 .parent_decl_node = 0,
5018 .lazy = .{ .node_abs = field.ast.value_expr },
5019 },
5020 .alignment => .{
5021 .file_scope = file_scope,
5022 .parent_decl_node = 0,
5023 .lazy = .{ .node_abs = field.ast.align_expr },
5024 },
5025 };
5026 }
5027 field_index += 1;
5028 }
5029 unreachable;
5030}
5031
4908/// Called from `performAllTheWork`, after all AstGen workers have finished,5032/// Called from `performAllTheWork`, after all AstGen workers have finished,
4909/// and before the main semantic analysis loop begins.5033/// and before the main semantic analysis loop begins.
4910pub fn processOutdatedAndDeletedDecls(mod: *Module) !void {5034pub fn processOutdatedAndDeletedDecls(mod: *Module) !void {
src/Sema.zig+590-185
...@@ -437,9 +437,10 @@ pub const Block = struct {...@@ -437,9 +437,10 @@ pub const Block = struct {
437 }437 }
438 }438 }
439439
440 pub fn startAnonDecl(block: *Block) !WipAnonDecl {440 pub fn startAnonDecl(block: *Block, src: LazySrcLoc) !WipAnonDecl {
441 return WipAnonDecl{441 return WipAnonDecl{
442 .block = block,442 .block = block,
443 .src = src,
443 .new_decl_arena = std.heap.ArenaAllocator.init(block.sema.gpa),444 .new_decl_arena = std.heap.ArenaAllocator.init(block.sema.gpa),
444 .finished = false,445 .finished = false,
445 };446 };
...@@ -447,6 +448,7 @@ pub const Block = struct {...@@ -447,6 +448,7 @@ pub const Block = struct {
447448
448 pub const WipAnonDecl = struct {449 pub const WipAnonDecl = struct {
449 block: *Block,450 block: *Block,
451 src: LazySrcLoc,
450 new_decl_arena: std.heap.ArenaAllocator,452 new_decl_arena: std.heap.ArenaAllocator,
451 finished: bool,453 finished: bool,
452454
...@@ -462,11 +464,15 @@ pub const Block = struct {...@@ -462,11 +464,15 @@ pub const Block = struct {
462 }464 }
463465
464 pub fn finish(wad: *WipAnonDecl, ty: Type, val: Value) !*Decl {466 pub fn finish(wad: *WipAnonDecl, ty: Type, val: Value) !*Decl {
465 const new_decl = try wad.block.sema.mod.createAnonymousDecl(wad.block, .{467 const sema = wad.block.sema;
468 // Do this ahead of time because `createAnonymousDecl` depends on calling
469 // `type.hasRuntimeBits()`.
470 _ = try sema.typeHasRuntimeBits(wad.block, wad.src, ty);
471 const new_decl = try sema.mod.createAnonymousDecl(wad.block, .{
466 .ty = ty,472 .ty = ty,
467 .val = val,473 .val = val,
468 });474 });
469 errdefer wad.block.sema.mod.abortAnonDecl(new_decl);475 errdefer sema.mod.abortAnonDecl(new_decl);
470 try new_decl.finalizeNewArena(&wad.new_decl_arena);476 try new_decl.finalizeNewArena(&wad.new_decl_arena);
471 wad.finished = true;477 wad.finished = true;
472 return new_decl;478 return new_decl;
...@@ -487,20 +493,23 @@ pub fn deinit(sema: *Sema) void {...@@ -487,20 +493,23 @@ pub fn deinit(sema: *Sema) void {
487/// Returns only the result from the body that is specified.493/// Returns only the result from the body that is specified.
488/// Only appropriate to call when it is determined at comptime that this body494/// Only appropriate to call when it is determined at comptime that this body
489/// has no peers.495/// has no peers.
490fn resolveBody(sema: *Sema, block: *Block, body: []const Zir.Inst.Index) CompileError!Air.Inst.Ref {496fn resolveBody(
497 sema: *Sema,
498 block: *Block,
499 body: []const Zir.Inst.Index,
500 /// This is the instruction that a break instruction within `body` can
501 /// use to return from the body.
502 body_inst: Zir.Inst.Index,
503) CompileError!Air.Inst.Ref {
491 const break_inst = try sema.analyzeBody(block, body);504 const break_inst = try sema.analyzeBody(block, body);
492 const break_data = sema.code.instructions.items(.data)[break_inst].@"break";505 const break_data = sema.code.instructions.items(.data)[break_inst].@"break";
493 // For comptime control flow, we need to detect when `analyzeBody` reports506 // For comptime control flow, we need to detect when `analyzeBody` reports
494 // that we need to break from an outer block. In such case we507 // that we need to break from an outer block. In such case we
495 // use Zig's error mechanism to send control flow up the stack until508 // use Zig's error mechanism to send control flow up the stack until
496 // we find the corresponding block to this break.509 // we find the corresponding block to this break.
497 if (block.is_comptime) {510 if (block.is_comptime and break_data.block_inst != body_inst) {
498 if (block.label) |label| {511 sema.comptime_break_inst = break_inst;
499 if (label.zir_block != break_data.block_inst) {512 return error.ComptimeBreak;
500 sema.comptime_break_inst = break_inst;
501 return error.ComptimeBreak;
502 }
503 }
504 }513 }
505 return sema.resolveInst(break_data.operand);514 return sema.resolveInst(break_data.operand);
506}515}
...@@ -1502,9 +1511,6 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -1502,9 +1511,6 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
1502 const ptr = sema.resolveInst(bin_inst.rhs);1511 const ptr = sema.resolveInst(bin_inst.rhs);
1503 const addr_space = target_util.defaultAddressSpace(sema.mod.getTarget(), .local);1512 const addr_space = target_util.defaultAddressSpace(sema.mod.getTarget(), .local);
15041513
1505 // Needed for the call to `anon_decl.finish()` below which checks `ty.hasCodeGenBits()`.
1506 _ = try sema.typeHasOnePossibleValue(block, src, pointee_ty);
1507
1508 if (Air.refToIndex(ptr)) |ptr_inst| {1514 if (Air.refToIndex(ptr)) |ptr_inst| {
1509 if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) {1515 if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) {
1510 const air_datas = sema.air_instructions.items(.data);1516 const air_datas = sema.air_instructions.items(.data);
...@@ -1535,7 +1541,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -1535,7 +1541,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
1535 const iac = ptr_val.castTag(.inferred_alloc_comptime).?;1541 const iac = ptr_val.castTag(.inferred_alloc_comptime).?;
1536 // There will be only one coerce_result_ptr because we are running at comptime.1542 // There will be only one coerce_result_ptr because we are running at comptime.
1537 // The alloc will turn into a Decl.1543 // The alloc will turn into a Decl.
1538 var anon_decl = try block.startAnonDecl();1544 var anon_decl = try block.startAnonDecl(src);
1539 defer anon_decl.deinit();1545 defer anon_decl.deinit();
1540 iac.data.decl = try anon_decl.finish(1546 iac.data.decl = try anon_decl.finish(
1541 try pointee_ty.copy(anon_decl.arena()),1547 try pointee_ty.copy(anon_decl.arena()),
...@@ -1654,7 +1660,10 @@ pub fn analyzeStructDecl(...@@ -1654,7 +1660,10 @@ pub fn analyzeStructDecl(
1654 assert(extended.opcode == .struct_decl);1660 assert(extended.opcode == .struct_decl);
1655 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);1661 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
16561662
1657 struct_obj.known_has_bits = small.known_has_bits;1663 struct_obj.known_non_opv = small.known_non_opv;
1664 if (small.known_comptime_only) {
1665 struct_obj.requires_comptime = .yes;
1666 }
16581667
1659 var extra_index: usize = extended.operand;1668 var extra_index: usize = extended.operand;
1660 extra_index += @boolToInt(small.has_src_node);1669 extra_index += @boolToInt(small.has_src_node);
...@@ -1702,7 +1711,7 @@ fn zirStructDecl(...@@ -1702,7 +1711,7 @@ fn zirStructDecl(
1702 .zir_index = inst,1711 .zir_index = inst,
1703 .layout = small.layout,1712 .layout = small.layout,
1704 .status = .none,1713 .status = .none,
1705 .known_has_bits = undefined,1714 .known_non_opv = undefined,
1706 .namespace = .{1715 .namespace = .{
1707 .parent = block.namespace,1716 .parent = block.namespace,
1708 .ty = struct_ty,1717 .ty = struct_ty,
...@@ -2528,7 +2537,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -2528,7 +2537,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
2528 const bitcast_ty_ref = air_datas[bitcast_inst].ty_op.ty;2537 const bitcast_ty_ref = air_datas[bitcast_inst].ty_op.ty;
25292538
2530 const new_decl = d: {2539 const new_decl = d: {
2531 var anon_decl = try block.startAnonDecl();2540 var anon_decl = try block.startAnonDecl(src);
2532 defer anon_decl.deinit();2541 defer anon_decl.deinit();
2533 const new_decl = try anon_decl.finish(2542 const new_decl = try anon_decl.finish(
2534 try final_elem_ty.copy(anon_decl.arena()),2543 try final_elem_ty.copy(anon_decl.arena()),
...@@ -3112,7 +3121,7 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi...@@ -3112,7 +3121,7 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi
3112 if (operand_val.tag() == .variable) {3121 if (operand_val.tag() == .variable) {
3113 return sema.failWithNeededComptime(block, src);3122 return sema.failWithNeededComptime(block, src);
3114 }3123 }
3115 var anon_decl = try block.startAnonDecl();3124 var anon_decl = try block.startAnonDecl(src);
3116 defer anon_decl.deinit();3125 defer anon_decl.deinit();
3117 iac.data.decl = try anon_decl.finish(3126 iac.data.decl = try anon_decl.finish(
3118 try operand_ty.copy(anon_decl.arena()),3127 try operand_ty.copy(anon_decl.arena()),
...@@ -3184,8 +3193,7 @@ fn addStrLit(sema: *Sema, block: *Block, zir_bytes: []const u8) CompileError!Air...@@ -3184,8 +3193,7 @@ fn addStrLit(sema: *Sema, block: *Block, zir_bytes: []const u8) CompileError!Air
3184 // after semantic analysis is complete, for example in the case of the initialization3193 // after semantic analysis is complete, for example in the case of the initialization
3185 // expression of a variable declaration. We need the memory to be in the new3194 // expression of a variable declaration. We need the memory to be in the new
3186 // anonymous Decl's arena.3195 // anonymous Decl's arena.
31873196 var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded);
3188 var anon_decl = try block.startAnonDecl();
3189 defer anon_decl.deinit();3197 defer anon_decl.deinit();
31903198
3191 const bytes = try anon_decl.arena().dupeZ(u8, zir_bytes);3199 const bytes = try anon_decl.arena().dupeZ(u8, zir_bytes);
...@@ -3508,10 +3516,13 @@ fn resolveBlockBody(...@@ -3508,10 +3516,13 @@ fn resolveBlockBody(
3508 src: LazySrcLoc,3516 src: LazySrcLoc,
3509 child_block: *Block,3517 child_block: *Block,
3510 body: []const Zir.Inst.Index,3518 body: []const Zir.Inst.Index,
3519 /// This is the instruction that a break instruction within `body` can
3520 /// use to return from the body.
3521 body_inst: Zir.Inst.Index,
3511 merges: *Block.Merges,3522 merges: *Block.Merges,
3512) CompileError!Air.Inst.Ref {3523) CompileError!Air.Inst.Ref {
3513 if (child_block.is_comptime) {3524 if (child_block.is_comptime) {
3514 return sema.resolveBody(child_block, body);3525 return sema.resolveBody(child_block, body, body_inst);
3515 } else {3526 } else {
3516 _ = try sema.analyzeBody(child_block, body);3527 _ = try sema.analyzeBody(child_block, body);
3517 return sema.analyzeBlockBody(parent_block, src, child_block, merges);3528 return sema.analyzeBlockBody(parent_block, src, child_block, merges);
...@@ -4147,7 +4158,7 @@ fn analyzeCall(...@@ -4147,7 +4158,7 @@ fn analyzeCall(
4147 const gpa = sema.gpa;4158 const gpa = sema.gpa;
41484159
4149 const is_comptime_call = block.is_comptime or modifier == .compile_time or4160 const is_comptime_call = block.is_comptime or modifier == .compile_time or
4150 func_ty_info.return_type.requiresComptime();4161 try sema.typeRequiresComptime(block, func_src, func_ty_info.return_type);
4151 const is_inline_call = is_comptime_call or modifier == .always_inline or4162 const is_inline_call = is_comptime_call or modifier == .always_inline or
4152 func_ty_info.cc == .Inline;4163 func_ty_info.cc == .Inline;
4153 const result: Air.Inst.Ref = if (is_inline_call) res: {4164 const result: Air.Inst.Ref = if (is_inline_call) res: {
...@@ -4251,7 +4262,7 @@ fn analyzeCall(...@@ -4251,7 +4262,7 @@ fn analyzeCall(
4251 const param_src = pl_tok.src();4262 const param_src = pl_tok.src();
4252 const extra = sema.code.extraData(Zir.Inst.Param, pl_tok.payload_index);4263 const extra = sema.code.extraData(Zir.Inst.Param, pl_tok.payload_index);
4253 const param_body = sema.code.extra[extra.end..][0..extra.data.body_len];4264 const param_body = sema.code.extra[extra.end..][0..extra.data.body_len];
4254 const param_ty_inst = try sema.resolveBody(&child_block, param_body);4265 const param_ty_inst = try sema.resolveBody(&child_block, param_body, inst);
4255 const param_ty = try sema.analyzeAsType(&child_block, param_src, param_ty_inst);4266 const param_ty = try sema.analyzeAsType(&child_block, param_src, param_ty_inst);
4256 const arg_src = call_src; // TODO: better source location4267 const arg_src = call_src; // TODO: better source location
4257 const casted_arg = try sema.coerce(&child_block, param_ty, uncasted_args[arg_i], arg_src);4268 const casted_arg = try sema.coerce(&child_block, param_ty, uncasted_args[arg_i], arg_src);
...@@ -4308,7 +4319,7 @@ fn analyzeCall(...@@ -4308,7 +4319,7 @@ fn analyzeCall(
4308 // on parameters, we must now do the same for the return type as we just did with4319 // on parameters, we must now do the same for the return type as we just did with
4309 // each of the parameters, resolving the return type and providing it to the child4320 // each of the parameters, resolving the return type and providing it to the child
4310 // `Sema` so that it can be used for the `ret_ptr` instruction.4321 // `Sema` so that it can be used for the `ret_ptr` instruction.
4311 const ret_ty_inst = try sema.resolveBody(&child_block, fn_info.ret_ty_body);4322 const ret_ty_inst = try sema.resolveBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst);
4312 const ret_ty_src = func_src; // TODO better source location4323 const ret_ty_src = func_src; // TODO better source location
4313 const bare_return_type = try sema.analyzeAsType(&child_block, ret_ty_src, ret_ty_inst);4324 const bare_return_type = try sema.analyzeAsType(&child_block, ret_ty_src, ret_ty_inst);
4314 // Create a fresh inferred error set type for inline/comptime calls.4325 // Create a fresh inferred error set type for inline/comptime calls.
...@@ -4576,7 +4587,7 @@ fn analyzeCall(...@@ -4576,7 +4587,7 @@ fn analyzeCall(
4576 }4587 }
4577 } else if (is_anytype) {4588 } else if (is_anytype) {
4578 const arg_ty = sema.typeOf(arg);4589 const arg_ty = sema.typeOf(arg);
4579 if (arg_ty.requiresComptime()) {4590 if (try sema.typeRequiresComptime(block, arg_src, arg_ty)) {
4580 const arg_val = try sema.resolveConstValue(block, arg_src, arg);4591 const arg_val = try sema.resolveConstValue(block, arg_src, arg);
4581 const child_arg = try child_sema.addConstant(arg_ty, arg_val);4592 const child_arg = try child_sema.addConstant(arg_ty, arg_val);
4582 child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);4593 child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
...@@ -4589,7 +4600,7 @@ fn analyzeCall(...@@ -4589,7 +4600,7 @@ fn analyzeCall(
4589 }4600 }
4590 arg_i += 1;4601 arg_i += 1;
4591 }4602 }
4592 const new_func_inst = child_sema.resolveBody(&child_block, fn_info.param_body) catch |err| {4603 const new_func_inst = child_sema.resolveBody(&child_block, fn_info.param_body, fn_info.param_body_inst) catch |err| {
4593 // TODO look up the compile error that happened here and attach a note to it4604 // TODO look up the compile error that happened here and attach a note to it
4594 // pointing here, at the generic instantiation callsite.4605 // pointing here, at the generic instantiation callsite.
4595 if (sema.owner_func) |owner_func| {4606 if (sema.owner_func) |owner_func| {
...@@ -4997,7 +5008,7 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -4997,7 +5008,7 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
49975008
4998 // TODO do we really want to create a Decl for this?5009 // TODO do we really want to create a Decl for this?
4999 // The reason we do it right now is for memory management.5010 // The reason we do it right now is for memory management.
5000 var anon_decl = try block.startAnonDecl();5011 var anon_decl = try block.startAnonDecl(src);
5001 defer anon_decl.deinit();5012 defer anon_decl.deinit();
50025013
5003 var names = Module.ErrorSet.NameMap{};5014 var names = Module.ErrorSet.NameMap{};
...@@ -5388,10 +5399,9 @@ fn zirFunc(...@@ -5388,10 +5399,9 @@ fn zirFunc(
5388 const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len];5399 const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len];
5389 extra_index += ret_ty_body.len;5400 extra_index += ret_ty_body.len;
53905401
5391 var body_inst: Zir.Inst.Index = 0;
5392 var src_locs: Zir.Inst.Func.SrcLocs = undefined;5402 var src_locs: Zir.Inst.Func.SrcLocs = undefined;
5393 if (extra.data.body_len != 0) {5403 const has_body = extra.data.body_len != 0;
5394 body_inst = inst;5404 if (has_body) {
5395 extra_index += extra.data.body_len;5405 extra_index += extra.data.body_len;
5396 src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;5406 src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
5397 }5407 }
...@@ -5404,13 +5414,14 @@ fn zirFunc(...@@ -5404,13 +5414,14 @@ fn zirFunc(
5404 return sema.funcCommon(5414 return sema.funcCommon(
5405 block,5415 block,
5406 inst_data.src_node,5416 inst_data.src_node,
5407 body_inst,5417 inst,
5408 ret_ty_body,5418 ret_ty_body,
5409 cc,5419 cc,
5410 Value.@"null",5420 Value.@"null",
5411 false,5421 false,
5412 inferred_error_set,5422 inferred_error_set,
5413 false,5423 false,
5424 has_body,
5414 src_locs,5425 src_locs,
5415 null,5426 null,
5416 );5427 );
...@@ -5420,17 +5431,17 @@ fn funcCommon(...@@ -5420,17 +5431,17 @@ fn funcCommon(
5420 sema: *Sema,5431 sema: *Sema,
5421 block: *Block,5432 block: *Block,
5422 src_node_offset: i32,5433 src_node_offset: i32,
5423 body_inst: Zir.Inst.Index,5434 func_inst: Zir.Inst.Index,
5424 ret_ty_body: []const Zir.Inst.Index,5435 ret_ty_body: []const Zir.Inst.Index,
5425 cc: std.builtin.CallingConvention,5436 cc: std.builtin.CallingConvention,
5426 align_val: Value,5437 align_val: Value,
5427 var_args: bool,5438 var_args: bool,
5428 inferred_error_set: bool,5439 inferred_error_set: bool,
5429 is_extern: bool,5440 is_extern: bool,
5441 has_body: bool,
5430 src_locs: Zir.Inst.Func.SrcLocs,5442 src_locs: Zir.Inst.Func.SrcLocs,
5431 opt_lib_name: ?[]const u8,5443 opt_lib_name: ?[]const u8,
5432) CompileError!Air.Inst.Ref {5444) CompileError!Air.Inst.Ref {
5433 const src: LazySrcLoc = .{ .node_offset = src_node_offset };
5434 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };5445 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
54355446
5436 // The return type body might be a type expression that depends on generic parameters.5447 // The return type body might be a type expression that depends on generic parameters.
...@@ -5448,7 +5459,7 @@ fn funcCommon(...@@ -5448,7 +5459,7 @@ fn funcCommon(
5448 block.params.deinit(sema.gpa);5459 block.params.deinit(sema.gpa);
5449 block.params = prev_params;5460 block.params = prev_params;
5450 }5461 }
5451 if (sema.resolveBody(block, ret_ty_body)) |ret_ty_inst| {5462 if (sema.resolveBody(block, ret_ty_body, func_inst)) |ret_ty_inst| {
5452 if (sema.analyzeAsType(block, ret_ty_src, ret_ty_inst)) |ret_ty| {5463 if (sema.analyzeAsType(block, ret_ty_src, ret_ty_inst)) |ret_ty| {
5453 break :ret_ty ret_ty;5464 break :ret_ty ret_ty;
5454 } else |err| break :err err;5465 } else |err| break :err err;
...@@ -5467,25 +5478,36 @@ fn funcCommon(...@@ -5467,25 +5478,36 @@ fn funcCommon(
5467 const mod = sema.mod;5478 const mod = sema.mod;
54685479
5469 const new_func: *Module.Fn = new_func: {5480 const new_func: *Module.Fn = new_func: {
5470 if (body_inst == 0) break :new_func undefined;5481 if (!has_body) break :new_func undefined;
5471 if (sema.comptime_args_fn_inst == body_inst) {5482 if (sema.comptime_args_fn_inst == func_inst) {
5472 const new_func = sema.preallocated_new_func.?;5483 const new_func = sema.preallocated_new_func.?;
5473 sema.preallocated_new_func = null; // take ownership5484 sema.preallocated_new_func = null; // take ownership
5474 break :new_func new_func;5485 break :new_func new_func;
5475 }5486 }
5476 break :new_func try sema.gpa.create(Module.Fn);5487 break :new_func try sema.gpa.create(Module.Fn);
5477 };5488 };
5478 errdefer if (body_inst != 0) sema.gpa.destroy(new_func);5489 errdefer if (has_body) sema.gpa.destroy(new_func);
54795490
5480 var maybe_inferred_error_set_node: ?*Module.Fn.InferredErrorSetListNode = null;5491 var maybe_inferred_error_set_node: ?*Module.Fn.InferredErrorSetListNode = null;
5481 errdefer if (maybe_inferred_error_set_node) |node| sema.gpa.destroy(node);5492 errdefer if (maybe_inferred_error_set_node) |node| sema.gpa.destroy(node);
5482 // Note: no need to errdefer since this will still be in its default state at the end of the function.5493 // Note: no need to errdefer since this will still be in its default state at the end of the function.
54835494
5495 const target = mod.getTarget();
5496
5484 const fn_ty: Type = fn_ty: {5497 const fn_ty: Type = fn_ty: {
5498 const alignment: u32 = if (align_val.tag() == .null_value) 0 else a: {
5499 const alignment = @intCast(u32, align_val.toUnsignedInt());
5500 if (alignment == target_util.defaultFunctionAlignment(target)) {
5501 break :a 0;
5502 } else {
5503 break :a alignment;
5504 }
5505 };
5506
5485 // Hot path for some common function types.5507 // Hot path for some common function types.
5486 // TODO can we eliminate some of these Type tag values? seems unnecessarily complicated.5508 // TODO can we eliminate some of these Type tag values? seems unnecessarily complicated.
5487 if (!is_generic and block.params.items.len == 0 and !var_args and5509 if (!is_generic and block.params.items.len == 0 and !var_args and
5488 align_val.tag() == .null_value and !inferred_error_set)5510 alignment == 0 and !inferred_error_set)
5489 {5511 {
5490 if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {5512 if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {
5491 break :fn_ty Type.initTag(.fn_noreturn_no_args);5513 break :fn_ty Type.initTag(.fn_noreturn_no_args);
...@@ -5507,16 +5529,15 @@ fn funcCommon(...@@ -5507,16 +5529,15 @@ fn funcCommon(
5507 const param_types = try sema.arena.alloc(Type, block.params.items.len);5529 const param_types = try sema.arena.alloc(Type, block.params.items.len);
5508 const comptime_params = try sema.arena.alloc(bool, block.params.items.len);5530 const comptime_params = try sema.arena.alloc(bool, block.params.items.len);
5509 for (block.params.items) |param, i| {5531 for (block.params.items) |param, i| {
5532 const param_src: LazySrcLoc = .{ .node_offset = src_node_offset }; // TODO better src
5510 param_types[i] = param.ty;5533 param_types[i] = param.ty;
5511 comptime_params[i] = param.is_comptime or param.ty.requiresComptime();5534 comptime_params[i] = param.is_comptime or
5535 try sema.typeRequiresComptime(block, param_src, param.ty);
5512 is_generic = is_generic or comptime_params[i] or param.ty.tag() == .generic_poison;5536 is_generic = is_generic or comptime_params[i] or param.ty.tag() == .generic_poison;
5513 }5537 }
55145538
5515 if (align_val.tag() != .null_value) {5539 is_generic = is_generic or
5516 return sema.fail(block, src, "TODO implement support for function prototypes to have alignment specified", .{});5540 try sema.typeRequiresComptime(block, ret_ty_src, bare_return_type);
5517 }
5518
5519 is_generic = is_generic or bare_return_type.requiresComptime();
55205541
5521 const return_type = if (!inferred_error_set or bare_return_type.tag() == .generic_poison)5542 const return_type = if (!inferred_error_set or bare_return_type.tag() == .generic_poison)
5522 bare_return_type5543 bare_return_type
...@@ -5537,6 +5558,7 @@ fn funcCommon(...@@ -5537,6 +5558,7 @@ fn funcCommon(
5537 .comptime_params = comptime_params.ptr,5558 .comptime_params = comptime_params.ptr,
5538 .return_type = return_type,5559 .return_type = return_type,
5539 .cc = cc,5560 .cc = cc,
5561 .alignment = alignment,
5540 .is_var_args = var_args,5562 .is_var_args = var_args,
5541 .is_generic = is_generic,5563 .is_generic = is_generic,
5542 });5564 });
...@@ -5550,7 +5572,6 @@ fn funcCommon(...@@ -5550,7 +5572,6 @@ fn funcCommon(
5550 lib_name, @errorName(err),5572 lib_name, @errorName(err),
5551 });5573 });
5552 };5574 };
5553 const target = mod.getTarget();
5554 if (target_util.is_libc_lib_name(target, lib_name)) {5575 if (target_util.is_libc_lib_name(target, lib_name)) {
5555 if (!mod.comp.bin_file.options.link_libc) {5576 if (!mod.comp.bin_file.options.link_libc) {
5556 return sema.fail(5577 return sema.fail(
...@@ -5590,26 +5611,21 @@ fn funcCommon(...@@ -5590,26 +5611,21 @@ fn funcCommon(
5590 );5611 );
5591 }5612 }
55925613
5593 if (body_inst == 0) {5614 if (!has_body) {
5594 const fn_ptr_ty = try Type.ptr(sema.arena, .{5615 return sema.addType(fn_ty);
5595 .pointee_type = fn_ty,
5596 .@"addrspace" = .generic,
5597 .mutable = false,
5598 });
5599 return sema.addType(fn_ptr_ty);
5600 }5616 }
56015617
5602 const is_inline = fn_ty.fnCallingConvention() == .Inline;5618 const is_inline = fn_ty.fnCallingConvention() == .Inline;
5603 const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .queued;5619 const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .queued;
56045620
5605 const comptime_args: ?[*]TypedValue = if (sema.comptime_args_fn_inst == body_inst) blk: {5621 const comptime_args: ?[*]TypedValue = if (sema.comptime_args_fn_inst == func_inst) blk: {
5606 break :blk if (sema.comptime_args.len == 0) null else sema.comptime_args.ptr;5622 break :blk if (sema.comptime_args.len == 0) null else sema.comptime_args.ptr;
5607 } else null;5623 } else null;
56085624
5609 const fn_payload = try sema.arena.create(Value.Payload.Function);5625 const fn_payload = try sema.arena.create(Value.Payload.Function);
5610 new_func.* = .{5626 new_func.* = .{
5611 .state = anal_state,5627 .state = anal_state,
5612 .zir_body_inst = body_inst,5628 .zir_body_inst = func_inst,
5613 .owner_decl = sema.owner_decl,5629 .owner_decl = sema.owner_decl,
5614 .comptime_args = comptime_args,5630 .comptime_args = comptime_args,
5615 .lbrace_line = src_locs.lbrace_line,5631 .lbrace_line = src_locs.lbrace_line,
...@@ -5632,7 +5648,7 @@ fn zirParam(...@@ -5632,7 +5648,7 @@ fn zirParam(
5632 sema: *Sema,5648 sema: *Sema,
5633 block: *Block,5649 block: *Block,
5634 inst: Zir.Inst.Index,5650 inst: Zir.Inst.Index,
5635 is_comptime: bool,5651 comptime_syntax: bool,
5636) CompileError!void {5652) CompileError!void {
5637 const inst_data = sema.code.instructions.items(.data)[inst].pl_tok;5653 const inst_data = sema.code.instructions.items(.data)[inst].pl_tok;
5638 const src = inst_data.src();5654 const src = inst_data.src();
...@@ -5656,7 +5672,7 @@ fn zirParam(...@@ -5656,7 +5672,7 @@ fn zirParam(
5656 block.params = prev_params;5672 block.params = prev_params;
5657 }5673 }
56585674
5659 if (sema.resolveBody(block, body)) |param_ty_inst| {5675 if (sema.resolveBody(block, body, inst)) |param_ty_inst| {
5660 if (sema.analyzeAsType(block, src, param_ty_inst)) |param_ty| {5676 if (sema.analyzeAsType(block, src, param_ty_inst)) |param_ty| {
5661 break :param_ty param_ty;5677 break :param_ty param_ty;
5662 } else |err| break :err err;5678 } else |err| break :err err;
...@@ -5669,7 +5685,7 @@ fn zirParam(...@@ -5669,7 +5685,7 @@ fn zirParam(
5669 // insert an anytype parameter.5685 // insert an anytype parameter.
5670 try block.params.append(sema.gpa, .{5686 try block.params.append(sema.gpa, .{
5671 .ty = Type.initTag(.generic_poison),5687 .ty = Type.initTag(.generic_poison),
5672 .is_comptime = is_comptime,5688 .is_comptime = comptime_syntax,
5673 });5689 });
5674 try sema.inst_map.putNoClobber(sema.gpa, inst, .generic_poison);5690 try sema.inst_map.putNoClobber(sema.gpa, inst, .generic_poison);
5675 return;5691 return;
...@@ -5677,8 +5693,10 @@ fn zirParam(...@@ -5677,8 +5693,10 @@ fn zirParam(
5677 else => |e| return e,5693 else => |e| return e,
5678 }5694 }
5679 };5695 };
5696 const is_comptime = comptime_syntax or
5697 try sema.typeRequiresComptime(block, src, param_ty);
5680 if (sema.inst_map.get(inst)) |arg| {5698 if (sema.inst_map.get(inst)) |arg| {
5681 if (is_comptime or param_ty.requiresComptime()) {5699 if (is_comptime) {
5682 // We have a comptime value for this parameter so it should be elided from the5700 // We have a comptime value for this parameter so it should be elided from the
5683 // function type of the function instruction in this block.5701 // function type of the function instruction in this block.
5684 const coerced_arg = try sema.coerce(block, param_ty, arg, src);5702 const coerced_arg = try sema.coerce(block, param_ty, arg, src);
...@@ -5692,7 +5710,7 @@ fn zirParam(...@@ -5692,7 +5710,7 @@ fn zirParam(
56925710
5693 try block.params.append(sema.gpa, .{5711 try block.params.append(sema.gpa, .{
5694 .ty = param_ty,5712 .ty = param_ty,
5695 .is_comptime = is_comptime or param_ty.requiresComptime(),5713 .is_comptime = is_comptime,
5696 });5714 });
5697 const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison));5715 const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison));
5698 try sema.inst_map.putNoClobber(sema.gpa, inst, result);5716 try sema.inst_map.putNoClobber(sema.gpa, inst, result);
...@@ -5702,9 +5720,10 @@ fn zirParamAnytype(...@@ -5702,9 +5720,10 @@ fn zirParamAnytype(
5702 sema: *Sema,5720 sema: *Sema,
5703 block: *Block,5721 block: *Block,
5704 inst: Zir.Inst.Index,5722 inst: Zir.Inst.Index,
5705 is_comptime: bool,5723 comptime_syntax: bool,
5706) CompileError!void {5724) CompileError!void {
5707 const inst_data = sema.code.instructions.items(.data)[inst].str_tok;5725 const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
5726 const src = inst_data.src();
5708 const param_name = inst_data.get(sema.code);5727 const param_name = inst_data.get(sema.code);
57095728
5710 // TODO check if param_name shadows a Decl. This only needs to be done if5729 // TODO check if param_name shadows a Decl. This only needs to be done if
...@@ -5713,7 +5732,7 @@ fn zirParamAnytype(...@@ -5713,7 +5732,7 @@ fn zirParamAnytype(
57135732
5714 if (sema.inst_map.get(inst)) |air_ref| {5733 if (sema.inst_map.get(inst)) |air_ref| {
5715 const param_ty = sema.typeOf(air_ref);5734 const param_ty = sema.typeOf(air_ref);
5716 if (is_comptime or param_ty.requiresComptime()) {5735 if (comptime_syntax or try sema.typeRequiresComptime(block, src, param_ty)) {
5717 // We have a comptime value for this parameter so it should be elided from the5736 // We have a comptime value for this parameter so it should be elided from the
5718 // function type of the function instruction in this block.5737 // function type of the function instruction in this block.
5719 return;5738 return;
...@@ -5730,7 +5749,7 @@ fn zirParamAnytype(...@@ -5730,7 +5749,7 @@ fn zirParamAnytype(
57305749
5731 try block.params.append(sema.gpa, .{5750 try block.params.append(sema.gpa, .{
5732 .ty = Type.initTag(.generic_poison),5751 .ty = Type.initTag(.generic_poison),
5733 .is_comptime = is_comptime,5752 .is_comptime = comptime_syntax,
5734 });5753 });
5735 try sema.inst_map.put(sema.gpa, inst, .generic_poison);5754 try sema.inst_map.put(sema.gpa, inst, .generic_poison);
5736}5755}
...@@ -5770,15 +5789,16 @@ fn zirPtrToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -5770,15 +5789,16 @@ fn zirPtrToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
5770 defer tracy.end();5789 defer tracy.end();
57715790
5772 const inst_data = sema.code.instructions.items(.data)[inst].un_node;5791 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
5792 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
5773 const ptr = sema.resolveInst(inst_data.operand);5793 const ptr = sema.resolveInst(inst_data.operand);
5774 const ptr_ty = sema.typeOf(ptr);5794 const ptr_ty = sema.typeOf(ptr);
5775 if (!ptr_ty.isPtrAtRuntime()) {5795 if (!ptr_ty.isPtrAtRuntime()) {
5776 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
5777 return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty});5796 return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty});
5778 }5797 }
5779 // TODO handle known-pointer-address5798 if (try sema.resolveMaybeUndefVal(block, ptr_src, ptr)) |ptr_val| {
5780 const src = inst_data.src();5799 return sema.addConstant(Type.usize, ptr_val);
5781 try sema.requireRuntimeBlock(block, src);5800 }
5801 try sema.requireRuntimeBlock(block, ptr_src);
5782 return block.addUnOp(.ptrtoint, ptr);5802 return block.addUnOp(.ptrtoint, ptr);
5783}5803}
57845804
...@@ -6802,7 +6822,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -6802,7 +6822,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
6802 // Validation above ensured these will succeed.6822 // Validation above ensured these will succeed.
6803 const item_val = sema.resolveConstValue(&child_block, .unneeded, item) catch unreachable;6823 const item_val = sema.resolveConstValue(&child_block, .unneeded, item) catch unreachable;
6804 if (operand_val.eql(item_val, operand_ty)) {6824 if (operand_val.eql(item_val, operand_ty)) {
6805 return sema.resolveBlockBody(block, src, &child_block, body, merges);6825 return sema.resolveBlockBody(block, src, &child_block, body, inst, merges);
6806 }6826 }
6807 }6827 }
6808 }6828 }
...@@ -6824,7 +6844,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -6824,7 +6844,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
6824 // Validation above ensured these will succeed.6844 // Validation above ensured these will succeed.
6825 const item_val = sema.resolveConstValue(&child_block, .unneeded, item) catch unreachable;6845 const item_val = sema.resolveConstValue(&child_block, .unneeded, item) catch unreachable;
6826 if (operand_val.eql(item_val, operand_ty)) {6846 if (operand_val.eql(item_val, operand_ty)) {
6827 return sema.resolveBlockBody(block, src, &child_block, body, merges);6847 return sema.resolveBlockBody(block, src, &child_block, body, inst, merges);
6828 }6848 }
6829 }6849 }
68306850
...@@ -6841,18 +6861,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -6841,18 +6861,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
6841 if (Value.compare(operand_val, .gte, first_tv.val, operand_ty) and6861 if (Value.compare(operand_val, .gte, first_tv.val, operand_ty) and
6842 Value.compare(operand_val, .lte, last_tv.val, operand_ty))6862 Value.compare(operand_val, .lte, last_tv.val, operand_ty))
6843 {6863 {
6844 return sema.resolveBlockBody(block, src, &child_block, body, merges);6864 return sema.resolveBlockBody(block, src, &child_block, body, inst, merges);
6845 }6865 }
6846 }6866 }
68476867
6848 extra_index += body_len;6868 extra_index += body_len;
6849 }6869 }
6850 }6870 }
6851 return sema.resolveBlockBody(block, src, &child_block, special.body, merges);6871 return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges);
6852 }6872 }
68536873
6854 if (scalar_cases_len + multi_cases_len == 0) {6874 if (scalar_cases_len + multi_cases_len == 0) {
6855 return sema.resolveBlockBody(block, src, &child_block, special.body, merges);6875 return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges);
6856 }6876 }
68576877
6858 try sema.requireRuntimeBlock(block, src);6878 try sema.requireRuntimeBlock(block, src);
...@@ -7395,7 +7415,7 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -7395,7 +7415,7 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
7395 },7415 },
7396 };7416 };
73977417
7398 var anon_decl = try block.startAnonDecl();7418 var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded);
7399 defer anon_decl.deinit();7419 defer anon_decl.deinit();
74007420
7401 const bytes_including_null = embed_file.bytes[0 .. embed_file.bytes.len + 1];7421 const bytes_including_null = embed_file.bytes[0 .. embed_file.bytes.len + 1];
...@@ -7659,7 +7679,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -7659,7 +7679,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
7659 const is_pointer = lhs_ty.zigTypeTag() == .Pointer;7679 const is_pointer = lhs_ty.zigTypeTag() == .Pointer;
7660 const lhs_sub_val = if (is_pointer) (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? else lhs_val;7680 const lhs_sub_val = if (is_pointer) (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? else lhs_val;
7661 const rhs_sub_val = if (is_pointer) (try sema.pointerDeref(block, rhs_src, rhs_val, rhs_ty)).? else rhs_val;7681 const rhs_sub_val = if (is_pointer) (try sema.pointerDeref(block, rhs_src, rhs_val, rhs_ty)).? else rhs_val;
7662 var anon_decl = try block.startAnonDecl();7682 var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded);
7663 defer anon_decl.deinit();7683 defer anon_decl.deinit();
76647684
7665 const buf = try anon_decl.arena().alloc(Value, final_len_including_sent);7685 const buf = try anon_decl.arena().alloc(Value, final_len_including_sent);
...@@ -7743,7 +7763,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -7743,7 +7763,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
77437763
7744 const lhs_sub_val = if (lhs_ty.zigTypeTag() == .Pointer) (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? else lhs_val;7764 const lhs_sub_val = if (lhs_ty.zigTypeTag() == .Pointer) (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? else lhs_val;
77457765
7746 var anon_decl = try block.startAnonDecl();7766 var anon_decl = try block.startAnonDecl(src);
7747 defer anon_decl.deinit();7767 defer anon_decl.deinit();
77487768
7749 const final_ty = if (mulinfo.sentinel) |sent|7769 const final_ty = if (mulinfo.sentinel) |sent|
...@@ -9357,7 +9377,7 @@ fn zirBuiltinSrc(...@@ -9357,7 +9377,7 @@ fn zirBuiltinSrc(
9357 const func = sema.func orelse return sema.fail(block, src, "@src outside function", .{});9377 const func = sema.func orelse return sema.fail(block, src, "@src outside function", .{});
93589378
9359 const func_name_val = blk: {9379 const func_name_val = blk: {
9360 var anon_decl = try block.startAnonDecl();9380 var anon_decl = try block.startAnonDecl(src);
9361 defer anon_decl.deinit();9381 defer anon_decl.deinit();
9362 const name = std.mem.span(func.owner_decl.name);9382 const name = std.mem.span(func.owner_decl.name);
9363 const bytes = try anon_decl.arena().dupe(u8, name[0 .. name.len + 1]);9383 const bytes = try anon_decl.arena().dupe(u8, name[0 .. name.len + 1]);
...@@ -9369,7 +9389,7 @@ fn zirBuiltinSrc(...@@ -9369,7 +9389,7 @@ fn zirBuiltinSrc(
9369 };9389 };
93709390
9371 const file_name_val = blk: {9391 const file_name_val = blk: {
9372 var anon_decl = try block.startAnonDecl();9392 var anon_decl = try block.startAnonDecl(src);
9373 defer anon_decl.deinit();9393 defer anon_decl.deinit();
9374 const name = try func.owner_decl.getFileScope().fullPathZ(anon_decl.arena());9394 const name = try func.owner_decl.getFileScope().fullPathZ(anon_decl.arena());
9375 const new_decl = try anon_decl.finish(9395 const new_decl = try anon_decl.finish(
...@@ -9619,7 +9639,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -9619,7 +9639,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
96199639
9620 const is_exhaustive = if (ty.isNonexhaustiveEnum()) Value.@"false" else Value.@"true";9640 const is_exhaustive = if (ty.isNonexhaustiveEnum()) Value.@"false" else Value.@"true";
96219641
9622 var fields_anon_decl = try block.startAnonDecl();9642 var fields_anon_decl = try block.startAnonDecl(src);
9623 defer fields_anon_decl.deinit();9643 defer fields_anon_decl.deinit();
96249644
9625 const enum_field_ty = t: {9645 const enum_field_ty = t: {
...@@ -9650,7 +9670,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -9650,7 +9670,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
96509670
9651 const name = enum_fields.keys()[i];9671 const name = enum_fields.keys()[i];
9652 const name_val = v: {9672 const name_val = v: {
9653 var anon_decl = try block.startAnonDecl();9673 var anon_decl = try block.startAnonDecl(src);
9654 defer anon_decl.deinit();9674 defer anon_decl.deinit();
9655 const bytes = try anon_decl.arena().dupeZ(u8, name);9675 const bytes = try anon_decl.arena().dupeZ(u8, name);
9656 const new_decl = try anon_decl.finish(9676 const new_decl = try anon_decl.finish(
...@@ -9715,7 +9735,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -9715,7 +9735,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
9715 .Union => {9735 .Union => {
9716 // TODO: look into memoizing this result.9736 // TODO: look into memoizing this result.
97179737
9718 var fields_anon_decl = try block.startAnonDecl();9738 var fields_anon_decl = try block.startAnonDecl(src);
9719 defer fields_anon_decl.deinit();9739 defer fields_anon_decl.deinit();
97209740
9721 const union_field_ty = t: {9741 const union_field_ty = t: {
...@@ -9739,7 +9759,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -9739,7 +9759,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
9739 const field = union_fields.values()[i];9759 const field = union_fields.values()[i];
9740 const name = union_fields.keys()[i];9760 const name = union_fields.keys()[i];
9741 const name_val = v: {9761 const name_val = v: {
9742 var anon_decl = try block.startAnonDecl();9762 var anon_decl = try block.startAnonDecl(src);
9743 defer anon_decl.deinit();9763 defer anon_decl.deinit();
9744 const bytes = try anon_decl.arena().dupeZ(u8, name);9764 const bytes = try anon_decl.arena().dupeZ(u8, name);
9745 const new_decl = try anon_decl.finish(9765 const new_decl = try anon_decl.finish(
...@@ -9810,7 +9830,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -9810,7 +9830,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
9810 .Opaque => {9830 .Opaque => {
9811 // TODO: look into memoizing this result.9831 // TODO: look into memoizing this result.
98129832
9813 var fields_anon_decl = try block.startAnonDecl();9833 var fields_anon_decl = try block.startAnonDecl(src);
9814 defer fields_anon_decl.deinit();9834 defer fields_anon_decl.deinit();
98159835
9816 const opaque_ty = try sema.resolveTypeFields(block, src, ty);9836 const opaque_ty = try sema.resolveTypeFields(block, src, ty);
...@@ -9848,7 +9868,7 @@ fn typeInfoDecls(...@@ -9848,7 +9868,7 @@ fn typeInfoDecls(
9848 const decls_len = namespace.decls.count();9868 const decls_len = namespace.decls.count();
9849 if (decls_len == 0) return Value.initTag(.empty_array);9869 if (decls_len == 0) return Value.initTag(.empty_array);
98509870
9851 var decls_anon_decl = try block.startAnonDecl();9871 var decls_anon_decl = try block.startAnonDecl(src);
9852 defer decls_anon_decl.deinit();9872 defer decls_anon_decl.deinit();
98539873
9854 const declaration_ty = t: {9874 const declaration_ty = t: {
...@@ -9869,7 +9889,7 @@ fn typeInfoDecls(...@@ -9869,7 +9889,7 @@ fn typeInfoDecls(
9869 const decl = namespace.decls.values()[i];9889 const decl = namespace.decls.values()[i];
9870 const name = namespace.decls.keys()[i];9890 const name = namespace.decls.keys()[i];
9871 const name_val = v: {9891 const name_val = v: {
9872 var anon_decl = try block.startAnonDecl();9892 var anon_decl = try block.startAnonDecl(src);
9873 defer anon_decl.deinit();9893 defer anon_decl.deinit();
9874 const bytes = try anon_decl.arena().dupeZ(u8, name);9894 const bytes = try anon_decl.arena().dupeZ(u8, name);
9875 const new_decl = try anon_decl.finish(9895 const new_decl = try anon_decl.finish(
...@@ -10031,7 +10051,7 @@ fn zirBoolBr(...@@ -10031,7 +10051,7 @@ fn zirBoolBr(
10031 // comptime-known left-hand side. No need for a block here; the result10051 // comptime-known left-hand side. No need for a block here; the result
10032 // is simply the rhs expression. Here we rely on there only being 110052 // is simply the rhs expression. Here we rely on there only being 1
10033 // break instruction (`break_inline`).10053 // break instruction (`break_inline`).
10034 return sema.resolveBody(parent_block, body);10054 return sema.resolveBody(parent_block, body, inst);
10035 }10055 }
1003610056
10037 const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);10057 const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
...@@ -10061,7 +10081,7 @@ fn zirBoolBr(...@@ -10061,7 +10081,7 @@ fn zirBoolBr(
10061 const lhs_result: Air.Inst.Ref = if (is_bool_or) .bool_true else .bool_false;10081 const lhs_result: Air.Inst.Ref = if (is_bool_or) .bool_true else .bool_false;
10062 _ = try lhs_block.addBr(block_inst, lhs_result);10082 _ = try lhs_block.addBr(block_inst, lhs_result);
1006310083
10064 const rhs_result = try sema.resolveBody(rhs_block, body);10084 const rhs_result = try sema.resolveBody(rhs_block, body, inst);
10065 _ = try rhs_block.addBr(block_inst, rhs_result);10085 _ = try rhs_block.addBr(block_inst, rhs_result);
1006610086
10067 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +10087 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +
...@@ -10654,7 +10674,7 @@ fn zirArrayInit(...@@ -10654,7 +10674,7 @@ fn zirArrayInit(
10654 } else null;10674 } else null;
1065510675
10656 const runtime_src = opt_runtime_src orelse {10676 const runtime_src = opt_runtime_src orelse {
10657 var anon_decl = try block.startAnonDecl();10677 var anon_decl = try block.startAnonDecl(src);
10658 defer anon_decl.deinit();10678 defer anon_decl.deinit();
1065910679
10660 const elem_vals = try anon_decl.arena().alloc(Value, resolved_args.len);10680 const elem_vals = try anon_decl.arena().alloc(Value, resolved_args.len);
...@@ -10740,7 +10760,7 @@ fn zirArrayInitAnon(...@@ -10740,7 +10760,7 @@ fn zirArrayInitAnon(
10740 const tuple_val = try Value.Tag.@"struct".create(sema.arena, values);10760 const tuple_val = try Value.Tag.@"struct".create(sema.arena, values);
10741 if (!is_ref) return sema.addConstant(tuple_ty, tuple_val);10761 if (!is_ref) return sema.addConstant(tuple_ty, tuple_val);
1074210762
10743 var anon_decl = try block.startAnonDecl();10763 var anon_decl = try block.startAnonDecl(src);
10744 defer anon_decl.deinit();10764 defer anon_decl.deinit();
10745 const decl = try anon_decl.finish(10765 const decl = try anon_decl.finish(
10746 try tuple_ty.copy(anon_decl.arena()),10766 try tuple_ty.copy(anon_decl.arena()),
...@@ -11032,7 +11052,7 @@ fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -11032,7 +11052,7 @@ fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
11032 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };11052 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
11033 const ty = try sema.resolveType(block, ty_src, inst_data.operand);11053 const ty = try sema.resolveType(block, ty_src, inst_data.operand);
1103411054
11035 var anon_decl = try block.startAnonDecl();11055 var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded);
11036 defer anon_decl.deinit();11056 defer anon_decl.deinit();
1103711057
11038 const bytes = try ty.nameAlloc(anon_decl.arena());11058 const bytes = try ty.nameAlloc(anon_decl.arena());
...@@ -11118,8 +11138,7 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -11118,8 +11138,7 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1111811138
11119 const type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };11139 const type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
11120 const type_res = try sema.resolveType(block, src, extra.lhs);11140 const type_res = try sema.resolveType(block, src, extra.lhs);
11121 if (type_res.zigTypeTag() != .Pointer)11141 try sema.checkPtrType(block, type_src, type_res);
11122 return sema.fail(block, type_src, "expected pointer, found '{}'", .{type_res});
11123 const ptr_align = type_res.ptrAlignment(sema.mod.getTarget());11142 const ptr_align = type_res.ptrAlignment(sema.mod.getTarget());
1112411143
11125 if (try sema.resolveDefinedValue(block, operand_src, operand_coerced)) |val| {11144 if (try sema.resolveDefinedValue(block, operand_src, operand_coerced)) |val| {
...@@ -11176,16 +11195,8 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -11176,16 +11195,8 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
11176 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);11195 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
11177 const operand = sema.resolveInst(extra.rhs);11196 const operand = sema.resolveInst(extra.rhs);
11178 const operand_ty = sema.typeOf(operand);11197 const operand_ty = sema.typeOf(operand);
11179 if (operand_ty.zigTypeTag() != .Pointer) {11198 try sema.checkPtrType(block, dest_ty_src, dest_ty);
11180 return sema.fail(block, operand_src, "expected pointer, found {s} type '{}'", .{11199 try sema.checkPtrOperand(block, operand_src, operand_ty);
11181 @tagName(operand_ty.zigTypeTag()), operand_ty,
11182 });
11183 }
11184 if (dest_ty.zigTypeTag() != .Pointer) {
11185 return sema.fail(block, dest_ty_src, "expected pointer, found {s} type '{}'", .{
11186 @tagName(dest_ty.zigTypeTag()), dest_ty,
11187 });
11188 }
11189 return sema.coerceCompatiblePtrs(block, dest_ty, operand, operand_src);11200 return sema.coerceCompatiblePtrs(block, dest_ty, operand, operand_src);
11190}11201}
1119111202
...@@ -11264,7 +11275,7 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -11264,7 +11275,7 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1126411275
11265 // TODO in addition to pointers, this instruction is supposed to work for11276 // TODO in addition to pointers, this instruction is supposed to work for
11266 // pointer-like optionals and slices.11277 // pointer-like optionals and slices.
11267 try sema.checkPtrType(block, ptr_src, ptr_ty);11278 try sema.checkPtrOperand(block, ptr_src, ptr_ty);
1126811279
11269 // TODO compile error if the result pointer is comptime known and would have an11280 // TODO compile error if the result pointer is comptime known and would have an
11270 // alignment that disagrees with the Decl's alignment.11281 // alignment that disagrees with the Decl's alignment.
...@@ -11462,6 +11473,34 @@ fn checkIntType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileEr...@@ -11462,6 +11473,34 @@ fn checkIntType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileEr
11462 }11473 }
11463}11474}
1146411475
11476fn checkPtrOperand(
11477 sema: *Sema,
11478 block: *Block,
11479 ty_src: LazySrcLoc,
11480 ty: Type,
11481) CompileError!void {
11482 switch (ty.zigTypeTag()) {
11483 .Pointer => {},
11484 .Fn => {
11485 const msg = msg: {
11486 const msg = try sema.errMsg(
11487 block,
11488 ty_src,
11489 "expected pointer, found {}",
11490 .{ty},
11491 );
11492 errdefer msg.destroy(sema.gpa);
11493
11494 try sema.errNote(block, ty_src, msg, "use '&' to obtain a function pointer", .{});
11495
11496 break :msg msg;
11497 };
11498 return sema.failWithOwnedErrorMsg(msg);
11499 },
11500 else => return sema.fail(block, ty_src, "expected pointer, found '{}'", .{ty}),
11501 }
11502}
11503
11465fn checkPtrType(11504fn checkPtrType(
11466 sema: *Sema,11505 sema: *Sema,
11467 block: *Block,11506 block: *Block,
...@@ -11470,6 +11509,22 @@ fn checkPtrType(...@@ -11470,6 +11509,22 @@ fn checkPtrType(
11470) CompileError!void {11509) CompileError!void {
11471 switch (ty.zigTypeTag()) {11510 switch (ty.zigTypeTag()) {
11472 .Pointer => {},11511 .Pointer => {},
11512 .Fn => {
11513 const msg = msg: {
11514 const msg = try sema.errMsg(
11515 block,
11516 ty_src,
11517 "expected pointer type, found '{}'",
11518 .{ty},
11519 );
11520 errdefer msg.destroy(sema.gpa);
11521
11522 try sema.errNote(block, ty_src, msg, "use '*const ' to make a function pointer type", .{});
11523
11524 break :msg msg;
11525 };
11526 return sema.failWithOwnedErrorMsg(msg);
11527 },
11473 else => return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty}),11528 else => return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty}),
11474 }11529 }
11475}11530}
...@@ -12139,20 +12194,14 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void...@@ -12139,20 +12194,14 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
12139 const dest_ptr = sema.resolveInst(extra.dest);12194 const dest_ptr = sema.resolveInst(extra.dest);
12140 const dest_ptr_ty = sema.typeOf(dest_ptr);12195 const dest_ptr_ty = sema.typeOf(dest_ptr);
1214112196
12142 if (dest_ptr_ty.zigTypeTag() != .Pointer) {12197 try sema.checkPtrOperand(block, dest_src, dest_ptr_ty);
12143 return sema.fail(block, dest_src, "expected pointer, found '{}'", .{dest_ptr_ty});
12144 }
12145 if (dest_ptr_ty.isConstPtr()) {12198 if (dest_ptr_ty.isConstPtr()) {
12146 return sema.fail(block, dest_src, "cannot store through const pointer '{}'", .{dest_ptr_ty});12199 return sema.fail(block, dest_src, "cannot store through const pointer '{}'", .{dest_ptr_ty});
12147 }12200 }
1214812201
12149 const uncasted_src_ptr = sema.resolveInst(extra.source);12202 const uncasted_src_ptr = sema.resolveInst(extra.source);
12150 const uncasted_src_ptr_ty = sema.typeOf(uncasted_src_ptr);12203 const uncasted_src_ptr_ty = sema.typeOf(uncasted_src_ptr);
12151 if (uncasted_src_ptr_ty.zigTypeTag() != .Pointer) {12204 try sema.checkPtrOperand(block, src_src, uncasted_src_ptr_ty);
12152 return sema.fail(block, src_src, "expected pointer, found '{}'", .{
12153 uncasted_src_ptr_ty,
12154 });
12155 }
12156 const src_ptr_info = uncasted_src_ptr_ty.ptrInfo().data;12205 const src_ptr_info = uncasted_src_ptr_ty.ptrInfo().data;
12157 const wanted_src_ptr_ty = try Type.ptr(sema.arena, .{12206 const wanted_src_ptr_ty = try Type.ptr(sema.arena, .{
12158 .pointee_type = dest_ptr_ty.elemType2(),12207 .pointee_type = dest_ptr_ty.elemType2(),
...@@ -12203,9 +12252,7 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void...@@ -12203,9 +12252,7 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
12203 const len_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };12252 const len_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
12204 const dest_ptr = sema.resolveInst(extra.dest);12253 const dest_ptr = sema.resolveInst(extra.dest);
12205 const dest_ptr_ty = sema.typeOf(dest_ptr);12254 const dest_ptr_ty = sema.typeOf(dest_ptr);
12206 if (dest_ptr_ty.zigTypeTag() != .Pointer) {12255 try sema.checkPtrOperand(block, dest_src, dest_ptr_ty);
12207 return sema.fail(block, dest_src, "expected pointer, found '{}'", .{dest_ptr_ty});
12208 }
12209 if (dest_ptr_ty.isConstPtr()) {12256 if (dest_ptr_ty.isConstPtr()) {
12210 return sema.fail(block, dest_src, "cannot store through const pointer '{}'", .{dest_ptr_ty});12257 return sema.fail(block, dest_src, "cannot store through const pointer '{}'", .{dest_ptr_ty});
12211 }12258 }
...@@ -12385,10 +12432,9 @@ fn zirFuncExtended(...@@ -12385,10 +12432,9 @@ fn zirFuncExtended(
12385 const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len];12432 const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len];
12386 extra_index += ret_ty_body.len;12433 extra_index += ret_ty_body.len;
1238712434
12388 var body_inst: Zir.Inst.Index = 0;
12389 var src_locs: Zir.Inst.Func.SrcLocs = undefined;12435 var src_locs: Zir.Inst.Func.SrcLocs = undefined;
12390 if (extra.data.body_len != 0) {12436 const has_body = extra.data.body_len != 0;
12391 body_inst = inst;12437 if (has_body) {
12392 extra_index += extra.data.body_len;12438 extra_index += extra.data.body_len;
12393 src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;12439 src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
12394 }12440 }
...@@ -12400,13 +12446,14 @@ fn zirFuncExtended(...@@ -12400,13 +12446,14 @@ fn zirFuncExtended(
12400 return sema.funcCommon(12446 return sema.funcCommon(
12401 block,12447 block,
12402 extra.data.src_node,12448 extra.data.src_node,
12403 body_inst,12449 inst,
12404 ret_ty_body,12450 ret_ty_body,
12405 cc,12451 cc,
12406 align_val,12452 align_val,
12407 is_var_args,12453 is_var_args,
12408 is_inferred_error,12454 is_inferred_error,
12409 is_extern,12455 is_extern,
12456 has_body,
12410 src_locs,12457 src_locs,
12411 lib_name,12458 lib_name,
12412 );12459 );
...@@ -12487,7 +12534,7 @@ fn zirPrefetch(...@@ -12487,7 +12534,7 @@ fn zirPrefetch(
12487 const opts_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };12534 const opts_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
12488 const options_ty = try sema.getBuiltinType(block, opts_src, "PrefetchOptions");12535 const options_ty = try sema.getBuiltinType(block, opts_src, "PrefetchOptions");
12489 const ptr = sema.resolveInst(extra.lhs);12536 const ptr = sema.resolveInst(extra.lhs);
12490 try sema.checkPtrType(block, ptr_src, sema.typeOf(ptr));12537 try sema.checkPtrOperand(block, ptr_src, sema.typeOf(ptr));
12491 const options = try sema.coerce(block, options_ty, sema.resolveInst(extra.rhs), opts_src);12538 const options = try sema.coerce(block, options_ty, sema.resolveInst(extra.rhs), opts_src);
1249212539
12493 const rw = try sema.fieldVal(block, opts_src, options, "rw", opts_src);12540 const rw = try sema.fieldVal(block, opts_src, options, "rw", opts_src);
...@@ -12568,12 +12615,15 @@ fn validateVarType(...@@ -12568,12 +12615,15 @@ fn validateVarType(
12568 .Type,12615 .Type,
12569 .Undefined,12616 .Undefined,
12570 .Null,12617 .Null,
12618 .Fn,
12571 => break,12619 => break,
1257212620
12573 .Pointer => {12621 .Pointer => {
12574 const elem_ty = ty.childType();12622 const elem_ty = ty.childType();
12575 if (elem_ty.zigTypeTag() == .Opaque) return;12623 switch (elem_ty.zigTypeTag()) {
12576 ty = elem_ty;12624 .Opaque, .Fn => return,
12625 else => ty = elem_ty,
12626 }
12577 },12627 },
12578 .Opaque => if (is_extern) return else break,12628 .Opaque => if (is_extern) return else break,
1257912629
...@@ -12586,9 +12636,9 @@ fn validateVarType(...@@ -12586,9 +12636,9 @@ fn validateVarType(
1258612636
12587 .ErrorUnion => ty = ty.errorUnionPayload(),12637 .ErrorUnion => ty = ty.errorUnionPayload(),
1258812638
12589 .Fn, .Struct, .Union => {12639 .Struct, .Union => {
12590 const resolved_ty = try sema.resolveTypeFields(block, src, ty);12640 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
12591 if (resolved_ty.requiresComptime()) {12641 if (try sema.typeRequiresComptime(block, src, resolved_ty)) {
12592 break;12642 break;
12593 } else {12643 } else {
12594 return;12644 return;
...@@ -12596,7 +12646,99 @@ fn validateVarType(...@@ -12596,7 +12646,99 @@ fn validateVarType(
12596 },12646 },
12597 } else unreachable; // TODO should not need else unreachable12647 } else unreachable; // TODO should not need else unreachable
1259812648
12599 return sema.fail(block, src, "variable of type '{}' must be const or comptime", .{var_ty});12649 const msg = msg: {
12650 const msg = try sema.errMsg(block, src, "variable of type '{}' must be const or comptime", .{var_ty});
12651 errdefer msg.destroy(sema.gpa);
12652
12653 try sema.explainWhyTypeIsComptime(block, src, msg, src.toSrcLoc(block.src_decl), var_ty);
12654
12655 break :msg msg;
12656 };
12657 return sema.failWithOwnedErrorMsg(msg);
12658}
12659
12660fn explainWhyTypeIsComptime(
12661 sema: *Sema,
12662 block: *Block,
12663 src: LazySrcLoc,
12664 msg: *Module.ErrorMsg,
12665 src_loc: Module.SrcLoc,
12666 ty: Type,
12667) CompileError!void {
12668 const mod = sema.mod;
12669 switch (ty.zigTypeTag()) {
12670 .Bool,
12671 .Int,
12672 .Float,
12673 .ErrorSet,
12674 .Enum,
12675 .Frame,
12676 .AnyFrame,
12677 .Void,
12678 => return,
12679
12680 .Fn => {
12681 try mod.errNoteNonLazy(src_loc, msg, "use '*const {}' for a function pointer type", .{
12682 ty,
12683 });
12684 },
12685
12686 .Type => {
12687 try mod.errNoteNonLazy(src_loc, msg, "types are not available at runtime", .{});
12688 },
12689
12690 .BoundFn,
12691 .ComptimeFloat,
12692 .ComptimeInt,
12693 .EnumLiteral,
12694 .NoReturn,
12695 .Undefined,
12696 .Null,
12697 .Opaque,
12698 .Optional,
12699 => return,
12700
12701 .Pointer, .Array, .Vector => {
12702 try sema.explainWhyTypeIsComptime(block, src, msg, src_loc, ty.elemType());
12703 },
12704
12705 .ErrorUnion => {
12706 try sema.explainWhyTypeIsComptime(block, src, msg, src_loc, ty.errorUnionPayload());
12707 },
12708
12709 .Struct => {
12710 if (ty.castTag(.@"struct")) |payload| {
12711 const struct_obj = payload.data;
12712 for (struct_obj.fields.values()) |field, i| {
12713 const field_src_loc = struct_obj.fieldSrcLoc(sema.gpa, .{
12714 .index = i,
12715 .range = .type,
12716 });
12717 if (try sema.typeRequiresComptime(block, src, field.ty)) {
12718 try mod.errNoteNonLazy(field_src_loc, msg, "struct requires comptime because of this field", .{});
12719 try sema.explainWhyTypeIsComptime(block, src, msg, field_src_loc, field.ty);
12720 }
12721 }
12722 }
12723 // TODO tuples
12724 },
12725
12726 .Union => {
12727 if (ty.cast(Type.Payload.Union)) |payload| {
12728 const union_obj = payload.data;
12729 for (union_obj.fields.values()) |field, i| {
12730 const field_src_loc = union_obj.fieldSrcLoc(sema.gpa, .{
12731 .index = i,
12732 .range = .type,
12733 });
12734 if (try sema.typeRequiresComptime(block, src, field.ty)) {
12735 try mod.errNoteNonLazy(field_src_loc, msg, "union requires comptime because of this field", .{});
12736 try sema.explainWhyTypeIsComptime(block, src, msg, field_src_loc, field.ty);
12737 }
12738 }
12739 }
12740 },
12741 }
12600}12742}
1260112743
12602pub const PanicId = enum {12744pub const PanicId = enum {
...@@ -12731,7 +12873,7 @@ fn safetyPanic(...@@ -12731,7 +12873,7 @@ fn safetyPanic(
12731 const msg_inst = msg_inst: {12873 const msg_inst = msg_inst: {
12732 // TODO instead of making a new decl for every panic in the entire compilation,12874 // TODO instead of making a new decl for every panic in the entire compilation,
12733 // introduce the concept of a reference-counted decl for these12875 // introduce the concept of a reference-counted decl for these
12734 var anon_decl = try block.startAnonDecl();12876 var anon_decl = try block.startAnonDecl(src);
12735 defer anon_decl.deinit();12877 defer anon_decl.deinit();
12736 break :msg_inst try sema.analyzeDeclRef(try anon_decl.finish(12878 break :msg_inst try sema.analyzeDeclRef(try anon_decl.finish(
12737 try Type.Tag.array_u8.create(anon_decl.arena(), msg.len),12879 try Type.Tag.array_u8.create(anon_decl.arena(), msg.len),
...@@ -12941,7 +13083,7 @@ fn fieldPtr(...@@ -12941,7 +13083,7 @@ fn fieldPtr(
12941 switch (inner_ty.zigTypeTag()) {13083 switch (inner_ty.zigTypeTag()) {
12942 .Array => {13084 .Array => {
12943 if (mem.eql(u8, field_name, "len")) {13085 if (mem.eql(u8, field_name, "len")) {
12944 var anon_decl = try block.startAnonDecl();13086 var anon_decl = try block.startAnonDecl(src);
12945 defer anon_decl.deinit();13087 defer anon_decl.deinit();
12946 return sema.analyzeDeclRef(try anon_decl.finish(13088 return sema.analyzeDeclRef(try anon_decl.finish(
12947 Type.initTag(.comptime_int),13089 Type.initTag(.comptime_int),
...@@ -12967,7 +13109,7 @@ fn fieldPtr(...@@ -12967,7 +13109,7 @@ fn fieldPtr(
12967 const slice_ptr_ty = inner_ty.slicePtrFieldType(buf);13109 const slice_ptr_ty = inner_ty.slicePtrFieldType(buf);
1296813110
12969 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {13111 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
12970 var anon_decl = try block.startAnonDecl();13112 var anon_decl = try block.startAnonDecl(src);
12971 defer anon_decl.deinit();13113 defer anon_decl.deinit();
1297213114
12973 return sema.analyzeDeclRef(try anon_decl.finish(13115 return sema.analyzeDeclRef(try anon_decl.finish(
...@@ -12986,7 +13128,7 @@ fn fieldPtr(...@@ -12986,7 +13128,7 @@ fn fieldPtr(
12986 return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr);13128 return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr);
12987 } else if (mem.eql(u8, field_name, "len")) {13129 } else if (mem.eql(u8, field_name, "len")) {
12988 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {13130 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
12989 var anon_decl = try block.startAnonDecl();13131 var anon_decl = try block.startAnonDecl(src);
12990 defer anon_decl.deinit();13132 defer anon_decl.deinit();
1299113133
12992 return sema.analyzeDeclRef(try anon_decl.finish(13134 return sema.analyzeDeclRef(try anon_decl.finish(
...@@ -13036,7 +13178,7 @@ fn fieldPtr(...@@ -13036,7 +13178,7 @@ fn fieldPtr(
13036 });13178 });
13037 } else (try sema.mod.getErrorValue(field_name)).key;13179 } else (try sema.mod.getErrorValue(field_name)).key;
1303813180
13039 var anon_decl = try block.startAnonDecl();13181 var anon_decl = try block.startAnonDecl(src);
13040 defer anon_decl.deinit();13182 defer anon_decl.deinit();
13041 return sema.analyzeDeclRef(try anon_decl.finish(13183 return sema.analyzeDeclRef(try anon_decl.finish(
13042 try child_type.copy(anon_decl.arena()),13184 try child_type.copy(anon_decl.arena()),
...@@ -13052,7 +13194,7 @@ fn fieldPtr(...@@ -13052,7 +13194,7 @@ fn fieldPtr(
13052 if (child_type.unionTagType()) |enum_ty| {13194 if (child_type.unionTagType()) |enum_ty| {
13053 if (enum_ty.enumFieldIndex(field_name)) |field_index| {13195 if (enum_ty.enumFieldIndex(field_name)) |field_index| {
13054 const field_index_u32 = @intCast(u32, field_index);13196 const field_index_u32 = @intCast(u32, field_index);
13055 var anon_decl = try block.startAnonDecl();13197 var anon_decl = try block.startAnonDecl(src);
13056 defer anon_decl.deinit();13198 defer anon_decl.deinit();
13057 return sema.analyzeDeclRef(try anon_decl.finish(13199 return sema.analyzeDeclRef(try anon_decl.finish(
13058 try enum_ty.copy(anon_decl.arena()),13200 try enum_ty.copy(anon_decl.arena()),
...@@ -13072,7 +13214,7 @@ fn fieldPtr(...@@ -13072,7 +13214,7 @@ fn fieldPtr(
13072 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);13214 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
13073 };13215 };
13074 const field_index_u32 = @intCast(u32, field_index);13216 const field_index_u32 = @intCast(u32, field_index);
13075 var anon_decl = try block.startAnonDecl();13217 var anon_decl = try block.startAnonDecl(src);
13076 defer anon_decl.deinit();13218 defer anon_decl.deinit();
13077 return sema.analyzeDeclRef(try anon_decl.finish(13219 return sema.analyzeDeclRef(try anon_decl.finish(
13078 try child_type.copy(anon_decl.arena()),13220 try child_type.copy(anon_decl.arena()),
...@@ -13328,7 +13470,7 @@ fn structFieldPtr(...@@ -13328,7 +13470,7 @@ fn structFieldPtr(
13328 var offset: u64 = 0;13470 var offset: u64 = 0;
13329 var running_bits: u16 = 0;13471 var running_bits: u16 = 0;
13330 for (struct_obj.fields.values()) |f, i| {13472 for (struct_obj.fields.values()) |f, i| {
13331 if (!f.ty.hasCodeGenBits()) continue;13473 if (!(try sema.typeHasRuntimeBits(block, field_name_src, f.ty))) continue;
1333213474
13333 const field_align = f.packedAlignment();13475 const field_align = f.packedAlignment();
13334 if (field_align == 0) {13476 if (field_align == 0) {
...@@ -13883,6 +14025,9 @@ fn coerce(...@@ -13883,6 +14025,9 @@ fn coerce(
13883 {14025 {
13884 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);14026 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
13885 }14027 }
14028
14029 // This will give an extra hint on top of what the bottom of this func would provide.
14030 try sema.checkPtrOperand(block, dest_ty_src, inst_ty);
13886 },14031 },
13887 .Int, .ComptimeInt => switch (inst_ty.zigTypeTag()) {14032 .Int, .ComptimeInt => switch (inst_ty.zigTypeTag()) {
13888 .Float, .ComptimeFloat => float: {14033 .Float, .ComptimeFloat => float: {
...@@ -14683,7 +14828,8 @@ const ComptimePtrLoadKit = struct {...@@ -14683,7 +14828,8 @@ const ComptimePtrLoadKit = struct {
14683 /// The Type of the parent Value.14828 /// The Type of the parent Value.
14684 ty: Type,14829 ty: Type,
14685 /// The starting byte offset of `val` from `root_val`.14830 /// The starting byte offset of `val` from `root_val`.
14686 byte_offset: usize,14831 /// If the type does not have a well-defined memory layout, this is null.
14832 byte_offset: ?usize,
14687 /// Whether the `root_val` could be mutated by further14833 /// Whether the `root_val` could be mutated by further
14688 /// semantic analysis and a copy must be performed.14834 /// semantic analysis and a copy must be performed.
14689 is_mutable: bool,14835 is_mutable: bool,
...@@ -14738,12 +14884,24 @@ fn beginComptimePtrLoad(...@@ -14738,12 +14884,24 @@ fn beginComptimePtrLoad(
14738 });14884 });
14739 }14885 }
14740 const elem_ty = parent.ty.childType();14886 const elem_ty = parent.ty.childType();
14741 const elem_size = elem_ty.abiSize(target);14887 const byte_offset: ?usize = bo: {
14888 if (try sema.typeRequiresComptime(block, src, elem_ty)) {
14889 break :bo null;
14890 } else {
14891 if (parent.byte_offset) |off| {
14892 try sema.resolveTypeLayout(block, src, elem_ty);
14893 const elem_size = elem_ty.abiSize(target);
14894 break :bo try sema.usizeCast(block, src, off + elem_size * elem_ptr.index);
14895 } else {
14896 break :bo null;
14897 }
14898 }
14899 };
14742 return ComptimePtrLoadKit{14900 return ComptimePtrLoadKit{
14743 .root_val = parent.root_val,14901 .root_val = parent.root_val,
14744 .val = try parent.val.elemValue(sema.arena, elem_ptr.index),14902 .val = try parent.val.elemValue(sema.arena, elem_ptr.index),
14745 .ty = elem_ty,14903 .ty = elem_ty,
14746 .byte_offset = try sema.usizeCast(block, src, parent.byte_offset + elem_size * elem_ptr.index),14904 .byte_offset = byte_offset,
14747 .is_mutable = parent.is_mutable,14905 .is_mutable = parent.is_mutable,
14748 };14906 };
14749 },14907 },
...@@ -14768,13 +14926,24 @@ fn beginComptimePtrLoad(...@@ -14768,13 +14926,24 @@ fn beginComptimePtrLoad(
14768 const field_ptr = ptr_val.castTag(.field_ptr).?.data;14926 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
14769 const parent = try beginComptimePtrLoad(sema, block, src, field_ptr.container_ptr);14927 const parent = try beginComptimePtrLoad(sema, block, src, field_ptr.container_ptr);
14770 const field_index = @intCast(u32, field_ptr.field_index);14928 const field_index = @intCast(u32, field_ptr.field_index);
14771 try sema.resolveTypeLayout(block, src, parent.ty);14929 const byte_offset: ?usize = bo: {
14772 const field_offset = parent.ty.structFieldOffset(field_index, target);14930 if (try sema.typeRequiresComptime(block, src, parent.ty)) {
14931 break :bo null;
14932 } else {
14933 if (parent.byte_offset) |off| {
14934 try sema.resolveTypeLayout(block, src, parent.ty);
14935 const field_offset = parent.ty.structFieldOffset(field_index, target);
14936 break :bo try sema.usizeCast(block, src, off + field_offset);
14937 } else {
14938 break :bo null;
14939 }
14940 }
14941 };
14773 return ComptimePtrLoadKit{14942 return ComptimePtrLoadKit{
14774 .root_val = parent.root_val,14943 .root_val = parent.root_val,
14775 .val = try parent.val.fieldValue(sema.arena, field_index),14944 .val = try parent.val.fieldValue(sema.arena, field_index),
14776 .ty = parent.ty.structFieldType(field_index),14945 .ty = parent.ty.structFieldType(field_index),
14777 .byte_offset = try sema.usizeCast(block, src, parent.byte_offset + field_offset),14946 .byte_offset = byte_offset,
14778 .is_mutable = parent.is_mutable,14947 .is_mutable = parent.is_mutable,
14779 };14948 };
14780 },14949 },
...@@ -14785,7 +14954,7 @@ fn beginComptimePtrLoad(...@@ -14785,7 +14954,7 @@ fn beginComptimePtrLoad(
14785 .root_val = parent.root_val,14954 .root_val = parent.root_val,
14786 .val = parent.val.castTag(.eu_payload).?.data,14955 .val = parent.val.castTag(.eu_payload).?.data,
14787 .ty = parent.ty.errorUnionPayload(),14956 .ty = parent.ty.errorUnionPayload(),
14788 .byte_offset = undefined,14957 .byte_offset = null,
14789 .is_mutable = parent.is_mutable,14958 .is_mutable = parent.is_mutable,
14790 };14959 };
14791 },14960 },
...@@ -14796,7 +14965,7 @@ fn beginComptimePtrLoad(...@@ -14796,7 +14965,7 @@ fn beginComptimePtrLoad(
14796 .root_val = parent.root_val,14965 .root_val = parent.root_val,
14797 .val = parent.val.castTag(.opt_payload).?.data,14966 .val = parent.val.castTag(.opt_payload).?.data,
14798 .ty = try parent.ty.optionalChildAlloc(sema.arena),14967 .ty = try parent.ty.optionalChildAlloc(sema.arena),
14799 .byte_offset = undefined,14968 .byte_offset = null,
14800 .is_mutable = parent.is_mutable,14969 .is_mutable = parent.is_mutable,
14801 };14970 };
14802 },14971 },
...@@ -15176,7 +15345,7 @@ fn analyzeRef(...@@ -15176,7 +15345,7 @@ fn analyzeRef(
15176 const operand_ty = sema.typeOf(operand);15345 const operand_ty = sema.typeOf(operand);
1517715346
15178 if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| {15347 if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| {
15179 var anon_decl = try block.startAnonDecl();15348 var anon_decl = try block.startAnonDecl(src);
15180 defer anon_decl.deinit();15349 defer anon_decl.deinit();
15181 return sema.analyzeDeclRef(try anon_decl.finish(15350 return sema.analyzeDeclRef(try anon_decl.finish(
15182 try operand_ty.copy(anon_decl.arena()),15351 try operand_ty.copy(anon_decl.arena()),
...@@ -15590,7 +15759,7 @@ fn cmpNumeric(...@@ -15590,7 +15759,7 @@ fn cmpNumeric(
15590 lhs_bits = bigint.toConst().bitCountTwosComp();15759 lhs_bits = bigint.toConst().bitCountTwosComp();
15591 break :x (zcmp != .lt);15760 break :x (zcmp != .lt);
15592 } else x: {15761 } else x: {
15593 lhs_bits = lhs_val.intBitCountTwosComp();15762 lhs_bits = lhs_val.intBitCountTwosComp(target);
15594 break :x (lhs_val.orderAgainstZero() != .lt);15763 break :x (lhs_val.orderAgainstZero() != .lt);
15595 };15764 };
15596 lhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);15765 lhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);
...@@ -15625,7 +15794,7 @@ fn cmpNumeric(...@@ -15625,7 +15794,7 @@ fn cmpNumeric(
15625 rhs_bits = bigint.toConst().bitCountTwosComp();15794 rhs_bits = bigint.toConst().bitCountTwosComp();
15626 break :x (zcmp != .lt);15795 break :x (zcmp != .lt);
15627 } else x: {15796 } else x: {
15628 rhs_bits = rhs_val.intBitCountTwosComp();15797 rhs_bits = rhs_val.intBitCountTwosComp(target);
15629 break :x (rhs_val.orderAgainstZero() != .lt);15798 break :x (rhs_val.orderAgainstZero() != .lt);
15630 };15799 };
15631 rhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);15800 rhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);
...@@ -16090,28 +16259,12 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp...@@ -16090,28 +16259,12 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp
16090 switch (ty.tag()) {16259 switch (ty.tag()) {
16091 .@"struct" => {16260 .@"struct" => {
16092 const struct_obj = ty.castTag(.@"struct").?.data;16261 const struct_obj = ty.castTag(.@"struct").?.data;
16093 switch (struct_obj.status) {16262 try sema.resolveTypeFieldsStruct(block, src, ty, struct_obj);
16094 .none => {},16263 return ty;
16095 .field_types_wip => {16264 },
16096 return sema.fail(block, src, "struct {} depends on itself", .{ty});16265 .@"union", .union_tagged => {
16097 },16266 const union_obj = ty.cast(Type.Payload.Union).?.data;
16098 .have_field_types,16267 try sema.resolveTypeFieldsUnion(block, src, ty, union_obj);
16099 .have_layout,
16100 .layout_wip,
16101 .fully_resolved_wip,
16102 .fully_resolved,
16103 => return ty,
16104 }
16105
16106 struct_obj.status = .field_types_wip;
16107 try semaStructFields(sema.mod, struct_obj);
16108
16109 if (struct_obj.fields.count() == 0) {
16110 struct_obj.status = .have_layout;
16111 } else {
16112 struct_obj.status = .have_field_types;
16113 }
16114
16115 return ty;16268 return ty;
16116 },16269 },
16117 .type_info => return sema.resolveBuiltinTypeFields(block, src, "TypeInfo"),16270 .type_info => return sema.resolveBuiltinTypeFields(block, src, "TypeInfo"),
...@@ -16126,29 +16279,63 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp...@@ -16126,29 +16279,63 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp
16126 .call_options => return sema.resolveBuiltinTypeFields(block, src, "CallOptions"),16279 .call_options => return sema.resolveBuiltinTypeFields(block, src, "CallOptions"),
16127 .prefetch_options => return sema.resolveBuiltinTypeFields(block, src, "PrefetchOptions"),16280 .prefetch_options => return sema.resolveBuiltinTypeFields(block, src, "PrefetchOptions"),
1612816281
16129 .@"union", .union_tagged => {16282 else => return ty,
16130 const union_obj = ty.cast(Type.Payload.Union).?.data;16283 }
16131 switch (union_obj.status) {16284}
16132 .none => {},
16133 .field_types_wip => {
16134 return sema.fail(block, src, "union {} depends on itself", .{ty});
16135 },
16136 .have_field_types,
16137 .have_layout,
16138 .layout_wip,
16139 .fully_resolved_wip,
16140 .fully_resolved,
16141 => return ty,
16142 }
1614316285
16144 union_obj.status = .field_types_wip;16286fn resolveTypeFieldsStruct(
16145 try semaUnionFields(sema.mod, union_obj);16287 sema: *Sema,
16146 union_obj.status = .have_field_types;16288 block: *Block,
16289 src: LazySrcLoc,
16290 ty: Type,
16291 struct_obj: *Module.Struct,
16292) CompileError!void {
16293 switch (struct_obj.status) {
16294 .none => {},
16295 .field_types_wip => {
16296 return sema.fail(block, src, "struct {} depends on itself", .{ty});
16297 },
16298 .have_field_types,
16299 .have_layout,
16300 .layout_wip,
16301 .fully_resolved_wip,
16302 .fully_resolved,
16303 => return,
16304 }
1614716305
16148 return ty;16306 struct_obj.status = .field_types_wip;
16307 try semaStructFields(sema.mod, struct_obj);
16308
16309 if (struct_obj.fields.count() == 0) {
16310 struct_obj.status = .have_layout;
16311 } else {
16312 struct_obj.status = .have_field_types;
16313 }
16314}
16315
16316fn resolveTypeFieldsUnion(
16317 sema: *Sema,
16318 block: *Block,
16319 src: LazySrcLoc,
16320 ty: Type,
16321 union_obj: *Module.Union,
16322) CompileError!void {
16323 switch (union_obj.status) {
16324 .none => {},
16325 .field_types_wip => {
16326 return sema.fail(block, src, "union {} depends on itself", .{ty});
16149 },16327 },
16150 else => return ty,16328 .have_field_types,
16329 .have_layout,
16330 .layout_wip,
16331 .fully_resolved_wip,
16332 .fully_resolved,
16333 => return,
16151 }16334 }
16335
16336 union_obj.status = .field_types_wip;
16337 try semaUnionFields(sema.mod, union_obj);
16338 union_obj.status = .have_field_types;
16152}16339}
1615316340
16154fn resolveBuiltinTypeFields(16341fn resolveBuiltinTypeFields(
...@@ -16695,6 +16882,7 @@ fn getBuiltinType(...@@ -16695,6 +16882,7 @@ fn getBuiltinType(
16695/// in `Sema` is for calling during semantic analysis, and performs field resolution16882/// in `Sema` is for calling during semantic analysis, and performs field resolution
16696/// to get the answer. The one in `Type` is for calling during codegen and asserts16883/// to get the answer. The one in `Type` is for calling during codegen and asserts
16697/// that the types are already resolved.16884/// that the types are already resolved.
16885/// TODO assert the return value matches `ty.onePossibleValue`
16698pub fn typeHasOnePossibleValue(16886pub fn typeHasOnePossibleValue(
16699 sema: *Sema,16887 sema: *Sema,
16700 block: *Block,16888 block: *Block,
...@@ -16842,7 +17030,7 @@ pub fn typeHasOnePossibleValue(...@@ -16842,7 +17030,7 @@ pub fn typeHasOnePossibleValue(
16842 },17030 },
16843 .enum_nonexhaustive => {17031 .enum_nonexhaustive => {
16844 const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty;17032 const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty;
16845 if (!tag_ty.hasCodeGenBits()) {17033 if (!(try sema.typeHasRuntimeBits(block, src, tag_ty))) {
16846 return Value.zero;17034 return Value.zero;
16847 } else {17035 } else {
16848 return null;17036 return null;
...@@ -17106,7 +17294,7 @@ fn analyzeComptimeAlloc(...@@ -17106,7 +17294,7 @@ fn analyzeComptimeAlloc(
17106 .@"align" = alignment,17294 .@"align" = alignment,
17107 });17295 });
1710817296
17109 var anon_decl = try block.startAnonDecl();17297 var anon_decl = try block.startAnonDecl(src);
17110 defer anon_decl.deinit();17298 defer anon_decl.deinit();
1711117299
17112 const align_val = if (alignment == 0)17300 const align_val = if (alignment == 0)
...@@ -17295,3 +17483,220 @@ fn typePtrOrOptionalPtrTy(...@@ -17295,3 +17483,220 @@ fn typePtrOrOptionalPtrTy(
17295 else => return null,17483 else => return null,
17296 }17484 }
17297}17485}
17486
17487/// `generic_poison` will return false.
17488/// This function returns false negatives when structs and unions are having their
17489/// field types resolved.
17490/// TODO assert the return value matches `ty.comptimeOnly`
17491fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
17492 return switch (ty.tag()) {
17493 .u1,
17494 .u8,
17495 .i8,
17496 .u16,
17497 .i16,
17498 .u32,
17499 .i32,
17500 .u64,
17501 .i64,
17502 .u128,
17503 .i128,
17504 .usize,
17505 .isize,
17506 .c_short,
17507 .c_ushort,
17508 .c_int,
17509 .c_uint,
17510 .c_long,
17511 .c_ulong,
17512 .c_longlong,
17513 .c_ulonglong,
17514 .c_longdouble,
17515 .f16,
17516 .f32,
17517 .f64,
17518 .f128,
17519 .anyopaque,
17520 .bool,
17521 .void,
17522 .anyerror,
17523 .noreturn,
17524 .@"anyframe",
17525 .@"null",
17526 .@"undefined",
17527 .atomic_order,
17528 .atomic_rmw_op,
17529 .calling_convention,
17530 .address_space,
17531 .float_mode,
17532 .reduce_op,
17533 .call_options,
17534 .prefetch_options,
17535 .export_options,
17536 .extern_options,
17537 .manyptr_u8,
17538 .manyptr_const_u8,
17539 .manyptr_const_u8_sentinel_0,
17540 .const_slice_u8,
17541 .const_slice_u8_sentinel_0,
17542 .anyerror_void_error_union,
17543 .empty_struct_literal,
17544 .empty_struct,
17545 .error_set,
17546 .error_set_single,
17547 .error_set_inferred,
17548 .error_set_merged,
17549 .@"opaque",
17550 .generic_poison,
17551 .array_u8,
17552 .array_u8_sentinel_0,
17553 .int_signed,
17554 .int_unsigned,
17555 .enum_simple,
17556 => false,
17557
17558 .single_const_pointer_to_comptime_int,
17559 .type,
17560 .comptime_int,
17561 .comptime_float,
17562 .enum_literal,
17563 .type_info,
17564 // These are function bodies, not function pointers.
17565 .fn_noreturn_no_args,
17566 .fn_void_no_args,
17567 .fn_naked_noreturn_no_args,
17568 .fn_ccc_void_no_args,
17569 .function,
17570 => true,
17571
17572 .var_args_param => unreachable,
17573 .inferred_alloc_mut => unreachable,
17574 .inferred_alloc_const => unreachable,
17575 .bound_fn => unreachable,
17576
17577 .array,
17578 .array_sentinel,
17579 .vector,
17580 => return sema.typeRequiresComptime(block, src, ty.childType()),
17581
17582 .pointer,
17583 .single_const_pointer,
17584 .single_mut_pointer,
17585 .many_const_pointer,
17586 .many_mut_pointer,
17587 .c_const_pointer,
17588 .c_mut_pointer,
17589 .const_slice,
17590 .mut_slice,
17591 => {
17592 const child_ty = ty.childType();
17593 if (child_ty.zigTypeTag() == .Fn) {
17594 return false;
17595 } else {
17596 return sema.typeRequiresComptime(block, src, child_ty);
17597 }
17598 },
17599
17600 .optional,
17601 .optional_single_mut_pointer,
17602 .optional_single_const_pointer,
17603 => {
17604 var buf: Type.Payload.ElemType = undefined;
17605 return sema.typeRequiresComptime(block, src, ty.optionalChild(&buf));
17606 },
17607
17608 .tuple => {
17609 const tuple = ty.castTag(.tuple).?.data;
17610 for (tuple.types) |field_ty| {
17611 if (try sema.typeRequiresComptime(block, src, field_ty)) {
17612 return true;
17613 }
17614 }
17615 return false;
17616 },
17617
17618 .@"struct" => {
17619 const struct_obj = ty.castTag(.@"struct").?.data;
17620 switch (struct_obj.requires_comptime) {
17621 .no, .wip => return false,
17622 .yes => return true,
17623 .unknown => {
17624 if (struct_obj.status == .field_types_wip)
17625 return false;
17626
17627 try sema.resolveTypeFieldsStruct(block, src, ty, struct_obj);
17628
17629 struct_obj.requires_comptime = .wip;
17630 for (struct_obj.fields.values()) |field| {
17631 if (try sema.typeRequiresComptime(block, src, field.ty)) {
17632 struct_obj.requires_comptime = .yes;
17633 return true;
17634 }
17635 }
17636 struct_obj.requires_comptime = .no;
17637 return false;
17638 },
17639 }
17640 },
17641
17642 .@"union", .union_tagged => {
17643 const union_obj = ty.cast(Type.Payload.Union).?.data;
17644 switch (union_obj.requires_comptime) {
17645 .no, .wip => return false,
17646 .yes => return true,
17647 .unknown => {
17648 if (union_obj.status == .field_types_wip)
17649 return false;
17650
17651 try sema.resolveTypeFieldsUnion(block, src, ty, union_obj);
17652
17653 union_obj.requires_comptime = .wip;
17654 for (union_obj.fields.values()) |field| {
17655 if (try sema.typeRequiresComptime(block, src, field.ty)) {
17656 union_obj.requires_comptime = .yes;
17657 return true;
17658 }
17659 }
17660 union_obj.requires_comptime = .no;
17661 return false;
17662 },
17663 }
17664 },
17665
17666 .error_union => return sema.typeRequiresComptime(block, src, ty.errorUnionPayload()),
17667 .anyframe_T => {
17668 const child_ty = ty.castTag(.anyframe_T).?.data;
17669 return sema.typeRequiresComptime(block, src, child_ty);
17670 },
17671 .enum_numbered => {
17672 const tag_ty = ty.castTag(.enum_numbered).?.data.tag_ty;
17673 return sema.typeRequiresComptime(block, src, tag_ty);
17674 },
17675 .enum_full, .enum_nonexhaustive => {
17676 const tag_ty = ty.cast(Type.Payload.EnumFull).?.data.tag_ty;
17677 return sema.typeRequiresComptime(block, src, tag_ty);
17678 },
17679 };
17680}
17681
17682pub fn typeHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
17683 if ((try sema.typeHasOnePossibleValue(block, src, ty)) != null) return false;
17684 if (try sema.typeRequiresComptime(block, src, ty)) return false;
17685 return true;
17686}
17687
17688/// Synchronize logic with `Type.isFnOrHasRuntimeBits`.
17689pub fn fnHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
17690 const fn_info = ty.fnInfo();
17691 if (fn_info.is_generic) return false;
17692 if (fn_info.is_var_args) return true;
17693 switch (fn_info.cc) {
17694 // If there was a comptime calling convention, it should also return false here.
17695 .Inline => return false,
17696 else => {},
17697 }
17698 if (try sema.typeRequiresComptime(block, src, fn_info.return_type)) {
17699 return false;
17700 }
17701 return true;
17702}
src/Zir.zig+5-2
...@@ -2599,10 +2599,11 @@ pub const Inst = struct {...@@ -2599,10 +2599,11 @@ pub const Inst = struct {
2599 has_body_len: bool,2599 has_body_len: bool,
2600 has_fields_len: bool,2600 has_fields_len: bool,
2601 has_decls_len: bool,2601 has_decls_len: bool,
2602 known_has_bits: bool,2602 known_non_opv: bool,
2603 known_comptime_only: bool,
2603 name_strategy: NameStrategy,2604 name_strategy: NameStrategy,
2604 layout: std.builtin.TypeInfo.ContainerLayout,2605 layout: std.builtin.TypeInfo.ContainerLayout,
2605 _: u7 = undefined,2606 _: u6 = undefined,
2606 };2607 };
2607 };2608 };
26082609
...@@ -3273,6 +3274,7 @@ fn findDeclsBody(...@@ -3273,6 +3274,7 @@ fn findDeclsBody(
32733274
3274pub const FnInfo = struct {3275pub const FnInfo = struct {
3275 param_body: []const Inst.Index,3276 param_body: []const Inst.Index,
3277 param_body_inst: Inst.Index,
3276 ret_ty_body: []const Inst.Index,3278 ret_ty_body: []const Inst.Index,
3277 body: []const Inst.Index,3279 body: []const Inst.Index,
3278 total_params_len: u32,3280 total_params_len: u32,
...@@ -3338,6 +3340,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {...@@ -3338,6 +3340,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
3338 }3340 }
3339 return .{3341 return .{
3340 .param_body = param_body,3342 .param_body = param_body,
3343 .param_body_inst = info.param_block,
3341 .ret_ty_body = info.ret_ty_body,3344 .ret_ty_body = info.ret_ty_body,
3342 .body = info.body,3345 .body = info.body,
3343 .total_params_len = total_params_len,3346 .total_params_len = total_params_len,
src/arch/aarch64/CodeGen.zig+40-30
...@@ -713,7 +713,7 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {...@@ -713,7 +713,7 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
713fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {713fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
714 switch (self.debug_output) {714 switch (self.debug_output) {
715 .dwarf => |dbg_out| {715 .dwarf => |dbg_out| {
716 assert(ty.hasCodeGenBits());716 assert(ty.hasRuntimeBits());
717 const index = dbg_out.dbg_info.items.len;717 const index = dbg_out.dbg_info.items.len;
718 try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4718 try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
719719
...@@ -1279,7 +1279,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -1279,7 +1279,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
1279 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1279 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1280 const elem_ty = self.air.typeOfIndex(inst);1280 const elem_ty = self.air.typeOfIndex(inst);
1281 const result: MCValue = result: {1281 const result: MCValue = result: {
1282 if (!elem_ty.hasCodeGenBits())1282 if (!elem_ty.hasRuntimeBits())
1283 break :result MCValue.none;1283 break :result MCValue.none;
12841284
1285 const ptr = try self.resolveInst(ty_op.operand);1285 const ptr = try self.resolveInst(ty_op.operand);
...@@ -2155,7 +2155,7 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {...@@ -2155,7 +2155,7 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {
2155fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {2155fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
2156 const block_data = self.blocks.getPtr(block).?;2156 const block_data = self.blocks.getPtr(block).?;
21572157
2158 if (self.air.typeOf(operand).hasCodeGenBits()) {2158 if (self.air.typeOf(operand).hasRuntimeBits()) {
2159 const operand_mcv = try self.resolveInst(operand);2159 const operand_mcv = try self.resolveInst(operand);
2160 const block_mcv = block_data.mcv;2160 const block_mcv = block_data.mcv;
2161 if (block_mcv == .none) {2161 if (block_mcv == .none) {
...@@ -2608,7 +2608,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -2608,7 +2608,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
2608 const ref_int = @enumToInt(inst);2608 const ref_int = @enumToInt(inst);
2609 if (ref_int < Air.Inst.Ref.typed_value_map.len) {2609 if (ref_int < Air.Inst.Ref.typed_value_map.len) {
2610 const tv = Air.Inst.Ref.typed_value_map[ref_int];2610 const tv = Air.Inst.Ref.typed_value_map[ref_int];
2611 if (!tv.ty.hasCodeGenBits()) {2611 if (!tv.ty.hasRuntimeBits()) {
2612 return MCValue{ .none = {} };2612 return MCValue{ .none = {} };
2613 }2613 }
2614 return self.genTypedValue(tv);2614 return self.genTypedValue(tv);
...@@ -2616,7 +2616,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -2616,7 +2616,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
26162616
2617 // If the type has no codegen bits, no need to store it.2617 // If the type has no codegen bits, no need to store it.
2618 const inst_ty = self.air.typeOf(inst);2618 const inst_ty = self.air.typeOf(inst);
2619 if (!inst_ty.hasCodeGenBits())2619 if (!inst_ty.hasRuntimeBits())
2620 return MCValue{ .none = {} };2620 return MCValue{ .none = {} };
26212621
2622 const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);2622 const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);
...@@ -2672,11 +2672,43 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV...@@ -2672,11 +2672,43 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV
2672 return mcv;2672 return mcv;
2673}2673}
26742674
2675fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue {
2676 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
2677 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
2678 decl.alive = true;
2679 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
2680 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
2681 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
2682 return MCValue{ .memory = got_addr };
2683 } else if (self.bin_file.cast(link.File.MachO)) |_| {
2684 // TODO I'm hacking my way through here by repurposing .memory for storing
2685 // index to the GOT target symbol index.
2686 return MCValue{ .memory = decl.link.macho.local_sym_index };
2687 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
2688 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
2689 return MCValue{ .memory = got_addr };
2690 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
2691 try p9.seeDecl(decl);
2692 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
2693 return MCValue{ .memory = got_addr };
2694 } else {
2695 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
2696 }
2697 _ = tv;
2698}
2699
2675fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {2700fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
2676 if (typed_value.val.isUndef())2701 if (typed_value.val.isUndef())
2677 return MCValue{ .undef = {} };2702 return MCValue{ .undef = {} };
2678 const ptr_bits = self.target.cpu.arch.ptrBitWidth();2703 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
2679 const ptr_bytes: u64 = @divExact(ptr_bits, 8);2704
2705 if (typed_value.val.castTag(.decl_ref)) |payload| {
2706 return self.lowerDeclRef(typed_value, payload.data);
2707 }
2708 if (typed_value.val.castTag(.decl_ref_mut)) |payload| {
2709 return self.lowerDeclRef(typed_value, payload.data.decl);
2710 }
2711
2680 switch (typed_value.ty.zigTypeTag()) {2712 switch (typed_value.ty.zigTypeTag()) {
2681 .Pointer => switch (typed_value.ty.ptrSize()) {2713 .Pointer => switch (typed_value.ty.ptrSize()) {
2682 .Slice => {2714 .Slice => {
...@@ -2693,28 +2725,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -2693,28 +2725,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
2693 return self.fail("TODO codegen for const slices", .{});2725 return self.fail("TODO codegen for const slices", .{});
2694 },2726 },
2695 else => {2727 else => {
2696 if (typed_value.val.castTag(.decl_ref)) |payload| {
2697 const decl = payload.data;
2698 decl.alive = true;
2699 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
2700 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
2701 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
2702 return MCValue{ .memory = got_addr };
2703 } else if (self.bin_file.cast(link.File.MachO)) |_| {
2704 // TODO I'm hacking my way through here by repurposing .memory for storing
2705 // index to the GOT target symbol index.
2706 return MCValue{ .memory = decl.link.macho.local_sym_index };
2707 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
2708 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
2709 return MCValue{ .memory = got_addr };
2710 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
2711 try p9.seeDecl(decl);
2712 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
2713 return MCValue{ .memory = got_addr };
2714 } else {
2715 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
2716 }
2717 }
2718 if (typed_value.val.tag() == .int_u64) {2728 if (typed_value.val.tag() == .int_u64) {
2719 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };2729 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
2720 }2730 }
...@@ -2794,7 +2804,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -2794,7 +2804,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
2794 const payload_type = typed_value.ty.errorUnionPayload();2804 const payload_type = typed_value.ty.errorUnionPayload();
2795 const sub_val = typed_value.val.castTag(.eu_payload).?.data;2805 const sub_val = typed_value.val.castTag(.eu_payload).?.data;
27962806
2797 if (!payload_type.hasCodeGenBits()) {2807 if (!payload_type.hasRuntimeBits()) {
2798 // We use the error type directly as the type.2808 // We use the error type directly as the type.
2799 return self.genTypedValue(.{ .ty = error_type, .val = sub_val });2809 return self.genTypedValue(.{ .ty = error_type, .val = sub_val });
2800 }2810 }
...@@ -2888,7 +2898,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -2888,7 +2898,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
28882898
2889 if (ret_ty.zigTypeTag() == .NoReturn) {2899 if (ret_ty.zigTypeTag() == .NoReturn) {
2890 result.return_value = .{ .unreach = {} };2900 result.return_value = .{ .unreach = {} };
2891 } else if (!ret_ty.hasCodeGenBits()) {2901 } else if (!ret_ty.hasRuntimeBits()) {
2892 result.return_value = .{ .none = {} };2902 result.return_value = .{ .none = {} };
2893 } else switch (cc) {2903 } else switch (cc) {
2894 .Naked => unreachable,2904 .Naked => unreachable,
src/arch/arm/CodeGen.zig+47-35
...@@ -1074,7 +1074,7 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1074,7 +1074,7 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
1074 const error_union_ty = self.air.typeOf(ty_op.operand);1074 const error_union_ty = self.air.typeOf(ty_op.operand);
1075 const payload_ty = error_union_ty.errorUnionPayload();1075 const payload_ty = error_union_ty.errorUnionPayload();
1076 const mcv = try self.resolveInst(ty_op.operand);1076 const mcv = try self.resolveInst(ty_op.operand);
1077 if (!payload_ty.hasCodeGenBits()) break :result mcv;1077 if (!payload_ty.hasRuntimeBits()) break :result mcv;
10781078
1079 return self.fail("TODO implement unwrap error union error for non-empty payloads", .{});1079 return self.fail("TODO implement unwrap error union error for non-empty payloads", .{});
1080 };1080 };
...@@ -1086,7 +1086,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {...@@ -1086,7 +1086,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
1086 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1086 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1087 const error_union_ty = self.air.typeOf(ty_op.operand);1087 const error_union_ty = self.air.typeOf(ty_op.operand);
1088 const payload_ty = error_union_ty.errorUnionPayload();1088 const payload_ty = error_union_ty.errorUnionPayload();
1089 if (!payload_ty.hasCodeGenBits()) break :result MCValue.none;1089 if (!payload_ty.hasRuntimeBits()) break :result MCValue.none;
10901090
1091 return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{});1091 return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{});
1092 };1092 };
...@@ -1135,7 +1135,7 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1135,7 +1135,7 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
1135 const error_union_ty = self.air.getRefType(ty_op.ty);1135 const error_union_ty = self.air.getRefType(ty_op.ty);
1136 const payload_ty = error_union_ty.errorUnionPayload();1136 const payload_ty = error_union_ty.errorUnionPayload();
1137 const mcv = try self.resolveInst(ty_op.operand);1137 const mcv = try self.resolveInst(ty_op.operand);
1138 if (!payload_ty.hasCodeGenBits()) break :result mcv;1138 if (!payload_ty.hasRuntimeBits()) break :result mcv;
11391139
1140 return self.fail("TODO implement wrap errunion error for non-empty payloads", .{});1140 return self.fail("TODO implement wrap errunion error for non-empty payloads", .{});
1141 };1141 };
...@@ -1506,7 +1506,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -1506,7 +1506,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
1506 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1506 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1507 const elem_ty = self.air.typeOfIndex(inst);1507 const elem_ty = self.air.typeOfIndex(inst);
1508 const result: MCValue = result: {1508 const result: MCValue = result: {
1509 if (!elem_ty.hasCodeGenBits())1509 if (!elem_ty.hasRuntimeBits())
1510 break :result MCValue.none;1510 break :result MCValue.none;
15111511
1512 const ptr = try self.resolveInst(ty_op.operand);1512 const ptr = try self.resolveInst(ty_op.operand);
...@@ -2666,9 +2666,9 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {...@@ -2666,9 +2666,9 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
2666 const error_type = ty.errorUnionSet();2666 const error_type = ty.errorUnionSet();
2667 const payload_type = ty.errorUnionPayload();2667 const payload_type = ty.errorUnionPayload();
26682668
2669 if (!error_type.hasCodeGenBits()) {2669 if (!error_type.hasRuntimeBits()) {
2670 return MCValue{ .immediate = 0 }; // always false2670 return MCValue{ .immediate = 0 }; // always false
2671 } else if (!payload_type.hasCodeGenBits()) {2671 } else if (!payload_type.hasRuntimeBits()) {
2672 if (error_type.abiSize(self.target.*) <= 4) {2672 if (error_type.abiSize(self.target.*) <= 4) {
2673 const reg_mcv: MCValue = switch (operand) {2673 const reg_mcv: MCValue = switch (operand) {
2674 .register => operand,2674 .register => operand,
...@@ -2900,7 +2900,7 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {...@@ -2900,7 +2900,7 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {
2900fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {2900fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
2901 const block_data = self.blocks.getPtr(block).?;2901 const block_data = self.blocks.getPtr(block).?;
29022902
2903 if (self.air.typeOf(operand).hasCodeGenBits()) {2903 if (self.air.typeOf(operand).hasRuntimeBits()) {
2904 const operand_mcv = try self.resolveInst(operand);2904 const operand_mcv = try self.resolveInst(operand);
2905 const block_mcv = block_data.mcv;2905 const block_mcv = block_data.mcv;
2906 if (block_mcv == .none) {2906 if (block_mcv == .none) {
...@@ -3658,7 +3658,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -3658,7 +3658,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
3658 const ref_int = @enumToInt(inst);3658 const ref_int = @enumToInt(inst);
3659 if (ref_int < Air.Inst.Ref.typed_value_map.len) {3659 if (ref_int < Air.Inst.Ref.typed_value_map.len) {
3660 const tv = Air.Inst.Ref.typed_value_map[ref_int];3660 const tv = Air.Inst.Ref.typed_value_map[ref_int];
3661 if (!tv.ty.hasCodeGenBits()) {3661 if (!tv.ty.hasRuntimeBits()) {
3662 return MCValue{ .none = {} };3662 return MCValue{ .none = {} };
3663 }3663 }
3664 return self.genTypedValue(tv);3664 return self.genTypedValue(tv);
...@@ -3666,7 +3666,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -3666,7 +3666,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
36663666
3667 // If the type has no codegen bits, no need to store it.3667 // If the type has no codegen bits, no need to store it.
3668 const inst_ty = self.air.typeOf(inst);3668 const inst_ty = self.air.typeOf(inst);
3669 if (!inst_ty.hasCodeGenBits())3669 if (!inst_ty.hasRuntimeBits())
3670 return MCValue{ .none = {} };3670 return MCValue{ .none = {} };
36713671
3672 const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);3672 const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);
...@@ -3701,11 +3701,45 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue {...@@ -3701,11 +3701,45 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue {
3701 }3701 }
3702}3702}
37033703
3704fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue {
3705 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
3706 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
3707
3708 decl.alive = true;
3709 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
3710 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
3711 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
3712 return MCValue{ .memory = got_addr };
3713 } else if (self.bin_file.cast(link.File.MachO)) |_| {
3714 // TODO I'm hacking my way through here by repurposing .memory for storing
3715 // index to the GOT target symbol index.
3716 return MCValue{ .memory = decl.link.macho.local_sym_index };
3717 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
3718 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
3719 return MCValue{ .memory = got_addr };
3720 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
3721 try p9.seeDecl(decl);
3722 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
3723 return MCValue{ .memory = got_addr };
3724 } else {
3725 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
3726 }
3727
3728 _ = tv;
3729}
3730
3704fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {3731fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
3705 if (typed_value.val.isUndef())3732 if (typed_value.val.isUndef())
3706 return MCValue{ .undef = {} };3733 return MCValue{ .undef = {} };
3707 const ptr_bits = self.target.cpu.arch.ptrBitWidth();3734 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
3708 const ptr_bytes: u64 = @divExact(ptr_bits, 8);3735
3736 if (typed_value.val.castTag(.decl_ref)) |payload| {
3737 return self.lowerDeclRef(typed_value, payload.data);
3738 }
3739 if (typed_value.val.castTag(.decl_ref_mut)) |payload| {
3740 return self.lowerDeclRef(typed_value, payload.data.decl);
3741 }
3742
3709 switch (typed_value.ty.zigTypeTag()) {3743 switch (typed_value.ty.zigTypeTag()) {
3710 .Pointer => switch (typed_value.ty.ptrSize()) {3744 .Pointer => switch (typed_value.ty.ptrSize()) {
3711 .Slice => {3745 .Slice => {
...@@ -3722,28 +3756,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -3722,28 +3756,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
3722 return self.fail("TODO codegen for const slices", .{});3756 return self.fail("TODO codegen for const slices", .{});
3723 },3757 },
3724 else => {3758 else => {
3725 if (typed_value.val.castTag(.decl_ref)) |payload| {
3726 const decl = payload.data;
3727 decl.alive = true;
3728 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
3729 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
3730 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
3731 return MCValue{ .memory = got_addr };
3732 } else if (self.bin_file.cast(link.File.MachO)) |_| {
3733 // TODO I'm hacking my way through here by repurposing .memory for storing
3734 // index to the GOT target symbol index.
3735 return MCValue{ .memory = decl.link.macho.local_sym_index };
3736 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
3737 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
3738 return MCValue{ .memory = got_addr };
3739 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
3740 try p9.seeDecl(decl);
3741 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
3742 return MCValue{ .memory = got_addr };
3743 } else {
3744 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
3745 }
3746 }
3747 if (typed_value.val.tag() == .int_u64) {3759 if (typed_value.val.tag() == .int_u64) {
3748 return MCValue{ .immediate = @intCast(u32, typed_value.val.toUnsignedInt()) };3760 return MCValue{ .immediate = @intCast(u32, typed_value.val.toUnsignedInt()) };
3749 }3761 }
...@@ -3812,7 +3824,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -3812,7 +3824,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
3812 const payload_type = typed_value.ty.errorUnionPayload();3824 const payload_type = typed_value.ty.errorUnionPayload();
38133825
3814 if (typed_value.val.castTag(.eu_payload)) |pl| {3826 if (typed_value.val.castTag(.eu_payload)) |pl| {
3815 if (!payload_type.hasCodeGenBits()) {3827 if (!payload_type.hasRuntimeBits()) {
3816 // We use the error type directly as the type.3828 // We use the error type directly as the type.
3817 return MCValue{ .immediate = 0 };3829 return MCValue{ .immediate = 0 };
3818 }3830 }
...@@ -3820,7 +3832,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -3820,7 +3832,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
3820 _ = pl;3832 _ = pl;
3821 return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty});3833 return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty});
3822 } else {3834 } else {
3823 if (!payload_type.hasCodeGenBits()) {3835 if (!payload_type.hasRuntimeBits()) {
3824 // We use the error type directly as the type.3836 // We use the error type directly as the type.
3825 return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val });3837 return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val });
3826 }3838 }
...@@ -3918,7 +3930,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -3918,7 +3930,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
39183930
3919 if (ret_ty.zigTypeTag() == .NoReturn) {3931 if (ret_ty.zigTypeTag() == .NoReturn) {
3920 result.return_value = .{ .unreach = {} };3932 result.return_value = .{ .unreach = {} };
3921 } else if (!ret_ty.hasCodeGenBits()) {3933 } else if (!ret_ty.hasRuntimeBits()) {
3922 result.return_value = .{ .none = {} };3934 result.return_value = .{ .none = {} };
3923 } else switch (cc) {3935 } else switch (cc) {
3924 .Naked => unreachable,3936 .Naked => unreachable,
src/arch/arm/Emit.zig+1-1
...@@ -372,7 +372,7 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {...@@ -372,7 +372,7 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
372fn addDbgInfoTypeReloc(self: *Emit, ty: Type) !void {372fn addDbgInfoTypeReloc(self: *Emit, ty: Type) !void {
373 switch (self.debug_output) {373 switch (self.debug_output) {
374 .dwarf => |dbg_out| {374 .dwarf => |dbg_out| {
375 assert(ty.hasCodeGenBits());375 assert(ty.hasRuntimeBits());
376 const index = dbg_out.dbg_info.items.len;376 const index = dbg_out.dbg_info.items.len;
377 try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4377 try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
378378
src/arch/riscv64/CodeGen.zig+39-30
...@@ -691,7 +691,7 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {...@@ -691,7 +691,7 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
691fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {691fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
692 switch (self.debug_output) {692 switch (self.debug_output) {
693 .dwarf => |dbg_out| {693 .dwarf => |dbg_out| {
694 assert(ty.hasCodeGenBits());694 assert(ty.hasRuntimeBits());
695 const index = dbg_out.dbg_info.items.len;695 const index = dbg_out.dbg_info.items.len;
696 try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4696 try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
697697
...@@ -1223,7 +1223,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -1223,7 +1223,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
1223 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1223 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1224 const elem_ty = self.air.typeOfIndex(inst);1224 const elem_ty = self.air.typeOfIndex(inst);
1225 const result: MCValue = result: {1225 const result: MCValue = result: {
1226 if (!elem_ty.hasCodeGenBits())1226 if (!elem_ty.hasRuntimeBits())
1227 break :result MCValue.none;1227 break :result MCValue.none;
12281228
1229 const ptr = try self.resolveInst(ty_op.operand);1229 const ptr = try self.resolveInst(ty_op.operand);
...@@ -1769,7 +1769,7 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {...@@ -1769,7 +1769,7 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {
1769fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {1769fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
1770 const block_data = self.blocks.getPtr(block).?;1770 const block_data = self.blocks.getPtr(block).?;
17711771
1772 if (self.air.typeOf(operand).hasCodeGenBits()) {1772 if (self.air.typeOf(operand).hasRuntimeBits()) {
1773 const operand_mcv = try self.resolveInst(operand);1773 const operand_mcv = try self.resolveInst(operand);
1774 const block_mcv = block_data.mcv;1774 const block_mcv = block_data.mcv;
1775 if (block_mcv == .none) {1775 if (block_mcv == .none) {
...@@ -2107,7 +2107,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -2107,7 +2107,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
2107 const ref_int = @enumToInt(inst);2107 const ref_int = @enumToInt(inst);
2108 if (ref_int < Air.Inst.Ref.typed_value_map.len) {2108 if (ref_int < Air.Inst.Ref.typed_value_map.len) {
2109 const tv = Air.Inst.Ref.typed_value_map[ref_int];2109 const tv = Air.Inst.Ref.typed_value_map[ref_int];
2110 if (!tv.ty.hasCodeGenBits()) {2110 if (!tv.ty.hasRuntimeBits()) {
2111 return MCValue{ .none = {} };2111 return MCValue{ .none = {} };
2112 }2112 }
2113 return self.genTypedValue(tv);2113 return self.genTypedValue(tv);
...@@ -2115,7 +2115,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -2115,7 +2115,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
21152115
2116 // If the type has no codegen bits, no need to store it.2116 // If the type has no codegen bits, no need to store it.
2117 const inst_ty = self.air.typeOf(inst);2117 const inst_ty = self.air.typeOf(inst);
2118 if (!inst_ty.hasCodeGenBits())2118 if (!inst_ty.hasRuntimeBits())
2119 return MCValue{ .none = {} };2119 return MCValue{ .none = {} };
21202120
2121 const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);2121 const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);
...@@ -2171,11 +2171,42 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV...@@ -2171,11 +2171,42 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV
2171 return mcv;2171 return mcv;
2172}2172}
21732173
2174fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue {
2175 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
2176 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
2177 decl.alive = true;
2178 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
2179 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
2180 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
2181 return MCValue{ .memory = got_addr };
2182 } else if (self.bin_file.cast(link.File.MachO)) |_| {
2183 // TODO I'm hacking my way through here by repurposing .memory for storing
2184 // index to the GOT target symbol index.
2185 return MCValue{ .memory = decl.link.macho.local_sym_index };
2186 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
2187 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
2188 return MCValue{ .memory = got_addr };
2189 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
2190 try p9.seeDecl(decl);
2191 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
2192 return MCValue{ .memory = got_addr };
2193 } else {
2194 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
2195 }
2196 _ = tv;
2197}
2198
2174fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {2199fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
2175 if (typed_value.val.isUndef())2200 if (typed_value.val.isUndef())
2176 return MCValue{ .undef = {} };2201 return MCValue{ .undef = {} };
2202
2203 if (typed_value.val.castTag(.decl_ref)) |payload| {
2204 return self.lowerDeclRef(typed_value, payload.data);
2205 }
2206 if (typed_value.val.castTag(.decl_ref_mut)) |payload| {
2207 return self.lowerDeclRef(typed_value, payload.data.decl);
2208 }
2177 const ptr_bits = self.target.cpu.arch.ptrBitWidth();2209 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
2178 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
2179 switch (typed_value.ty.zigTypeTag()) {2210 switch (typed_value.ty.zigTypeTag()) {
2180 .Pointer => switch (typed_value.ty.ptrSize()) {2211 .Pointer => switch (typed_value.ty.ptrSize()) {
2181 .Slice => {2212 .Slice => {
...@@ -2192,28 +2223,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -2192,28 +2223,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
2192 return self.fail("TODO codegen for const slices", .{});2223 return self.fail("TODO codegen for const slices", .{});
2193 },2224 },
2194 else => {2225 else => {
2195 if (typed_value.val.castTag(.decl_ref)) |payload| {
2196 const decl = payload.data;
2197 decl.alive = true;
2198 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
2199 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
2200 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
2201 return MCValue{ .memory = got_addr };
2202 } else if (self.bin_file.cast(link.File.MachO)) |_| {
2203 // TODO I'm hacking my way through here by repurposing .memory for storing
2204 // index to the GOT target symbol index.
2205 return MCValue{ .memory = decl.link.macho.local_sym_index };
2206 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
2207 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
2208 return MCValue{ .memory = got_addr };
2209 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
2210 try p9.seeDecl(decl);
2211 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
2212 return MCValue{ .memory = got_addr };
2213 } else {
2214 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
2215 }
2216 }
2217 if (typed_value.val.tag() == .int_u64) {2226 if (typed_value.val.tag() == .int_u64) {
2218 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };2227 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
2219 }2228 }
...@@ -2290,7 +2299,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -2290,7 +2299,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
2290 const payload_type = typed_value.ty.errorUnionPayload();2299 const payload_type = typed_value.ty.errorUnionPayload();
2291 const sub_val = typed_value.val.castTag(.eu_payload).?.data;2300 const sub_val = typed_value.val.castTag(.eu_payload).?.data;
22922301
2293 if (!payload_type.hasCodeGenBits()) {2302 if (!payload_type.hasRuntimeBits()) {
2294 // We use the error type directly as the type.2303 // We use the error type directly as the type.
2295 return self.genTypedValue(.{ .ty = error_type, .val = sub_val });2304 return self.genTypedValue(.{ .ty = error_type, .val = sub_val });
2296 }2305 }
...@@ -2381,7 +2390,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -2381,7 +2390,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
23812390
2382 if (ret_ty.zigTypeTag() == .NoReturn) {2391 if (ret_ty.zigTypeTag() == .NoReturn) {
2383 result.return_value = .{ .unreach = {} };2392 result.return_value = .{ .unreach = {} };
2384 } else if (!ret_ty.hasCodeGenBits()) {2393 } else if (!ret_ty.hasRuntimeBits()) {
2385 result.return_value = .{ .none = {} };2394 result.return_value = .{ .none = {} };
2386 } else switch (cc) {2395 } else switch (cc) {
2387 .Naked => unreachable,2396 .Naked => unreachable,
src/arch/wasm/CodeGen.zig+35-35
...@@ -598,7 +598,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!WValue {...@@ -598,7 +598,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!WValue {
598 // means we must generate it from a constant.598 // means we must generate it from a constant.
599 const val = self.air.value(ref).?;599 const val = self.air.value(ref).?;
600 const ty = self.air.typeOf(ref);600 const ty = self.air.typeOf(ref);
601 if (!ty.hasCodeGenBits() and !ty.isInt()) return WValue{ .none = {} };601 if (!ty.hasRuntimeBits() and !ty.isInt()) return WValue{ .none = {} };
602602
603 // When we need to pass the value by reference (such as a struct), we will603 // When we need to pass the value by reference (such as a struct), we will
604 // leverage `genTypedValue` to lower the constant to bytes and emit it604 // leverage `genTypedValue` to lower the constant to bytes and emit it
...@@ -790,13 +790,13 @@ fn genFunctype(gpa: Allocator, fn_ty: Type, target: std.Target) !wasm.Type {...@@ -790,13 +790,13 @@ fn genFunctype(gpa: Allocator, fn_ty: Type, target: std.Target) !wasm.Type {
790 defer gpa.free(fn_params);790 defer gpa.free(fn_params);
791 fn_ty.fnParamTypes(fn_params);791 fn_ty.fnParamTypes(fn_params);
792 for (fn_params) |param_type| {792 for (fn_params) |param_type| {
793 if (!param_type.hasCodeGenBits()) continue;793 if (!param_type.hasRuntimeBits()) continue;
794 try params.append(typeToValtype(param_type, target));794 try params.append(typeToValtype(param_type, target));
795 }795 }
796 }796 }
797797
798 // return type798 // return type
799 if (!want_sret and return_type.hasCodeGenBits()) {799 if (!want_sret and return_type.hasRuntimeBits()) {
800 try returns.append(typeToValtype(return_type, target));800 try returns.append(typeToValtype(return_type, target));
801 }801 }
802802
...@@ -935,7 +935,7 @@ pub const DeclGen = struct {...@@ -935,7 +935,7 @@ pub const DeclGen = struct {
935 const abi_size = @intCast(usize, ty.abiSize(self.target()));935 const abi_size = @intCast(usize, ty.abiSize(self.target()));
936 const offset = abi_size - @intCast(usize, payload_type.abiSize(self.target()));936 const offset = abi_size - @intCast(usize, payload_type.abiSize(self.target()));
937937
938 if (!payload_type.hasCodeGenBits()) {938 if (!payload_type.hasRuntimeBits()) {
939 try writer.writeByteNTimes(@boolToInt(is_pl), abi_size);939 try writer.writeByteNTimes(@boolToInt(is_pl), abi_size);
940 return Result{ .appended = {} };940 return Result{ .appended = {} };
941 }941 }
...@@ -1044,7 +1044,7 @@ pub const DeclGen = struct {...@@ -1044,7 +1044,7 @@ pub const DeclGen = struct {
1044 const field_vals = val.castTag(.@"struct").?.data;1044 const field_vals = val.castTag(.@"struct").?.data;
1045 for (field_vals) |field_val, index| {1045 for (field_vals) |field_val, index| {
1046 const field_ty = ty.structFieldType(index);1046 const field_ty = ty.structFieldType(index);
1047 if (!field_ty.hasCodeGenBits()) continue;1047 if (!field_ty.hasRuntimeBits()) continue;
1048 switch (try self.genTypedValue(field_ty, field_val, writer)) {1048 switch (try self.genTypedValue(field_ty, field_val, writer)) {
1049 .appended => {},1049 .appended => {},
1050 .externally_managed => |payload| try writer.writeAll(payload),1050 .externally_managed => |payload| try writer.writeAll(payload),
...@@ -1093,7 +1093,7 @@ pub const DeclGen = struct {...@@ -1093,7 +1093,7 @@ pub const DeclGen = struct {
1093 .appended => {},1093 .appended => {},
1094 }1094 }
10951095
1096 if (payload_ty.hasCodeGenBits()) {1096 if (payload_ty.hasRuntimeBits()) {
1097 const pl_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef);1097 const pl_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef);
1098 switch (try self.genTypedValue(payload_ty, pl_val, writer)) {1098 switch (try self.genTypedValue(payload_ty, pl_val, writer)) {
1099 .externally_managed => |data| try writer.writeAll(data),1099 .externally_managed => |data| try writer.writeAll(data),
...@@ -1180,7 +1180,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu...@@ -1180,7 +1180,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu
1180 .Naked => return result,1180 .Naked => return result,
1181 .Unspecified, .C => {1181 .Unspecified, .C => {
1182 for (param_types) |ty, ty_index| {1182 for (param_types) |ty, ty_index| {
1183 if (!ty.hasCodeGenBits()) {1183 if (!ty.hasRuntimeBits()) {
1184 result.args[ty_index] = .{ .none = {} };1184 result.args[ty_index] = .{ .none = {} };
1185 continue;1185 continue;
1186 }1186 }
...@@ -1243,7 +1243,7 @@ fn moveStack(self: *Self, offset: u32, local: u32) !void {...@@ -1243,7 +1243,7 @@ fn moveStack(self: *Self, offset: u32, local: u32) !void {
1243///1243///
1244/// Asserts Type has codegenbits1244/// Asserts Type has codegenbits
1245fn allocStack(self: *Self, ty: Type) !WValue {1245fn allocStack(self: *Self, ty: Type) !WValue {
1246 assert(ty.hasCodeGenBits());1246 assert(ty.hasRuntimeBits());
12471247
1248 // calculate needed stack space1248 // calculate needed stack space
1249 const abi_size = std.math.cast(u32, ty.abiSize(self.target)) catch {1249 const abi_size = std.math.cast(u32, ty.abiSize(self.target)) catch {
...@@ -1319,22 +1319,22 @@ fn isByRef(ty: Type, target: std.Target) bool {...@@ -1319,22 +1319,22 @@ fn isByRef(ty: Type, target: std.Target) bool {
1319 .Struct,1319 .Struct,
1320 .Frame,1320 .Frame,
1321 .Union,1321 .Union,
1322 => return ty.hasCodeGenBits(),1322 => return ty.hasRuntimeBits(),
1323 .Int => return if (ty.intInfo(target).bits > 64) true else false,1323 .Int => return if (ty.intInfo(target).bits > 64) true else false,
1324 .ErrorUnion => {1324 .ErrorUnion => {
1325 const has_tag = ty.errorUnionSet().hasCodeGenBits();1325 const has_tag = ty.errorUnionSet().hasRuntimeBits();
1326 const has_pl = ty.errorUnionPayload().hasCodeGenBits();1326 const has_pl = ty.errorUnionPayload().hasRuntimeBits();
1327 if (!has_tag or !has_pl) return false;1327 if (!has_tag or !has_pl) return false;
1328 return ty.hasCodeGenBits();1328 return ty.hasRuntimeBits();
1329 },1329 },
1330 .Optional => {1330 .Optional => {
1331 if (ty.isPtrLikeOptional()) return false;1331 if (ty.isPtrLikeOptional()) return false;
1332 var buf: Type.Payload.ElemType = undefined;1332 var buf: Type.Payload.ElemType = undefined;
1333 return ty.optionalChild(&buf).hasCodeGenBits();1333 return ty.optionalChild(&buf).hasRuntimeBits();
1334 },1334 },
1335 .Pointer => {1335 .Pointer => {
1336 // Slices act like struct and will be passed by reference1336 // Slices act like struct and will be passed by reference
1337 if (ty.isSlice()) return ty.hasCodeGenBits();1337 if (ty.isSlice()) return ty.hasRuntimeBits();
1338 return false;1338 return false;
1339 },1339 },
1340 }1340 }
...@@ -1563,7 +1563,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1563,7 +1563,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1563 const un_op = self.air.instructions.items(.data)[inst].un_op;1563 const un_op = self.air.instructions.items(.data)[inst].un_op;
1564 const operand = try self.resolveInst(un_op);1564 const operand = try self.resolveInst(un_op);
1565 const ret_ty = self.air.typeOf(un_op).childType();1565 const ret_ty = self.air.typeOf(un_op).childType();
1566 if (!ret_ty.hasCodeGenBits()) return WValue.none;1566 if (!ret_ty.hasRuntimeBits()) return WValue.none;
15671567
1568 if (!isByRef(ret_ty, self.target)) {1568 if (!isByRef(ret_ty, self.target)) {
1569 const result = try self.load(operand, ret_ty, 0);1569 const result = try self.load(operand, ret_ty, 0);
...@@ -1611,7 +1611,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1611,7 +1611,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1611 const arg_val = try self.resolveInst(arg_ref);1611 const arg_val = try self.resolveInst(arg_ref);
16121612
1613 const arg_ty = self.air.typeOf(arg_ref);1613 const arg_ty = self.air.typeOf(arg_ref);
1614 if (!arg_ty.hasCodeGenBits()) continue;1614 if (!arg_ty.hasRuntimeBits()) continue;
1615 try self.emitWValue(arg_val);1615 try self.emitWValue(arg_val);
1616 }1616 }
16171617
...@@ -1631,7 +1631,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1631,7 +1631,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1631 try self.addLabel(.call_indirect, fn_type_index);1631 try self.addLabel(.call_indirect, fn_type_index);
1632 }1632 }
16331633
1634 if (self.liveness.isUnused(inst) or !ret_ty.hasCodeGenBits()) {1634 if (self.liveness.isUnused(inst) or !ret_ty.hasRuntimeBits()) {
1635 return WValue.none;1635 return WValue.none;
1636 } else if (ret_ty.isNoReturn()) {1636 } else if (ret_ty.isNoReturn()) {
1637 try self.addTag(.@"unreachable");1637 try self.addTag(.@"unreachable");
...@@ -1653,7 +1653,7 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1653,7 +1653,7 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1653 try self.initializeStack();1653 try self.initializeStack();
1654 }1654 }
16551655
1656 if (!pointee_type.hasCodeGenBits()) {1656 if (!pointee_type.hasRuntimeBits()) {
1657 // when the pointee is zero-sized, we still want to create a pointer.1657 // when the pointee is zero-sized, we still want to create a pointer.
1658 // but instead use a default pointer type as storage.1658 // but instead use a default pointer type as storage.
1659 const zero_ptr = try self.allocStack(Type.usize);1659 const zero_ptr = try self.allocStack(Type.usize);
...@@ -1678,7 +1678,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro...@@ -1678,7 +1678,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
1678 .ErrorUnion => {1678 .ErrorUnion => {
1679 const err_ty = ty.errorUnionSet();1679 const err_ty = ty.errorUnionSet();
1680 const pl_ty = ty.errorUnionPayload();1680 const pl_ty = ty.errorUnionPayload();
1681 if (!pl_ty.hasCodeGenBits()) {1681 if (!pl_ty.hasRuntimeBits()) {
1682 const err_val = try self.load(rhs, err_ty, 0);1682 const err_val = try self.load(rhs, err_ty, 0);
1683 return self.store(lhs, err_val, err_ty, 0);1683 return self.store(lhs, err_val, err_ty, 0);
1684 }1684 }
...@@ -1691,7 +1691,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro...@@ -1691,7 +1691,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
1691 }1691 }
1692 var buf: Type.Payload.ElemType = undefined;1692 var buf: Type.Payload.ElemType = undefined;
1693 const pl_ty = ty.optionalChild(&buf);1693 const pl_ty = ty.optionalChild(&buf);
1694 if (!pl_ty.hasCodeGenBits()) {1694 if (!pl_ty.hasRuntimeBits()) {
1695 return self.store(lhs, rhs, Type.initTag(.u8), 0);1695 return self.store(lhs, rhs, Type.initTag(.u8), 0);
1696 }1696 }
16971697
...@@ -1750,7 +1750,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1750,7 +1750,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1750 const operand = try self.resolveInst(ty_op.operand);1750 const operand = try self.resolveInst(ty_op.operand);
1751 const ty = self.air.getRefType(ty_op.ty);1751 const ty = self.air.getRefType(ty_op.ty);
17521752
1753 if (!ty.hasCodeGenBits()) return WValue{ .none = {} };1753 if (!ty.hasRuntimeBits()) return WValue{ .none = {} };
17541754
1755 if (isByRef(ty, self.target)) {1755 if (isByRef(ty, self.target)) {
1756 const new_local = try self.allocStack(ty);1756 const new_local = try self.allocStack(ty);
...@@ -2146,7 +2146,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner...@@ -2146,7 +2146,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner
2146 if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) {2146 if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) {
2147 var buf: Type.Payload.ElemType = undefined;2147 var buf: Type.Payload.ElemType = undefined;
2148 const payload_ty = operand_ty.optionalChild(&buf);2148 const payload_ty = operand_ty.optionalChild(&buf);
2149 if (payload_ty.hasCodeGenBits()) {2149 if (payload_ty.hasRuntimeBits()) {
2150 // When we hit this case, we must check the value of optionals2150 // When we hit this case, we must check the value of optionals
2151 // that are not pointers. This means first checking against non-null for2151 // that are not pointers. This means first checking against non-null for
2152 // both lhs and rhs, as well as checking the payload are matching of lhs and rhs2152 // both lhs and rhs, as well as checking the payload are matching of lhs and rhs
...@@ -2190,7 +2190,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2190,7 +2190,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2190 const block = self.blocks.get(br.block_inst).?;2190 const block = self.blocks.get(br.block_inst).?;
21912191
2192 // if operand has codegen bits we should break with a value2192 // if operand has codegen bits we should break with a value
2193 if (self.air.typeOf(br.operand).hasCodeGenBits()) {2193 if (self.air.typeOf(br.operand).hasRuntimeBits()) {
2194 try self.emitWValue(try self.resolveInst(br.operand));2194 try self.emitWValue(try self.resolveInst(br.operand));
21952195
2196 if (block.value != .none) {2196 if (block.value != .none) {
...@@ -2282,7 +2282,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2282,7 +2282,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2282 const operand = try self.resolveInst(struct_field.struct_operand);2282 const operand = try self.resolveInst(struct_field.struct_operand);
2283 const field_index = struct_field.field_index;2283 const field_index = struct_field.field_index;
2284 const field_ty = struct_ty.structFieldType(field_index);2284 const field_ty = struct_ty.structFieldType(field_index);
2285 if (!field_ty.hasCodeGenBits()) return WValue{ .none = {} };2285 if (!field_ty.hasRuntimeBits()) return WValue{ .none = {} };
2286 const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, self.target)) catch {2286 const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, self.target)) catch {
2287 return self.fail("Field type '{}' too big to fit into stack frame", .{field_ty});2287 return self.fail("Field type '{}' too big to fit into stack frame", .{field_ty});
2288 };2288 };
...@@ -2452,7 +2452,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!W...@@ -2452,7 +2452,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!W
24522452
2453 // load the error tag value2453 // load the error tag value
2454 try self.emitWValue(operand);2454 try self.emitWValue(operand);
2455 if (pl_ty.hasCodeGenBits()) {2455 if (pl_ty.hasRuntimeBits()) {
2456 try self.addMemArg(.i32_load16_u, .{2456 try self.addMemArg(.i32_load16_u, .{
2457 .offset = 0,2457 .offset = 0,
2458 .alignment = err_ty.errorUnionSet().abiAlignment(self.target),2458 .alignment = err_ty.errorUnionSet().abiAlignment(self.target),
...@@ -2474,7 +2474,7 @@ fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue...@@ -2474,7 +2474,7 @@ fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue
2474 const operand = try self.resolveInst(ty_op.operand);2474 const operand = try self.resolveInst(ty_op.operand);
2475 const err_ty = self.air.typeOf(ty_op.operand);2475 const err_ty = self.air.typeOf(ty_op.operand);
2476 const payload_ty = err_ty.errorUnionPayload();2476 const payload_ty = err_ty.errorUnionPayload();
2477 if (!payload_ty.hasCodeGenBits()) return WValue{ .none = {} };2477 if (!payload_ty.hasRuntimeBits()) return WValue{ .none = {} };
2478 const offset = @intCast(u32, err_ty.errorUnionSet().abiSize(self.target));2478 const offset = @intCast(u32, err_ty.errorUnionSet().abiSize(self.target));
2479 if (isByRef(payload_ty, self.target)) {2479 if (isByRef(payload_ty, self.target)) {
2480 return self.buildPointerOffset(operand, offset, .new);2480 return self.buildPointerOffset(operand, offset, .new);
...@@ -2489,7 +2489,7 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2489,7 +2489,7 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2489 const operand = try self.resolveInst(ty_op.operand);2489 const operand = try self.resolveInst(ty_op.operand);
2490 const err_ty = self.air.typeOf(ty_op.operand);2490 const err_ty = self.air.typeOf(ty_op.operand);
2491 const payload_ty = err_ty.errorUnionPayload();2491 const payload_ty = err_ty.errorUnionPayload();
2492 if (!payload_ty.hasCodeGenBits()) {2492 if (!payload_ty.hasRuntimeBits()) {
2493 return operand;2493 return operand;
2494 }2494 }
24952495
...@@ -2502,7 +2502,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2502,7 +2502,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2502 const operand = try self.resolveInst(ty_op.operand);2502 const operand = try self.resolveInst(ty_op.operand);
25032503
2504 const op_ty = self.air.typeOf(ty_op.operand);2504 const op_ty = self.air.typeOf(ty_op.operand);
2505 if (!op_ty.hasCodeGenBits()) return operand;2505 if (!op_ty.hasRuntimeBits()) return operand;
2506 const err_ty = self.air.getRefType(ty_op.ty);2506 const err_ty = self.air.getRefType(ty_op.ty);
2507 const offset = err_ty.errorUnionSet().abiSize(self.target);2507 const offset = err_ty.errorUnionSet().abiSize(self.target);
25082508
...@@ -2580,7 +2580,7 @@ fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode)...@@ -2580,7 +2580,7 @@ fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode)
2580 const payload_ty = optional_ty.optionalChild(&buf);2580 const payload_ty = optional_ty.optionalChild(&buf);
2581 // When payload is zero-bits, we can treat operand as a value, rather than2581 // When payload is zero-bits, we can treat operand as a value, rather than
2582 // a pointer to the stack value2582 // a pointer to the stack value
2583 if (payload_ty.hasCodeGenBits()) {2583 if (payload_ty.hasRuntimeBits()) {
2584 try self.addMemArg(.i32_load8_u, .{ .offset = 0, .alignment = 1 });2584 try self.addMemArg(.i32_load8_u, .{ .offset = 0, .alignment = 1 });
2585 }2585 }
2586 }2586 }
...@@ -2600,7 +2600,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2600,7 +2600,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2600 const operand = try self.resolveInst(ty_op.operand);2600 const operand = try self.resolveInst(ty_op.operand);
2601 const opt_ty = self.air.typeOf(ty_op.operand);2601 const opt_ty = self.air.typeOf(ty_op.operand);
2602 const payload_ty = self.air.typeOfIndex(inst);2602 const payload_ty = self.air.typeOfIndex(inst);
2603 if (!payload_ty.hasCodeGenBits()) return WValue{ .none = {} };2603 if (!payload_ty.hasRuntimeBits()) return WValue{ .none = {} };
2604 if (opt_ty.isPtrLikeOptional()) return operand;2604 if (opt_ty.isPtrLikeOptional()) return operand;
26052605
2606 const offset = opt_ty.abiSize(self.target) - payload_ty.abiSize(self.target);2606 const offset = opt_ty.abiSize(self.target) - payload_ty.abiSize(self.target);
...@@ -2621,7 +2621,7 @@ fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2621,7 +2621,7 @@ fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
26212621
2622 var buf: Type.Payload.ElemType = undefined;2622 var buf: Type.Payload.ElemType = undefined;
2623 const payload_ty = opt_ty.optionalChild(&buf);2623 const payload_ty = opt_ty.optionalChild(&buf);
2624 if (!payload_ty.hasCodeGenBits() or opt_ty.isPtrLikeOptional()) {2624 if (!payload_ty.hasRuntimeBits() or opt_ty.isPtrLikeOptional()) {
2625 return operand;2625 return operand;
2626 }2626 }
26272627
...@@ -2635,7 +2635,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue...@@ -2635,7 +2635,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue
2635 const opt_ty = self.air.typeOf(ty_op.operand).childType();2635 const opt_ty = self.air.typeOf(ty_op.operand).childType();
2636 var buf: Type.Payload.ElemType = undefined;2636 var buf: Type.Payload.ElemType = undefined;
2637 const payload_ty = opt_ty.optionalChild(&buf);2637 const payload_ty = opt_ty.optionalChild(&buf);
2638 if (!payload_ty.hasCodeGenBits()) {2638 if (!payload_ty.hasRuntimeBits()) {
2639 return self.fail("TODO: Implement OptionalPayloadPtrSet for optional with zero-sized type {}", .{payload_ty});2639 return self.fail("TODO: Implement OptionalPayloadPtrSet for optional with zero-sized type {}", .{payload_ty});
2640 }2640 }
26412641
...@@ -2659,7 +2659,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2659,7 +2659,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
26592659
2660 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2660 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2661 const payload_ty = self.air.typeOf(ty_op.operand);2661 const payload_ty = self.air.typeOf(ty_op.operand);
2662 if (!payload_ty.hasCodeGenBits()) {2662 if (!payload_ty.hasRuntimeBits()) {
2663 const non_null_bit = try self.allocStack(Type.initTag(.u1));2663 const non_null_bit = try self.allocStack(Type.initTag(.u1));
2664 try self.addLabel(.local_get, non_null_bit.local);2664 try self.addLabel(.local_get, non_null_bit.local);
2665 try self.addImm32(1);2665 try self.addImm32(1);
...@@ -2851,7 +2851,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2851,7 +2851,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2851 const slice_local = try self.allocStack(slice_ty);2851 const slice_local = try self.allocStack(slice_ty);
28522852
2853 // store the array ptr in the slice2853 // store the array ptr in the slice
2854 if (array_ty.hasCodeGenBits()) {2854 if (array_ty.hasRuntimeBits()) {
2855 try self.store(slice_local, operand, ty, 0);2855 try self.store(slice_local, operand, ty, 0);
2856 }2856 }
28572857
...@@ -3105,7 +3105,7 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3105,7 +3105,7 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3105}3105}
31063106
3107fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {3107fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {
3108 assert(operand_ty.hasCodeGenBits());3108 assert(operand_ty.hasRuntimeBits());
3109 assert(op == .eq or op == .neq);3109 assert(op == .eq or op == .neq);
3110 var buf: Type.Payload.ElemType = undefined;3110 var buf: Type.Payload.ElemType = undefined;
3111 const payload_ty = operand_ty.optionalChild(&buf);3111 const payload_ty = operand_ty.optionalChild(&buf);
src/arch/x86_64/CodeGen.zig+49-37
...@@ -1202,7 +1202,7 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1202,7 +1202,7 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
1202 const err_union_ty = self.air.typeOf(ty_op.operand);1202 const err_union_ty = self.air.typeOf(ty_op.operand);
1203 const payload_ty = err_union_ty.errorUnionPayload();1203 const payload_ty = err_union_ty.errorUnionPayload();
1204 const mcv = try self.resolveInst(ty_op.operand);1204 const mcv = try self.resolveInst(ty_op.operand);
1205 if (!payload_ty.hasCodeGenBits()) break :result mcv;1205 if (!payload_ty.hasRuntimeBits()) break :result mcv;
1206 return self.fail("TODO implement unwrap error union error for non-empty payloads", .{});1206 return self.fail("TODO implement unwrap error union error for non-empty payloads", .{});
1207 };1207 };
1208 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1208 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
...@@ -1213,7 +1213,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {...@@ -1213,7 +1213,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
1213 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1213 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1214 const err_union_ty = self.air.typeOf(ty_op.operand);1214 const err_union_ty = self.air.typeOf(ty_op.operand);
1215 const payload_ty = err_union_ty.errorUnionPayload();1215 const payload_ty = err_union_ty.errorUnionPayload();
1216 if (!payload_ty.hasCodeGenBits()) break :result MCValue.none;1216 if (!payload_ty.hasRuntimeBits()) break :result MCValue.none;
1217 return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{});1217 return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{});
1218 };1218 };
1219 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1219 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
...@@ -1270,7 +1270,7 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1270,7 +1270,7 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
1270 const error_union_ty = self.air.getRefType(ty_op.ty);1270 const error_union_ty = self.air.getRefType(ty_op.ty);
1271 const payload_ty = error_union_ty.errorUnionPayload();1271 const payload_ty = error_union_ty.errorUnionPayload();
1272 const mcv = try self.resolveInst(ty_op.operand);1272 const mcv = try self.resolveInst(ty_op.operand);
1273 if (!payload_ty.hasCodeGenBits()) break :result mcv;1273 if (!payload_ty.hasRuntimeBits()) break :result mcv;
12741274
1275 return self.fail("TODO implement wrap errunion error for non-empty payloads", .{});1275 return self.fail("TODO implement wrap errunion error for non-empty payloads", .{});
1276 };1276 };
...@@ -1636,7 +1636,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -1636,7 +1636,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
1636 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1636 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1637 const elem_ty = self.air.typeOfIndex(inst);1637 const elem_ty = self.air.typeOfIndex(inst);
1638 const result: MCValue = result: {1638 const result: MCValue = result: {
1639 if (!elem_ty.hasCodeGenBits())1639 if (!elem_ty.hasRuntimeBits())
1640 break :result MCValue.none;1640 break :result MCValue.none;
16411641
1642 const ptr = try self.resolveInst(ty_op.operand);1642 const ptr = try self.resolveInst(ty_op.operand);
...@@ -2739,9 +2739,9 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {...@@ -2739,9 +2739,9 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {
2739fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {2739fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
2740 const err_type = ty.errorUnionSet();2740 const err_type = ty.errorUnionSet();
2741 const payload_type = ty.errorUnionPayload();2741 const payload_type = ty.errorUnionPayload();
2742 if (!err_type.hasCodeGenBits()) {2742 if (!err_type.hasRuntimeBits()) {
2743 return MCValue{ .immediate = 0 }; // always false2743 return MCValue{ .immediate = 0 }; // always false
2744 } else if (!payload_type.hasCodeGenBits()) {2744 } else if (!payload_type.hasRuntimeBits()) {
2745 if (err_type.abiSize(self.target.*) <= 8) {2745 if (err_type.abiSize(self.target.*) <= 8) {
2746 try self.genBinMathOpMir(.cmp, err_type, .unsigned, operand, MCValue{ .immediate = 0 });2746 try self.genBinMathOpMir(.cmp, err_type, .unsigned, operand, MCValue{ .immediate = 0 });
2747 return MCValue{ .compare_flags_unsigned = .gt };2747 return MCValue{ .compare_flags_unsigned = .gt };
...@@ -2962,7 +2962,7 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {...@@ -2962,7 +2962,7 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {
2962fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {2962fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
2963 const block_data = self.blocks.getPtr(block).?;2963 const block_data = self.blocks.getPtr(block).?;
29642964
2965 if (self.air.typeOf(operand).hasCodeGenBits()) {2965 if (self.air.typeOf(operand).hasRuntimeBits()) {
2966 const operand_mcv = try self.resolveInst(operand);2966 const operand_mcv = try self.resolveInst(operand);
2967 const block_mcv = block_data.mcv;2967 const block_mcv = block_data.mcv;
2968 if (block_mcv == .none) {2968 if (block_mcv == .none) {
...@@ -3913,7 +3913,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -3913,7 +3913,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
3913 const ref_int = @enumToInt(inst);3913 const ref_int = @enumToInt(inst);
3914 if (ref_int < Air.Inst.Ref.typed_value_map.len) {3914 if (ref_int < Air.Inst.Ref.typed_value_map.len) {
3915 const tv = Air.Inst.Ref.typed_value_map[ref_int];3915 const tv = Air.Inst.Ref.typed_value_map[ref_int];
3916 if (!tv.ty.hasCodeGenBits()) {3916 if (!tv.ty.hasRuntimeBits()) {
3917 return MCValue{ .none = {} };3917 return MCValue{ .none = {} };
3918 }3918 }
3919 return self.genTypedValue(tv);3919 return self.genTypedValue(tv);
...@@ -3921,7 +3921,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -3921,7 +3921,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
39213921
3922 // If the type has no codegen bits, no need to store it.3922 // If the type has no codegen bits, no need to store it.
3923 const inst_ty = self.air.typeOf(inst);3923 const inst_ty = self.air.typeOf(inst);
3924 if (!inst_ty.hasCodeGenBits())3924 if (!inst_ty.hasRuntimeBits())
3925 return MCValue{ .none = {} };3925 return MCValue{ .none = {} };
39263926
3927 const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);3927 const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);
...@@ -3977,11 +3977,45 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV...@@ -3977,11 +3977,45 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV
3977 return mcv;3977 return mcv;
3978}3978}
39793979
3980fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue {
3981 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
3982 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
3983
3984 decl.alive = true;
3985 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
3986 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
3987 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
3988 return MCValue{ .memory = got_addr };
3989 } else if (self.bin_file.cast(link.File.MachO)) |_| {
3990 // TODO I'm hacking my way through here by repurposing .memory for storing
3991 // index to the GOT target symbol index.
3992 return MCValue{ .memory = decl.link.macho.local_sym_index };
3993 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
3994 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
3995 return MCValue{ .memory = got_addr };
3996 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
3997 try p9.seeDecl(decl);
3998 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
3999 return MCValue{ .memory = got_addr };
4000 } else {
4001 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
4002 }
4003
4004 _ = tv;
4005}
4006
3980fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {4007fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
3981 if (typed_value.val.isUndef())4008 if (typed_value.val.isUndef())
3982 return MCValue{ .undef = {} };4009 return MCValue{ .undef = {} };
3983 const ptr_bits = self.target.cpu.arch.ptrBitWidth();4010 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
3984 const ptr_bytes: u64 = @divExact(ptr_bits, 8);4011
4012 if (typed_value.val.castTag(.decl_ref)) |payload| {
4013 return self.lowerDeclRef(typed_value, payload.data);
4014 }
4015 if (typed_value.val.castTag(.decl_ref_mut)) |payload| {
4016 return self.lowerDeclRef(typed_value, payload.data.decl);
4017 }
4018
3985 switch (typed_value.ty.zigTypeTag()) {4019 switch (typed_value.ty.zigTypeTag()) {
3986 .Pointer => switch (typed_value.ty.ptrSize()) {4020 .Pointer => switch (typed_value.ty.ptrSize()) {
3987 .Slice => {4021 .Slice => {
...@@ -3998,28 +4032,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -3998,28 +4032,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
3998 return self.fail("TODO codegen for const slices", .{});4032 return self.fail("TODO codegen for const slices", .{});
3999 },4033 },
4000 else => {4034 else => {
4001 if (typed_value.val.castTag(.decl_ref)) |payload| {
4002 const decl = payload.data;
4003 decl.alive = true;
4004 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4005 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
4006 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
4007 return MCValue{ .memory = got_addr };
4008 } else if (self.bin_file.cast(link.File.MachO)) |_| {
4009 // TODO I'm hacking my way through here by repurposing .memory for storing
4010 // index to the GOT target symbol index.
4011 return MCValue{ .memory = decl.link.macho.local_sym_index };
4012 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
4013 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
4014 return MCValue{ .memory = got_addr };
4015 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
4016 try p9.seeDecl(decl);
4017 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
4018 return MCValue{ .memory = got_addr };
4019 } else {
4020 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
4021 }
4022 }
4023 if (typed_value.val.tag() == .int_u64) {4035 if (typed_value.val.tag() == .int_u64) {
4024 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };4036 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
4025 }4037 }
...@@ -4091,7 +4103,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -4091,7 +4103,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
4091 const payload_type = typed_value.ty.errorUnionPayload();4103 const payload_type = typed_value.ty.errorUnionPayload();
40924104
4093 if (typed_value.val.castTag(.eu_payload)) |pl| {4105 if (typed_value.val.castTag(.eu_payload)) |pl| {
4094 if (!payload_type.hasCodeGenBits()) {4106 if (!payload_type.hasRuntimeBits()) {
4095 // We use the error type directly as the type.4107 // We use the error type directly as the type.
4096 return MCValue{ .immediate = 0 };4108 return MCValue{ .immediate = 0 };
4097 }4109 }
...@@ -4099,7 +4111,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -4099,7 +4111,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
4099 _ = pl;4111 _ = pl;
4100 return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty});4112 return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty});
4101 } else {4113 } else {
4102 if (!payload_type.hasCodeGenBits()) {4114 if (!payload_type.hasRuntimeBits()) {
4103 // We use the error type directly as the type.4115 // We use the error type directly as the type.
4104 return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val });4116 return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val });
4105 }4117 }
...@@ -4156,7 +4168,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -4156,7 +4168,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
4156 var by_reg = std.AutoHashMap(usize, usize).init(self.bin_file.allocator);4168 var by_reg = std.AutoHashMap(usize, usize).init(self.bin_file.allocator);
4157 defer by_reg.deinit();4169 defer by_reg.deinit();
4158 for (param_types) |ty, i| {4170 for (param_types) |ty, i| {
4159 if (!ty.hasCodeGenBits()) continue;4171 if (!ty.hasRuntimeBits()) continue;
4160 const param_size = @intCast(u32, ty.abiSize(self.target.*));4172 const param_size = @intCast(u32, ty.abiSize(self.target.*));
4161 const pass_in_reg = switch (ty.zigTypeTag()) {4173 const pass_in_reg = switch (ty.zigTypeTag()) {
4162 .Bool => true,4174 .Bool => true,
...@@ -4178,7 +4190,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -4178,7 +4190,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
4178 // for (param_types) |ty, i| {4190 // for (param_types) |ty, i| {
4179 const i = count - 1;4191 const i = count - 1;
4180 const ty = param_types[i];4192 const ty = param_types[i];
4181 if (!ty.hasCodeGenBits()) {4193 if (!ty.hasRuntimeBits()) {
4182 assert(cc != .C);4194 assert(cc != .C);
4183 result.args[i] = .{ .none = {} };4195 result.args[i] = .{ .none = {} };
4184 continue;4196 continue;
...@@ -4207,7 +4219,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -4207,7 +4219,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
42074219
4208 if (ret_ty.zigTypeTag() == .NoReturn) {4220 if (ret_ty.zigTypeTag() == .NoReturn) {
4209 result.return_value = .{ .unreach = {} };4221 result.return_value = .{ .unreach = {} };
4210 } else if (!ret_ty.hasCodeGenBits()) {4222 } else if (!ret_ty.hasRuntimeBits()) {
4211 result.return_value = .{ .none = {} };4223 result.return_value = .{ .none = {} };
4212 } else switch (cc) {4224 } else switch (cc) {
4213 .Naked => unreachable,4225 .Naked => unreachable,
src/arch/x86_64/Emit.zig+1-1
...@@ -885,7 +885,7 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue) !void {...@@ -885,7 +885,7 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue) !void {
885fn addDbgInfoTypeReloc(emit: *Emit, ty: Type) !void {885fn addDbgInfoTypeReloc(emit: *Emit, ty: Type) !void {
886 switch (emit.debug_output) {886 switch (emit.debug_output) {
887 .dwarf => |dbg_out| {887 .dwarf => |dbg_out| {
888 assert(ty.hasCodeGenBits());888 assert(ty.hasRuntimeBits());
889 const index = dbg_out.dbg_info.items.len;889 const index = dbg_out.dbg_info.items.len;
890 try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4890 try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
891891
src/codegen.zig+1-1
...@@ -377,7 +377,7 @@ pub fn generateSymbol(...@@ -377,7 +377,7 @@ pub fn generateSymbol(
377 const field_vals = typed_value.val.castTag(.@"struct").?.data;377 const field_vals = typed_value.val.castTag(.@"struct").?.data;
378 for (field_vals) |field_val, index| {378 for (field_vals) |field_val, index| {
379 const field_ty = typed_value.ty.structFieldType(index);379 const field_ty = typed_value.ty.structFieldType(index);
380 if (!field_ty.hasCodeGenBits()) continue;380 if (!field_ty.hasRuntimeBits()) continue;
381 switch (try generateSymbol(bin_file, src_loc, .{381 switch (try generateSymbol(bin_file, src_loc, .{
382 .ty = field_ty,382 .ty = field_ty,
383 .val = field_val,383 .val = field_val,
src/codegen/c.zig+14-14
...@@ -507,7 +507,7 @@ pub const DeclGen = struct {...@@ -507,7 +507,7 @@ pub const DeclGen = struct {
507 const error_type = ty.errorUnionSet();507 const error_type = ty.errorUnionSet();
508 const payload_type = ty.errorUnionPayload();508 const payload_type = ty.errorUnionPayload();
509509
510 if (!payload_type.hasCodeGenBits()) {510 if (!payload_type.hasRuntimeBits()) {
511 // We use the error type directly as the type.511 // We use the error type directly as the type.
512 const err_val = if (val.errorUnionIsPayload()) Value.initTag(.zero) else val;512 const err_val = if (val.errorUnionIsPayload()) Value.initTag(.zero) else val;
513 return dg.renderValue(writer, error_type, err_val);513 return dg.renderValue(writer, error_type, err_val);
...@@ -581,7 +581,7 @@ pub const DeclGen = struct {...@@ -581,7 +581,7 @@ pub const DeclGen = struct {
581581
582 for (field_vals) |field_val, i| {582 for (field_vals) |field_val, i| {
583 const field_ty = ty.structFieldType(i);583 const field_ty = ty.structFieldType(i);
584 if (!field_ty.hasCodeGenBits()) continue;584 if (!field_ty.hasRuntimeBits()) continue;
585585
586 if (i != 0) try writer.writeAll(",");586 if (i != 0) try writer.writeAll(",");
587 try dg.renderValue(writer, field_ty, field_val);587 try dg.renderValue(writer, field_ty, field_val);
...@@ -611,7 +611,7 @@ pub const DeclGen = struct {...@@ -611,7 +611,7 @@ pub const DeclGen = struct {
611 const index = union_ty.tag_ty.enumTagFieldIndex(union_obj.tag).?;611 const index = union_ty.tag_ty.enumTagFieldIndex(union_obj.tag).?;
612 const field_ty = ty.unionFields().values()[index].ty;612 const field_ty = ty.unionFields().values()[index].ty;
613 const field_name = ty.unionFields().keys()[index];613 const field_name = ty.unionFields().keys()[index];
614 if (field_ty.hasCodeGenBits()) {614 if (field_ty.hasRuntimeBits()) {
615 try writer.print(".{} = ", .{fmtIdent(field_name)});615 try writer.print(".{} = ", .{fmtIdent(field_name)});
616 try dg.renderValue(writer, field_ty, union_obj.val);616 try dg.renderValue(writer, field_ty, union_obj.val);
617 }617 }
...@@ -652,7 +652,7 @@ pub const DeclGen = struct {...@@ -652,7 +652,7 @@ pub const DeclGen = struct {
652 }652 }
653 }653 }
654 const return_ty = dg.decl.ty.fnReturnType();654 const return_ty = dg.decl.ty.fnReturnType();
655 if (return_ty.hasCodeGenBits()) {655 if (return_ty.hasRuntimeBits()) {
656 try dg.renderType(w, return_ty);656 try dg.renderType(w, return_ty);
657 } else if (return_ty.zigTypeTag() == .NoReturn) {657 } else if (return_ty.zigTypeTag() == .NoReturn) {
658 try w.writeAll("zig_noreturn void");658 try w.writeAll("zig_noreturn void");
...@@ -784,7 +784,7 @@ pub const DeclGen = struct {...@@ -784,7 +784,7 @@ pub const DeclGen = struct {
784 var it = struct_obj.fields.iterator();784 var it = struct_obj.fields.iterator();
785 while (it.next()) |entry| {785 while (it.next()) |entry| {
786 const field_ty = entry.value_ptr.ty;786 const field_ty = entry.value_ptr.ty;
787 if (!field_ty.hasCodeGenBits()) continue;787 if (!field_ty.hasRuntimeBits()) continue;
788788
789 const alignment = entry.value_ptr.abi_align;789 const alignment = entry.value_ptr.abi_align;
790 const name: CValue = .{ .identifier = entry.key_ptr.* };790 const name: CValue = .{ .identifier = entry.key_ptr.* };
...@@ -837,7 +837,7 @@ pub const DeclGen = struct {...@@ -837,7 +837,7 @@ pub const DeclGen = struct {
837 var it = t.unionFields().iterator();837 var it = t.unionFields().iterator();
838 while (it.next()) |entry| {838 while (it.next()) |entry| {
839 const field_ty = entry.value_ptr.ty;839 const field_ty = entry.value_ptr.ty;
840 if (!field_ty.hasCodeGenBits()) continue;840 if (!field_ty.hasRuntimeBits()) continue;
841 const alignment = entry.value_ptr.abi_align;841 const alignment = entry.value_ptr.abi_align;
842 const name: CValue = .{ .identifier = entry.key_ptr.* };842 const name: CValue = .{ .identifier = entry.key_ptr.* };
843 try buffer.append(' ');843 try buffer.append(' ');
...@@ -1582,7 +1582,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -1582,7 +1582,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
15821582
1583 const elem_type = inst_ty.elemType();1583 const elem_type = inst_ty.elemType();
1584 const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;1584 const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;
1585 if (!elem_type.hasCodeGenBits()) {1585 if (!elem_type.isFnOrHasRuntimeBits()) {
1586 const target = f.object.dg.module.getTarget();1586 const target = f.object.dg.module.getTarget();
1587 const literal = switch (target.cpu.arch.ptrBitWidth()) {1587 const literal = switch (target.cpu.arch.ptrBitWidth()) {
1588 32 => "(void *)0xaaaaaaaa",1588 32 => "(void *)0xaaaaaaaa",
...@@ -1683,7 +1683,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -1683,7 +1683,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
1683fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {1683fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {
1684 const un_op = f.air.instructions.items(.data)[inst].un_op;1684 const un_op = f.air.instructions.items(.data)[inst].un_op;
1685 const writer = f.object.writer();1685 const writer = f.object.writer();
1686 if (f.air.typeOf(un_op).hasCodeGenBits()) {1686 if (f.air.typeOf(un_op).isFnOrHasRuntimeBits()) {
1687 const operand = try f.resolveInst(un_op);1687 const operand = try f.resolveInst(un_op);
1688 try writer.writeAll("return ");1688 try writer.writeAll("return ");
1689 try f.writeCValue(writer, operand);1689 try f.writeCValue(writer, operand);
...@@ -1699,7 +1699,7 @@ fn airRetLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -1699,7 +1699,7 @@ fn airRetLoad(f: *Function, inst: Air.Inst.Index) !CValue {
1699 const writer = f.object.writer();1699 const writer = f.object.writer();
1700 const ptr_ty = f.air.typeOf(un_op);1700 const ptr_ty = f.air.typeOf(un_op);
1701 const ret_ty = ptr_ty.childType();1701 const ret_ty = ptr_ty.childType();
1702 if (!ret_ty.hasCodeGenBits()) {1702 if (!ret_ty.isFnOrHasRuntimeBits()) {
1703 try writer.writeAll("return;\n");1703 try writer.writeAll("return;\n");
1704 }1704 }
1705 const ptr = try f.resolveInst(un_op);1705 const ptr = try f.resolveInst(un_op);
...@@ -2315,7 +2315,7 @@ fn airCall(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2315,7 +2315,7 @@ fn airCall(f: *Function, inst: Air.Inst.Index) !CValue {
23152315
2316 var result_local: CValue = .none;2316 var result_local: CValue = .none;
2317 if (unused_result) {2317 if (unused_result) {
2318 if (ret_ty.hasCodeGenBits()) {2318 if (ret_ty.hasRuntimeBits()) {
2319 try writer.print("(void)", .{});2319 try writer.print("(void)", .{});
2320 }2320 }
2321 } else {2321 } else {
...@@ -2832,7 +2832,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2832,7 +2832,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
2832 const operand_ty = f.air.typeOf(ty_op.operand);2832 const operand_ty = f.air.typeOf(ty_op.operand);
28332833
2834 const payload_ty = operand_ty.errorUnionPayload();2834 const payload_ty = operand_ty.errorUnionPayload();
2835 if (!payload_ty.hasCodeGenBits()) {2835 if (!payload_ty.hasRuntimeBits()) {
2836 if (operand_ty.zigTypeTag() == .Pointer) {2836 if (operand_ty.zigTypeTag() == .Pointer) {
2837 const local = try f.allocLocal(inst_ty, .Const);2837 const local = try f.allocLocal(inst_ty, .Const);
2838 try writer.writeAll(" = *");2838 try writer.writeAll(" = *");
...@@ -2864,7 +2864,7 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []cons...@@ -2864,7 +2864,7 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []cons
2864 const operand_ty = f.air.typeOf(ty_op.operand);2864 const operand_ty = f.air.typeOf(ty_op.operand);
28652865
2866 const payload_ty = operand_ty.errorUnionPayload();2866 const payload_ty = operand_ty.errorUnionPayload();
2867 if (!payload_ty.hasCodeGenBits()) {2867 if (!payload_ty.hasRuntimeBits()) {
2868 return CValue.none;2868 return CValue.none;
2869 }2869 }
28702870
...@@ -2908,7 +2908,7 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2908,7 +2908,7 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
2908 const operand = try f.resolveInst(ty_op.operand);2908 const operand = try f.resolveInst(ty_op.operand);
2909 const err_un_ty = f.air.typeOfIndex(inst);2909 const err_un_ty = f.air.typeOfIndex(inst);
2910 const payload_ty = err_un_ty.errorUnionPayload();2910 const payload_ty = err_un_ty.errorUnionPayload();
2911 if (!payload_ty.hasCodeGenBits()) {2911 if (!payload_ty.hasRuntimeBits()) {
2912 return operand;2912 return operand;
2913 }2913 }
29142914
...@@ -2951,7 +2951,7 @@ fn airIsErr(...@@ -2951,7 +2951,7 @@ fn airIsErr(
2951 const operand_ty = f.air.typeOf(un_op);2951 const operand_ty = f.air.typeOf(un_op);
2952 const local = try f.allocLocal(Type.initTag(.bool), .Const);2952 const local = try f.allocLocal(Type.initTag(.bool), .Const);
2953 const payload_ty = operand_ty.errorUnionPayload();2953 const payload_ty = operand_ty.errorUnionPayload();
2954 if (!payload_ty.hasCodeGenBits()) {2954 if (!payload_ty.hasRuntimeBits()) {
2955 try writer.print(" = {s}", .{deref_prefix});2955 try writer.print(" = {s}", .{deref_prefix});
2956 try f.writeCValue(writer, operand);2956 try f.writeCValue(writer, operand);
2957 try writer.print(" {s} 0;\n", .{op_str});2957 try writer.print(" {s} 0;\n", .{op_str});
src/codegen/llvm.zig+90-71
...@@ -176,7 +176,7 @@ pub const Object = struct {...@@ -176,7 +176,7 @@ pub const Object = struct {
176 /// the compiler, but the Type/Value memory here is backed by `type_map_arena`.176 /// the compiler, but the Type/Value memory here is backed by `type_map_arena`.
177 /// TODO we need to remove entries from this map in response to incremental compilation177 /// TODO we need to remove entries from this map in response to incremental compilation
178 /// but I think the frontend won't tell us about types that get deleted because178 /// but I think the frontend won't tell us about types that get deleted because
179 /// hasCodeGenBits() is false for types.179 /// hasRuntimeBits() is false for types.
180 type_map: TypeMap,180 type_map: TypeMap,
181 /// The backing memory for `type_map`. Periodically garbage collected after flush().181 /// The backing memory for `type_map`. Periodically garbage collected after flush().
182 /// The code for doing the periodical GC is not yet implemented.182 /// The code for doing the periodical GC is not yet implemented.
...@@ -463,7 +463,7 @@ pub const Object = struct {...@@ -463,7 +463,7 @@ pub const Object = struct {
463463
464 const param_offset: c_uint = @boolToInt(ret_ptr != null);464 const param_offset: c_uint = @boolToInt(ret_ptr != null);
465 for (fn_info.param_types) |param_ty| {465 for (fn_info.param_types) |param_ty| {
466 if (!param_ty.hasCodeGenBits()) continue;466 if (!param_ty.hasRuntimeBits()) continue;
467467
468 const llvm_arg_i = @intCast(c_uint, args.items.len) + param_offset;468 const llvm_arg_i = @intCast(c_uint, args.items.len) + param_offset;
469 try args.append(llvm_func.getParam(llvm_arg_i));469 try args.append(llvm_func.getParam(llvm_arg_i));
...@@ -662,6 +662,7 @@ pub const DeclGen = struct {...@@ -662,6 +662,7 @@ pub const DeclGen = struct {
662 new_global.setAlignment(global.getAlignment());662 new_global.setAlignment(global.getAlignment());
663 new_global.setInitializer(llvm_init);663 new_global.setInitializer(llvm_init);
664 global.replaceAllUsesWith(new_global);664 global.replaceAllUsesWith(new_global);
665 dg.object.decl_map.putAssumeCapacity(decl, new_global);
665 new_global.takeName(global);666 new_global.takeName(global);
666 global.deleteGlobal();667 global.deleteGlobal();
667 }668 }
...@@ -709,7 +710,7 @@ pub const DeclGen = struct {...@@ -709,7 +710,7 @@ pub const DeclGen = struct {
709 // Set parameter attributes.710 // Set parameter attributes.
710 var llvm_param_i: c_uint = @boolToInt(sret);711 var llvm_param_i: c_uint = @boolToInt(sret);
711 for (fn_info.param_types) |param_ty| {712 for (fn_info.param_types) |param_ty| {
712 if (!param_ty.hasCodeGenBits()) continue;713 if (!param_ty.hasRuntimeBits()) continue;
713714
714 if (isByRef(param_ty)) {715 if (isByRef(param_ty)) {
715 dg.addArgAttr(llvm_fn, llvm_param_i, "nonnull");716 dg.addArgAttr(llvm_fn, llvm_param_i, "nonnull");
...@@ -725,6 +726,10 @@ pub const DeclGen = struct {...@@ -725,6 +726,10 @@ pub const DeclGen = struct {
725 llvm_fn.setFunctionCallConv(toLlvmCallConv(fn_info.cc, target));726 llvm_fn.setFunctionCallConv(toLlvmCallConv(fn_info.cc, target));
726 }727 }
727728
729 if (fn_info.alignment != 0) {
730 llvm_fn.setAlignment(fn_info.alignment);
731 }
732
728 // Function attributes that are independent of analysis results of the function body.733 // Function attributes that are independent of analysis results of the function body.
729 dg.addCommonFnAttributes(llvm_fn);734 dg.addCommonFnAttributes(llvm_fn);
730735
...@@ -840,7 +845,11 @@ pub const DeclGen = struct {...@@ -840,7 +845,11 @@ pub const DeclGen = struct {
840 }845 }
841 const llvm_addrspace = dg.llvmAddressSpace(t.ptrAddressSpace());846 const llvm_addrspace = dg.llvmAddressSpace(t.ptrAddressSpace());
842 const elem_ty = t.childType();847 const elem_ty = t.childType();
843 const llvm_elem_ty = if (elem_ty.hasCodeGenBits() or elem_ty.zigTypeTag() == .Array)848 const lower_elem_ty = switch (elem_ty.zigTypeTag()) {
849 .Opaque, .Array, .Fn => true,
850 else => elem_ty.hasRuntimeBits(),
851 };
852 const llvm_elem_ty = if (lower_elem_ty)
844 try dg.llvmType(elem_ty)853 try dg.llvmType(elem_ty)
845 else854 else
846 dg.context.intType(8);855 dg.context.intType(8);
...@@ -878,13 +887,13 @@ pub const DeclGen = struct {...@@ -878,13 +887,13 @@ pub const DeclGen = struct {
878 .Optional => {887 .Optional => {
879 var buf: Type.Payload.ElemType = undefined;888 var buf: Type.Payload.ElemType = undefined;
880 const child_type = t.optionalChild(&buf);889 const child_type = t.optionalChild(&buf);
881 if (!child_type.hasCodeGenBits()) {890 if (!child_type.hasRuntimeBits()) {
882 return dg.context.intType(1);891 return dg.context.intType(1);
883 }892 }
884 const payload_llvm_ty = try dg.llvmType(child_type);893 const payload_llvm_ty = try dg.llvmType(child_type);
885 if (t.isPtrLikeOptional()) {894 if (t.isPtrLikeOptional()) {
886 return payload_llvm_ty;895 return payload_llvm_ty;
887 } else if (!child_type.hasCodeGenBits()) {896 } else if (!child_type.hasRuntimeBits()) {
888 return dg.context.intType(1);897 return dg.context.intType(1);
889 }898 }
890899
...@@ -897,7 +906,7 @@ pub const DeclGen = struct {...@@ -897,7 +906,7 @@ pub const DeclGen = struct {
897 const error_type = t.errorUnionSet();906 const error_type = t.errorUnionSet();
898 const payload_type = t.errorUnionPayload();907 const payload_type = t.errorUnionPayload();
899 const llvm_error_type = try dg.llvmType(error_type);908 const llvm_error_type = try dg.llvmType(error_type);
900 if (!payload_type.hasCodeGenBits()) {909 if (!payload_type.hasRuntimeBits()) {
901 return llvm_error_type;910 return llvm_error_type;
902 }911 }
903 const llvm_payload_type = try dg.llvmType(payload_type);912 const llvm_payload_type = try dg.llvmType(payload_type);
...@@ -962,7 +971,7 @@ pub const DeclGen = struct {...@@ -962,7 +971,7 @@ pub const DeclGen = struct {
962 var big_align: u32 = 0;971 var big_align: u32 = 0;
963 var running_bits: u16 = 0;972 var running_bits: u16 = 0;
964 for (struct_obj.fields.values()) |field| {973 for (struct_obj.fields.values()) |field| {
965 if (!field.ty.hasCodeGenBits()) continue;974 if (!field.ty.hasRuntimeBits()) continue;
966975
967 const field_align = field.packedAlignment();976 const field_align = field.packedAlignment();
968 if (field_align == 0) {977 if (field_align == 0) {
...@@ -1029,7 +1038,7 @@ pub const DeclGen = struct {...@@ -1029,7 +1038,7 @@ pub const DeclGen = struct {
1029 }1038 }
1030 } else {1039 } else {
1031 for (struct_obj.fields.values()) |field| {1040 for (struct_obj.fields.values()) |field| {
1032 if (!field.ty.hasCodeGenBits()) continue;1041 if (!field.ty.hasRuntimeBits()) continue;
1033 llvm_field_types.appendAssumeCapacity(try dg.llvmType(field.ty));1042 llvm_field_types.appendAssumeCapacity(try dg.llvmType(field.ty));
1034 }1043 }
1035 }1044 }
...@@ -1123,7 +1132,7 @@ pub const DeclGen = struct {...@@ -1123,7 +1132,7 @@ pub const DeclGen = struct {
1123 const sret = firstParamSRet(fn_info, target);1132 const sret = firstParamSRet(fn_info, target);
1124 const return_type = fn_info.return_type;1133 const return_type = fn_info.return_type;
1125 const raw_llvm_ret_ty = try dg.llvmType(return_type);1134 const raw_llvm_ret_ty = try dg.llvmType(return_type);
1126 const llvm_ret_ty = if (!return_type.hasCodeGenBits() or sret)1135 const llvm_ret_ty = if (!return_type.hasRuntimeBits() or sret)
1127 dg.context.voidType()1136 dg.context.voidType()
1128 else1137 else
1129 raw_llvm_ret_ty;1138 raw_llvm_ret_ty;
...@@ -1136,7 +1145,7 @@ pub const DeclGen = struct {...@@ -1136,7 +1145,7 @@ pub const DeclGen = struct {
1136 }1145 }
11371146
1138 for (fn_info.param_types) |param_ty| {1147 for (fn_info.param_types) |param_ty| {
1139 if (!param_ty.hasCodeGenBits()) continue;1148 if (!param_ty.hasRuntimeBits()) continue;
11401149
1141 const raw_llvm_ty = try dg.llvmType(param_ty);1150 const raw_llvm_ty = try dg.llvmType(param_ty);
1142 const actual_llvm_ty = if (!isByRef(param_ty)) raw_llvm_ty else raw_llvm_ty.pointerType(0);1151 const actual_llvm_ty = if (!isByRef(param_ty)) raw_llvm_ty else raw_llvm_ty.pointerType(0);
...@@ -1176,29 +1185,35 @@ pub const DeclGen = struct {...@@ -1176,29 +1185,35 @@ pub const DeclGen = struct {
1176 const llvm_type = try dg.llvmType(tv.ty);1185 const llvm_type = try dg.llvmType(tv.ty);
1177 return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull();1186 return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull();
1178 },1187 },
1179 .Int => {1188 // TODO this duplicates code with Pointer but they should share the handling
1180 var bigint_space: Value.BigIntSpace = undefined;1189 // of the tv.val.tag() and then Int should do extra constPtrToInt on top
1181 const bigint = tv.val.toBigInt(&bigint_space);1190 .Int => switch (tv.val.tag()) {
1182 const target = dg.module.getTarget();1191 .decl_ref_mut => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref_mut).?.data.decl),
1183 const int_info = tv.ty.intInfo(target);1192 .decl_ref => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref).?.data),
1184 const llvm_type = dg.context.intType(int_info.bits);1193 else => {
1194 var bigint_space: Value.BigIntSpace = undefined;
1195 const bigint = tv.val.toBigInt(&bigint_space);
1196 const target = dg.module.getTarget();
1197 const int_info = tv.ty.intInfo(target);
1198 const llvm_type = dg.context.intType(int_info.bits);
11851199
1186 const unsigned_val = v: {1200 const unsigned_val = v: {
1187 if (bigint.limbs.len == 1) {1201 if (bigint.limbs.len == 1) {
1188 break :v llvm_type.constInt(bigint.limbs[0], .False);1202 break :v llvm_type.constInt(bigint.limbs[0], .False);
1189 }1203 }
1190 if (@sizeOf(usize) == @sizeOf(u64)) {1204 if (@sizeOf(usize) == @sizeOf(u64)) {
1191 break :v llvm_type.constIntOfArbitraryPrecision(1205 break :v llvm_type.constIntOfArbitraryPrecision(
1192 @intCast(c_uint, bigint.limbs.len),1206 @intCast(c_uint, bigint.limbs.len),
1193 bigint.limbs.ptr,1207 bigint.limbs.ptr,
1194 );1208 );
1209 }
1210 @panic("TODO implement bigint to llvm int for 32-bit compiler builds");
1211 };
1212 if (!bigint.positive) {
1213 return llvm.constNeg(unsigned_val);
1195 }1214 }
1196 @panic("TODO implement bigint to llvm int for 32-bit compiler builds");1215 return unsigned_val;
1197 };1216 },
1198 if (!bigint.positive) {
1199 return llvm.constNeg(unsigned_val);
1200 }
1201 return unsigned_val;
1202 },1217 },
1203 .Enum => {1218 .Enum => {
1204 var int_buffer: Value.Payload.U64 = undefined;1219 var int_buffer: Value.Payload.U64 = undefined;
...@@ -1370,7 +1385,7 @@ pub const DeclGen = struct {...@@ -1370,7 +1385,7 @@ pub const DeclGen = struct {
1370 const llvm_i1 = dg.context.intType(1);1385 const llvm_i1 = dg.context.intType(1);
1371 const is_pl = !tv.val.isNull();1386 const is_pl = !tv.val.isNull();
1372 const non_null_bit = if (is_pl) llvm_i1.constAllOnes() else llvm_i1.constNull();1387 const non_null_bit = if (is_pl) llvm_i1.constAllOnes() else llvm_i1.constNull();
1373 if (!payload_ty.hasCodeGenBits()) {1388 if (!payload_ty.hasRuntimeBits()) {
1374 return non_null_bit;1389 return non_null_bit;
1375 }1390 }
1376 if (tv.ty.isPtrLikeOptional()) {1391 if (tv.ty.isPtrLikeOptional()) {
...@@ -1383,6 +1398,7 @@ pub const DeclGen = struct {...@@ -1383,6 +1398,7 @@ pub const DeclGen = struct {
1383 return llvm_ty.constNull();1398 return llvm_ty.constNull();
1384 }1399 }
1385 }1400 }
1401 assert(payload_ty.zigTypeTag() != .Fn);
1386 const fields: [2]*const llvm.Value = .{1402 const fields: [2]*const llvm.Value = .{
1387 try dg.genTypedValue(.{1403 try dg.genTypedValue(.{
1388 .ty = payload_ty,1404 .ty = payload_ty,
...@@ -1420,7 +1436,7 @@ pub const DeclGen = struct {...@@ -1420,7 +1436,7 @@ pub const DeclGen = struct {
1420 const payload_type = tv.ty.errorUnionPayload();1436 const payload_type = tv.ty.errorUnionPayload();
1421 const is_pl = tv.val.errorUnionIsPayload();1437 const is_pl = tv.val.errorUnionIsPayload();
14221438
1423 if (!payload_type.hasCodeGenBits()) {1439 if (!payload_type.hasRuntimeBits()) {
1424 // We use the error type directly as the type.1440 // We use the error type directly as the type.
1425 const err_val = if (!is_pl) tv.val else Value.initTag(.zero);1441 const err_val = if (!is_pl) tv.val else Value.initTag(.zero);
1426 return dg.genTypedValue(.{ .ty = error_type, .val = err_val });1442 return dg.genTypedValue(.{ .ty = error_type, .val = err_val });
...@@ -1458,7 +1474,7 @@ pub const DeclGen = struct {...@@ -1458,7 +1474,7 @@ pub const DeclGen = struct {
1458 var running_int: *const llvm.Value = llvm_struct_ty.structGetTypeAtIndex(0).constNull();1474 var running_int: *const llvm.Value = llvm_struct_ty.structGetTypeAtIndex(0).constNull();
1459 for (field_vals) |field_val, i| {1475 for (field_vals) |field_val, i| {
1460 const field = fields[i];1476 const field = fields[i];
1461 if (!field.ty.hasCodeGenBits()) continue;1477 if (!field.ty.hasRuntimeBits()) continue;
14621478
1463 const field_align = field.packedAlignment();1479 const field_align = field.packedAlignment();
1464 if (field_align == 0) {1480 if (field_align == 0) {
...@@ -1540,7 +1556,7 @@ pub const DeclGen = struct {...@@ -1540,7 +1556,7 @@ pub const DeclGen = struct {
1540 } else {1556 } else {
1541 for (field_vals) |field_val, i| {1557 for (field_vals) |field_val, i| {
1542 const field_ty = tv.ty.structFieldType(i);1558 const field_ty = tv.ty.structFieldType(i);
1543 if (!field_ty.hasCodeGenBits()) continue;1559 if (!field_ty.hasRuntimeBits()) continue;
15441560
1545 llvm_fields.appendAssumeCapacity(try dg.genTypedValue(.{1561 llvm_fields.appendAssumeCapacity(try dg.genTypedValue(.{
1546 .ty = field_ty,1562 .ty = field_ty,
...@@ -1572,7 +1588,7 @@ pub const DeclGen = struct {...@@ -1572,7 +1588,7 @@ pub const DeclGen = struct {
1572 assert(union_obj.haveFieldTypes());1588 assert(union_obj.haveFieldTypes());
1573 const field_ty = union_obj.fields.values()[field_index].ty;1589 const field_ty = union_obj.fields.values()[field_index].ty;
1574 const payload = p: {1590 const payload = p: {
1575 if (!field_ty.hasCodeGenBits()) {1591 if (!field_ty.hasRuntimeBits()) {
1576 const padding_len = @intCast(c_uint, layout.payload_size);1592 const padding_len = @intCast(c_uint, layout.payload_size);
1577 break :p dg.context.intType(8).arrayType(padding_len).getUndef();1593 break :p dg.context.intType(8).arrayType(padding_len).getUndef();
1578 }1594 }
...@@ -1784,13 +1800,14 @@ pub const DeclGen = struct {...@@ -1784,13 +1800,14 @@ pub const DeclGen = struct {
1784 return self.context.constStruct(&fields, fields.len, .False);1800 return self.context.constStruct(&fields, fields.len, .False);
1785 }1801 }
17861802
1787 if (!tv.ty.childType().hasCodeGenBits() or !decl.ty.hasCodeGenBits()) {1803 const is_fn_body = decl.ty.zigTypeTag() == .Fn;
1804 if (!is_fn_body and !decl.ty.hasRuntimeBits()) {
1788 return self.lowerPtrToVoid(tv.ty);1805 return self.lowerPtrToVoid(tv.ty);
1789 }1806 }
17901807
1791 decl.markAlive();1808 decl.markAlive();
17921809
1793 const llvm_val = if (decl.ty.zigTypeTag() == .Fn)1810 const llvm_val = if (is_fn_body)
1794 try self.resolveLlvmFunction(decl)1811 try self.resolveLlvmFunction(decl)
1795 else1812 else
1796 try self.resolveGlobalDecl(decl);1813 try self.resolveGlobalDecl(decl);
...@@ -2182,7 +2199,7 @@ pub const FuncGen = struct {...@@ -2182,7 +2199,7 @@ pub const FuncGen = struct {
2182 } else {2199 } else {
2183 for (args) |arg, i| {2200 for (args) |arg, i| {
2184 const param_ty = fn_info.param_types[i];2201 const param_ty = fn_info.param_types[i];
2185 if (!param_ty.hasCodeGenBits()) continue;2202 if (!param_ty.hasRuntimeBits()) continue;
21862203
2187 try llvm_args.append(try self.resolveInst(arg));2204 try llvm_args.append(try self.resolveInst(arg));
2188 }2205 }
...@@ -2200,7 +2217,7 @@ pub const FuncGen = struct {...@@ -2200,7 +2217,7 @@ pub const FuncGen = struct {
2200 if (return_type.isNoReturn()) {2217 if (return_type.isNoReturn()) {
2201 _ = self.builder.buildUnreachable();2218 _ = self.builder.buildUnreachable();
2202 return null;2219 return null;
2203 } else if (self.liveness.isUnused(inst) or !return_type.hasCodeGenBits()) {2220 } else if (self.liveness.isUnused(inst) or !return_type.hasRuntimeBits()) {
2204 return null;2221 return null;
2205 } else if (sret) {2222 } else if (sret) {
2206 call.setCallSret(llvm_ret_ty);2223 call.setCallSret(llvm_ret_ty);
...@@ -2224,7 +2241,7 @@ pub const FuncGen = struct {...@@ -2224,7 +2241,7 @@ pub const FuncGen = struct {
2224 _ = self.builder.buildRetVoid();2241 _ = self.builder.buildRetVoid();
2225 return null;2242 return null;
2226 }2243 }
2227 if (!ret_ty.hasCodeGenBits()) {2244 if (!ret_ty.hasRuntimeBits()) {
2228 _ = self.builder.buildRetVoid();2245 _ = self.builder.buildRetVoid();
2229 return null;2246 return null;
2230 }2247 }
...@@ -2237,7 +2254,7 @@ pub const FuncGen = struct {...@@ -2237,7 +2254,7 @@ pub const FuncGen = struct {
2237 const un_op = self.air.instructions.items(.data)[inst].un_op;2254 const un_op = self.air.instructions.items(.data)[inst].un_op;
2238 const ptr_ty = self.air.typeOf(un_op);2255 const ptr_ty = self.air.typeOf(un_op);
2239 const ret_ty = ptr_ty.childType();2256 const ret_ty = ptr_ty.childType();
2240 if (!ret_ty.hasCodeGenBits() or isByRef(ret_ty)) {2257 if (!ret_ty.hasRuntimeBits() or isByRef(ret_ty)) {
2241 _ = self.builder.buildRetVoid();2258 _ = self.builder.buildRetVoid();
2242 return null;2259 return null;
2243 }2260 }
...@@ -2273,7 +2290,7 @@ pub const FuncGen = struct {...@@ -2273,7 +2290,7 @@ pub const FuncGen = struct {
2273 .Int, .Bool, .Pointer, .ErrorSet => operand_ty,2290 .Int, .Bool, .Pointer, .ErrorSet => operand_ty,
2274 .Optional => blk: {2291 .Optional => blk: {
2275 const payload_ty = operand_ty.optionalChild(&opt_buffer);2292 const payload_ty = operand_ty.optionalChild(&opt_buffer);
2276 if (!payload_ty.hasCodeGenBits() or operand_ty.isPtrLikeOptional()) {2293 if (!payload_ty.hasRuntimeBits() or operand_ty.isPtrLikeOptional()) {
2277 break :blk operand_ty;2294 break :blk operand_ty;
2278 }2295 }
2279 // We need to emit instructions to check for equality/inequality2296 // We need to emit instructions to check for equality/inequality
...@@ -2397,7 +2414,8 @@ pub const FuncGen = struct {...@@ -2397,7 +2414,8 @@ pub const FuncGen = struct {
2397 self.builder.positionBuilderAtEnd(parent_bb);2414 self.builder.positionBuilderAtEnd(parent_bb);
23982415
2399 // If the block does not return a value, we dont have to create a phi node.2416 // If the block does not return a value, we dont have to create a phi node.
2400 if (!inst_ty.hasCodeGenBits()) return null;2417 const is_body = inst_ty.zigTypeTag() == .Fn;
2418 if (!is_body and !inst_ty.hasRuntimeBits()) return null;
24012419
2402 const raw_llvm_ty = try self.dg.llvmType(inst_ty);2420 const raw_llvm_ty = try self.dg.llvmType(inst_ty);
24032421
...@@ -2406,7 +2424,7 @@ pub const FuncGen = struct {...@@ -2406,7 +2424,7 @@ pub const FuncGen = struct {
2406 // a pointer to it. LLVM IR allows the call instruction to use function bodies instead2424 // a pointer to it. LLVM IR allows the call instruction to use function bodies instead
2407 // of function pointers, however the phi makes it a runtime value and therefore2425 // of function pointers, however the phi makes it a runtime value and therefore
2408 // the LLVM type has to be wrapped in a pointer.2426 // the LLVM type has to be wrapped in a pointer.
2409 if (inst_ty.zigTypeTag() == .Fn or isByRef(inst_ty)) {2427 if (is_body or isByRef(inst_ty)) {
2410 break :ty raw_llvm_ty.pointerType(0);2428 break :ty raw_llvm_ty.pointerType(0);
2411 }2429 }
2412 break :ty raw_llvm_ty;2430 break :ty raw_llvm_ty;
...@@ -2427,7 +2445,8 @@ pub const FuncGen = struct {...@@ -2427,7 +2445,8 @@ pub const FuncGen = struct {
24272445
2428 // If the break doesn't break a value, then we don't have to add2446 // If the break doesn't break a value, then we don't have to add
2429 // the values to the lists.2447 // the values to the lists.
2430 if (self.air.typeOf(branch.operand).hasCodeGenBits()) {2448 const operand_ty = self.air.typeOf(branch.operand);
2449 if (operand_ty.hasRuntimeBits() or operand_ty.zigTypeTag() == .Fn) {
2431 const val = try self.resolveInst(branch.operand);2450 const val = try self.resolveInst(branch.operand);
24322451
2433 // For the phi node, we need the basic blocks and the values of the2452 // For the phi node, we need the basic blocks and the values of the
...@@ -2531,7 +2550,7 @@ pub const FuncGen = struct {...@@ -2531,7 +2550,7 @@ pub const FuncGen = struct {
2531 const llvm_usize = try self.dg.llvmType(Type.usize);2550 const llvm_usize = try self.dg.llvmType(Type.usize);
2532 const len = llvm_usize.constInt(array_ty.arrayLen(), .False);2551 const len = llvm_usize.constInt(array_ty.arrayLen(), .False);
2533 const slice_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));2552 const slice_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));
2534 if (!array_ty.hasCodeGenBits()) {2553 if (!array_ty.hasRuntimeBits()) {
2535 return self.builder.buildInsertValue(slice_llvm_ty.getUndef(), len, 1, "");2554 return self.builder.buildInsertValue(slice_llvm_ty.getUndef(), len, 1, "");
2536 }2555 }
2537 const operand = try self.resolveInst(ty_op.operand);2556 const operand = try self.resolveInst(ty_op.operand);
...@@ -2662,7 +2681,7 @@ pub const FuncGen = struct {...@@ -2662,7 +2681,7 @@ pub const FuncGen = struct {
2662 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;2681 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
2663 const ptr_ty = self.air.typeOf(bin_op.lhs);2682 const ptr_ty = self.air.typeOf(bin_op.lhs);
2664 const elem_ty = ptr_ty.childType();2683 const elem_ty = ptr_ty.childType();
2665 if (!elem_ty.hasCodeGenBits()) return null;2684 if (!elem_ty.hasRuntimeBits()) return null;
26662685
2667 const base_ptr = try self.resolveInst(bin_op.lhs);2686 const base_ptr = try self.resolveInst(bin_op.lhs);
2668 const rhs = try self.resolveInst(bin_op.rhs);2687 const rhs = try self.resolveInst(bin_op.rhs);
...@@ -2709,7 +2728,7 @@ pub const FuncGen = struct {...@@ -2709,7 +2728,7 @@ pub const FuncGen = struct {
2709 const struct_llvm_val = try self.resolveInst(struct_field.struct_operand);2728 const struct_llvm_val = try self.resolveInst(struct_field.struct_operand);
2710 const field_index = struct_field.field_index;2729 const field_index = struct_field.field_index;
2711 const field_ty = struct_ty.structFieldType(field_index);2730 const field_ty = struct_ty.structFieldType(field_index);
2712 if (!field_ty.hasCodeGenBits()) {2731 if (!field_ty.hasRuntimeBits()) {
2713 return null;2732 return null;
2714 }2733 }
2715 const target = self.dg.module.getTarget();2734 const target = self.dg.module.getTarget();
...@@ -2914,7 +2933,7 @@ pub const FuncGen = struct {...@@ -2914,7 +2933,7 @@ pub const FuncGen = struct {
29142933
2915 var buf: Type.Payload.ElemType = undefined;2934 var buf: Type.Payload.ElemType = undefined;
2916 const payload_ty = optional_ty.optionalChild(&buf);2935 const payload_ty = optional_ty.optionalChild(&buf);
2917 if (!payload_ty.hasCodeGenBits()) {2936 if (!payload_ty.hasRuntimeBits()) {
2918 if (invert) {2937 if (invert) {
2919 return self.builder.buildNot(operand, "");2938 return self.builder.buildNot(operand, "");
2920 } else {2939 } else {
...@@ -2946,7 +2965,7 @@ pub const FuncGen = struct {...@@ -2946,7 +2965,7 @@ pub const FuncGen = struct {
2946 const err_set_ty = try self.dg.llvmType(Type.initTag(.anyerror));2965 const err_set_ty = try self.dg.llvmType(Type.initTag(.anyerror));
2947 const zero = err_set_ty.constNull();2966 const zero = err_set_ty.constNull();
29482967
2949 if (!payload_ty.hasCodeGenBits()) {2968 if (!payload_ty.hasRuntimeBits()) {
2950 const loaded = if (operand_is_ptr) self.builder.buildLoad(operand, "") else operand;2969 const loaded = if (operand_is_ptr) self.builder.buildLoad(operand, "") else operand;
2951 return self.builder.buildICmp(op, loaded, zero, "");2970 return self.builder.buildICmp(op, loaded, zero, "");
2952 }2971 }
...@@ -2969,7 +2988,7 @@ pub const FuncGen = struct {...@@ -2969,7 +2988,7 @@ pub const FuncGen = struct {
2969 const optional_ty = self.air.typeOf(ty_op.operand).childType();2988 const optional_ty = self.air.typeOf(ty_op.operand).childType();
2970 var buf: Type.Payload.ElemType = undefined;2989 var buf: Type.Payload.ElemType = undefined;
2971 const payload_ty = optional_ty.optionalChild(&buf);2990 const payload_ty = optional_ty.optionalChild(&buf);
2972 if (!payload_ty.hasCodeGenBits()) {2991 if (!payload_ty.hasRuntimeBits()) {
2973 // We have a pointer to a zero-bit value and we need to return2992 // We have a pointer to a zero-bit value and we need to return
2974 // a pointer to a zero-bit value.2993 // a pointer to a zero-bit value.
2975 return operand;2994 return operand;
...@@ -2993,7 +3012,7 @@ pub const FuncGen = struct {...@@ -2993,7 +3012,7 @@ pub const FuncGen = struct {
2993 var buf: Type.Payload.ElemType = undefined;3012 var buf: Type.Payload.ElemType = undefined;
2994 const payload_ty = optional_ty.optionalChild(&buf);3013 const payload_ty = optional_ty.optionalChild(&buf);
2995 const non_null_bit = self.context.intType(1).constAllOnes();3014 const non_null_bit = self.context.intType(1).constAllOnes();
2996 if (!payload_ty.hasCodeGenBits()) {3015 if (!payload_ty.hasRuntimeBits()) {
2997 // We have a pointer to a i1. We need to set it to 1 and then return the same pointer.3016 // We have a pointer to a i1. We need to set it to 1 and then return the same pointer.
2998 _ = self.builder.buildStore(non_null_bit, operand);3017 _ = self.builder.buildStore(non_null_bit, operand);
2999 return operand;3018 return operand;
...@@ -3028,7 +3047,7 @@ pub const FuncGen = struct {...@@ -3028,7 +3047,7 @@ pub const FuncGen = struct {
3028 const operand = try self.resolveInst(ty_op.operand);3047 const operand = try self.resolveInst(ty_op.operand);
3029 const optional_ty = self.air.typeOf(ty_op.operand);3048 const optional_ty = self.air.typeOf(ty_op.operand);
3030 const payload_ty = self.air.typeOfIndex(inst);3049 const payload_ty = self.air.typeOfIndex(inst);
3031 if (!payload_ty.hasCodeGenBits()) return null;3050 if (!payload_ty.hasRuntimeBits()) return null;
30323051
3033 if (optional_ty.isPtrLikeOptional()) {3052 if (optional_ty.isPtrLikeOptional()) {
3034 // Payload value is the same as the optional value.3053 // Payload value is the same as the optional value.
...@@ -3049,7 +3068,7 @@ pub const FuncGen = struct {...@@ -3049,7 +3068,7 @@ pub const FuncGen = struct {
3049 const operand = try self.resolveInst(ty_op.operand);3068 const operand = try self.resolveInst(ty_op.operand);
3050 const err_union_ty = self.air.typeOf(ty_op.operand);3069 const err_union_ty = self.air.typeOf(ty_op.operand);
3051 const payload_ty = err_union_ty.errorUnionPayload();3070 const payload_ty = err_union_ty.errorUnionPayload();
3052 if (!payload_ty.hasCodeGenBits()) return null;3071 if (!payload_ty.hasRuntimeBits()) return null;
3053 if (operand_is_ptr or isByRef(payload_ty)) {3072 if (operand_is_ptr or isByRef(payload_ty)) {
3054 return self.builder.buildStructGEP(operand, 1, "");3073 return self.builder.buildStructGEP(operand, 1, "");
3055 }3074 }
...@@ -3069,7 +3088,7 @@ pub const FuncGen = struct {...@@ -3069,7 +3088,7 @@ pub const FuncGen = struct {
3069 const operand_ty = self.air.typeOf(ty_op.operand);3088 const operand_ty = self.air.typeOf(ty_op.operand);
30703089
3071 const payload_ty = operand_ty.errorUnionPayload();3090 const payload_ty = operand_ty.errorUnionPayload();
3072 if (!payload_ty.hasCodeGenBits()) {3091 if (!payload_ty.hasRuntimeBits()) {
3073 if (!operand_is_ptr) return operand;3092 if (!operand_is_ptr) return operand;
3074 return self.builder.buildLoad(operand, "");3093 return self.builder.buildLoad(operand, "");
3075 }3094 }
...@@ -3088,7 +3107,7 @@ pub const FuncGen = struct {...@@ -3088,7 +3107,7 @@ pub const FuncGen = struct {
3088 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3107 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3089 const payload_ty = self.air.typeOf(ty_op.operand);3108 const payload_ty = self.air.typeOf(ty_op.operand);
3090 const non_null_bit = self.context.intType(1).constAllOnes();3109 const non_null_bit = self.context.intType(1).constAllOnes();
3091 if (!payload_ty.hasCodeGenBits()) return non_null_bit;3110 if (!payload_ty.hasRuntimeBits()) return non_null_bit;
3092 const operand = try self.resolveInst(ty_op.operand);3111 const operand = try self.resolveInst(ty_op.operand);
3093 const optional_ty = self.air.typeOfIndex(inst);3112 const optional_ty = self.air.typeOfIndex(inst);
3094 if (optional_ty.isPtrLikeOptional()) return operand;3113 if (optional_ty.isPtrLikeOptional()) return operand;
...@@ -3116,7 +3135,7 @@ pub const FuncGen = struct {...@@ -3116,7 +3135,7 @@ pub const FuncGen = struct {
3116 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3135 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3117 const payload_ty = self.air.typeOf(ty_op.operand);3136 const payload_ty = self.air.typeOf(ty_op.operand);
3118 const operand = try self.resolveInst(ty_op.operand);3137 const operand = try self.resolveInst(ty_op.operand);
3119 if (!payload_ty.hasCodeGenBits()) {3138 if (!payload_ty.hasRuntimeBits()) {
3120 return operand;3139 return operand;
3121 }3140 }
3122 const inst_ty = self.air.typeOfIndex(inst);3141 const inst_ty = self.air.typeOfIndex(inst);
...@@ -3147,7 +3166,7 @@ pub const FuncGen = struct {...@@ -3147,7 +3166,7 @@ pub const FuncGen = struct {
3147 const err_un_ty = self.air.typeOfIndex(inst);3166 const err_un_ty = self.air.typeOfIndex(inst);
3148 const payload_ty = err_un_ty.errorUnionPayload();3167 const payload_ty = err_un_ty.errorUnionPayload();
3149 const operand = try self.resolveInst(ty_op.operand);3168 const operand = try self.resolveInst(ty_op.operand);
3150 if (!payload_ty.hasCodeGenBits()) {3169 if (!payload_ty.hasRuntimeBits()) {
3151 return operand;3170 return operand;
3152 }3171 }
3153 const err_un_llvm_ty = try self.dg.llvmType(err_un_ty);3172 const err_un_llvm_ty = try self.dg.llvmType(err_un_ty);
...@@ -3836,7 +3855,7 @@ pub const FuncGen = struct {...@@ -3836,7 +3855,7 @@ pub const FuncGen = struct {
3836 if (self.liveness.isUnused(inst)) return null;3855 if (self.liveness.isUnused(inst)) return null;
3837 const ptr_ty = self.air.typeOfIndex(inst);3856 const ptr_ty = self.air.typeOfIndex(inst);
3838 const pointee_type = ptr_ty.childType();3857 const pointee_type = ptr_ty.childType();
3839 if (!pointee_type.hasCodeGenBits()) return self.dg.lowerPtrToVoid(ptr_ty);3858 if (!pointee_type.isFnOrHasRuntimeBits()) return self.dg.lowerPtrToVoid(ptr_ty);
38403859
3841 const pointee_llvm_ty = try self.dg.llvmType(pointee_type);3860 const pointee_llvm_ty = try self.dg.llvmType(pointee_type);
3842 const alloca_inst = self.buildAlloca(pointee_llvm_ty);3861 const alloca_inst = self.buildAlloca(pointee_llvm_ty);
...@@ -3850,7 +3869,7 @@ pub const FuncGen = struct {...@@ -3850,7 +3869,7 @@ pub const FuncGen = struct {
3850 if (self.liveness.isUnused(inst)) return null;3869 if (self.liveness.isUnused(inst)) return null;
3851 const ptr_ty = self.air.typeOfIndex(inst);3870 const ptr_ty = self.air.typeOfIndex(inst);
3852 const ret_ty = ptr_ty.childType();3871 const ret_ty = ptr_ty.childType();
3853 if (!ret_ty.hasCodeGenBits()) return null;3872 if (!ret_ty.isFnOrHasRuntimeBits()) return null;
3854 if (self.ret_ptr) |ret_ptr| return ret_ptr;3873 if (self.ret_ptr) |ret_ptr| return ret_ptr;
3855 const ret_llvm_ty = try self.dg.llvmType(ret_ty);3874 const ret_llvm_ty = try self.dg.llvmType(ret_ty);
3856 const target = self.dg.module.getTarget();3875 const target = self.dg.module.getTarget();
...@@ -4074,7 +4093,7 @@ pub const FuncGen = struct {...@@ -4074,7 +4093,7 @@ pub const FuncGen = struct {
4074 const bin_op = self.air.instructions.items(.data)[inst].bin_op;4093 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
4075 const ptr_ty = self.air.typeOf(bin_op.lhs);4094 const ptr_ty = self.air.typeOf(bin_op.lhs);
4076 const operand_ty = ptr_ty.childType();4095 const operand_ty = ptr_ty.childType();
4077 if (!operand_ty.hasCodeGenBits()) return null;4096 if (!operand_ty.isFnOrHasRuntimeBits()) return null;
4078 var ptr = try self.resolveInst(bin_op.lhs);4097 var ptr = try self.resolveInst(bin_op.lhs);
4079 var element = try self.resolveInst(bin_op.rhs);4098 var element = try self.resolveInst(bin_op.rhs);
4080 const opt_abi_ty = self.dg.getAtomicAbiType(operand_ty, false);4099 const opt_abi_ty = self.dg.getAtomicAbiType(operand_ty, false);
...@@ -4674,7 +4693,7 @@ pub const FuncGen = struct {...@@ -4674,7 +4693,7 @@ pub const FuncGen = struct {
4674 const union_obj = union_ty.cast(Type.Payload.Union).?.data;4693 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
4675 const field = &union_obj.fields.values()[field_index];4694 const field = &union_obj.fields.values()[field_index];
4676 const result_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));4695 const result_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));
4677 if (!field.ty.hasCodeGenBits()) {4696 if (!field.ty.hasRuntimeBits()) {
4678 return null;4697 return null;
4679 }4698 }
4680 const target = self.dg.module.getTarget();4699 const target = self.dg.module.getTarget();
...@@ -4702,7 +4721,7 @@ pub const FuncGen = struct {...@@ -4702,7 +4721,7 @@ pub const FuncGen = struct {
47024721
4703 fn load(self: *FuncGen, ptr: *const llvm.Value, ptr_ty: Type) !?*const llvm.Value {4722 fn load(self: *FuncGen, ptr: *const llvm.Value, ptr_ty: Type) !?*const llvm.Value {
4704 const info = ptr_ty.ptrInfo().data;4723 const info = ptr_ty.ptrInfo().data;
4705 if (!info.pointee_type.hasCodeGenBits()) return null;4724 if (!info.pointee_type.hasRuntimeBits()) return null;
47064725
4707 const target = self.dg.module.getTarget();4726 const target = self.dg.module.getTarget();
4708 const ptr_alignment = ptr_ty.ptrAlignment(target);4727 const ptr_alignment = ptr_ty.ptrAlignment(target);
...@@ -4757,7 +4776,7 @@ pub const FuncGen = struct {...@@ -4757,7 +4776,7 @@ pub const FuncGen = struct {
4757 ) void {4776 ) void {
4758 const info = ptr_ty.ptrInfo().data;4777 const info = ptr_ty.ptrInfo().data;
4759 const elem_ty = info.pointee_type;4778 const elem_ty = info.pointee_type;
4760 if (!elem_ty.hasCodeGenBits()) {4779 if (!elem_ty.isFnOrHasRuntimeBits()) {
4761 return;4780 return;
4762 }4781 }
4763 const target = self.dg.module.getTarget();4782 const target = self.dg.module.getTarget();
...@@ -5087,7 +5106,7 @@ fn llvmFieldIndex(...@@ -5087,7 +5106,7 @@ fn llvmFieldIndex(
5087 if (struct_obj.layout != .Packed) {5106 if (struct_obj.layout != .Packed) {
5088 var llvm_field_index: c_uint = 0;5107 var llvm_field_index: c_uint = 0;
5089 for (struct_obj.fields.values()) |field, i| {5108 for (struct_obj.fields.values()) |field, i| {
5090 if (!field.ty.hasCodeGenBits())5109 if (!field.ty.hasRuntimeBits())
5091 continue;5110 continue;
5092 if (field_index > i) {5111 if (field_index > i) {
5093 llvm_field_index += 1;5112 llvm_field_index += 1;
...@@ -5114,7 +5133,7 @@ fn llvmFieldIndex(...@@ -5114,7 +5133,7 @@ fn llvmFieldIndex(
5114 var running_bits: u16 = 0;5133 var running_bits: u16 = 0;
5115 var llvm_field_index: c_uint = 0;5134 var llvm_field_index: c_uint = 0;
5116 for (struct_obj.fields.values()) |field, i| {5135 for (struct_obj.fields.values()) |field, i| {
5117 if (!field.ty.hasCodeGenBits())5136 if (!field.ty.hasRuntimeBits())
5118 continue;5137 continue;
51195138
5120 const field_align = field.packedAlignment();5139 const field_align = field.packedAlignment();
...@@ -5227,9 +5246,9 @@ fn isByRef(ty: Type) bool {...@@ -5227,9 +5246,9 @@ fn isByRef(ty: Type) bool {
5227 .AnyFrame,5246 .AnyFrame,
5228 => return false,5247 => return false,
52295248
5230 .Array, .Frame => return ty.hasCodeGenBits(),5249 .Array, .Frame => return ty.hasRuntimeBits(),
5231 .Struct => {5250 .Struct => {
5232 if (!ty.hasCodeGenBits()) return false;5251 if (!ty.hasRuntimeBits()) return false;
5233 if (ty.castTag(.tuple)) |tuple| {5252 if (ty.castTag(.tuple)) |tuple| {
5234 var count: usize = 0;5253 var count: usize = 0;
5235 for (tuple.data.values) |field_val, i| {5254 for (tuple.data.values) |field_val, i| {
...@@ -5247,7 +5266,7 @@ fn isByRef(ty: Type) bool {...@@ -5247,7 +5266,7 @@ fn isByRef(ty: Type) bool {
5247 }5266 }
5248 return true;5267 return true;
5249 },5268 },
5250 .Union => return ty.hasCodeGenBits(),5269 .Union => return ty.hasRuntimeBits(),
5251 .ErrorUnion => return isByRef(ty.errorUnionPayload()),5270 .ErrorUnion => return isByRef(ty.errorUnionPayload()),
5252 .Optional => {5271 .Optional => {
5253 var buf: Type.Payload.ElemType = undefined;5272 var buf: Type.Payload.ElemType = undefined;
src/codegen/spirv.zig+3-3
...@@ -852,7 +852,7 @@ pub const DeclGen = struct {...@@ -852,7 +852,7 @@ pub const DeclGen = struct {
852 try self.beginSPIRVBlock(label_id);852 try self.beginSPIRVBlock(label_id);
853853
854 // If this block didn't produce a value, simply return here.854 // If this block didn't produce a value, simply return here.
855 if (!ty.hasCodeGenBits())855 if (!ty.hasRuntimeBits())
856 return null;856 return null;
857857
858 // Combine the result from the blocks using the Phi instruction.858 // Combine the result from the blocks using the Phi instruction.
...@@ -879,7 +879,7 @@ pub const DeclGen = struct {...@@ -879,7 +879,7 @@ pub const DeclGen = struct {
879 const block = self.blocks.get(br.block_inst).?;879 const block = self.blocks.get(br.block_inst).?;
880 const operand_ty = self.air.typeOf(br.operand);880 const operand_ty = self.air.typeOf(br.operand);
881881
882 if (operand_ty.hasCodeGenBits()) {882 if (operand_ty.hasRuntimeBits()) {
883 const operand_id = try self.resolve(br.operand);883 const operand_id = try self.resolve(br.operand);
884 // current_block_label_id should not be undefined here, lest there is a br or br_void in the function's body.884 // current_block_label_id should not be undefined here, lest there is a br or br_void in the function's body.
885 try block.incoming_blocks.append(self.spv.gpa, .{ .src_label_id = self.current_block_label_id, .break_value_id = operand_id });885 try block.incoming_blocks.append(self.spv.gpa, .{ .src_label_id = self.current_block_label_id, .break_value_id = operand_id });
...@@ -958,7 +958,7 @@ pub const DeclGen = struct {...@@ -958,7 +958,7 @@ pub const DeclGen = struct {
958 fn airRet(self: *DeclGen, inst: Air.Inst.Index) !void {958 fn airRet(self: *DeclGen, inst: Air.Inst.Index) !void {
959 const operand = self.air.instructions.items(.data)[inst].un_op;959 const operand = self.air.instructions.items(.data)[inst].un_op;
960 const operand_ty = self.air.typeOf(operand);960 const operand_ty = self.air.typeOf(operand);
961 if (operand_ty.hasCodeGenBits()) {961 if (operand_ty.hasRuntimeBits()) {
962 const operand_id = try self.resolve(operand);962 const operand_id = try self.resolve(operand);
963 try writeInstruction(&self.code, .OpReturnValue, &[_]Word{operand_id});963 try writeInstruction(&self.code, .OpReturnValue, &[_]Word{operand_id});
964 } else {964 } else {
src/link/Elf.zig+1-1
...@@ -2476,7 +2476,7 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven...@@ -2476,7 +2476,7 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven
2476 try dbg_info_buffer.ensureUnusedCapacity(25 + decl_name_with_null.len);2476 try dbg_info_buffer.ensureUnusedCapacity(25 + decl_name_with_null.len);
24772477
2478 const fn_ret_type = decl.ty.fnReturnType();2478 const fn_ret_type = decl.ty.fnReturnType();
2479 const fn_ret_has_bits = fn_ret_type.hasCodeGenBits();2479 const fn_ret_has_bits = fn_ret_type.hasRuntimeBits();
2480 if (fn_ret_has_bits) {2480 if (fn_ret_has_bits) {
2481 dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram);2481 dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram);
2482 } else {2482 } else {
src/link/MachO/DebugSymbols.zig+1-1
...@@ -920,7 +920,7 @@ pub fn initDeclDebugBuffers(...@@ -920,7 +920,7 @@ pub fn initDeclDebugBuffers(
920 try dbg_info_buffer.ensureUnusedCapacity(27 + decl_name_with_null.len);920 try dbg_info_buffer.ensureUnusedCapacity(27 + decl_name_with_null.len);
921921
922 const fn_ret_type = decl.ty.fnReturnType();922 const fn_ret_type = decl.ty.fnReturnType();
923 const fn_ret_has_bits = fn_ret_type.hasCodeGenBits();923 const fn_ret_has_bits = fn_ret_type.hasRuntimeBits();
924 if (fn_ret_has_bits) {924 if (fn_ret_has_bits) {
925 dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram);925 dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram);
926 } else {926 } else {
src/link/Wasm.zig+1-1
...@@ -259,7 +259,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {...@@ -259,7 +259,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
259 if (build_options.have_llvm) {259 if (build_options.have_llvm) {
260 if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(module, decl);260 if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(module, decl);
261 }261 }
262 if (!decl.ty.hasCodeGenBits()) return;262 if (!decl.ty.hasRuntimeBits()) return;
263 assert(decl.link.wasm.sym_index != 0); // Must call allocateDeclIndexes()263 assert(decl.link.wasm.sym_index != 0); // Must call allocateDeclIndexes()
264264
265 decl.link.wasm.clear();265 decl.link.wasm.clear();
src/print_zir.zig+2-1
...@@ -1157,7 +1157,8 @@ const Writer = struct {...@@ -1157,7 +1157,8 @@ const Writer = struct {
1157 break :blk decls_len;1157 break :blk decls_len;
1158 } else 0;1158 } else 0;
11591159
1160 try self.writeFlag(stream, "known_has_bits, ", small.known_has_bits);1160 try self.writeFlag(stream, "known_non_opv, ", small.known_non_opv);
1161 try self.writeFlag(stream, "known_comptime_only, ", small.known_comptime_only);
1161 try stream.print("{s}, {s}, ", .{1162 try stream.print("{s}, {s}, ", .{
1162 @tagName(small.name_strategy), @tagName(small.layout),1163 @tagName(small.name_strategy), @tagName(small.layout),
1163 });1164 });
src/target.zig+9
...@@ -637,3 +637,12 @@ pub fn llvmMachineAbi(target: std.Target) ?[:0]const u8 {...@@ -637,3 +637,12 @@ pub fn llvmMachineAbi(target: std.Target) ?[:0]const u8 {
637 else => return null,637 else => return null,
638 }638 }
639}639}
640
641pub fn defaultFunctionAlignment(target: std.Target) u32 {
642 return switch (target.cpu.arch) {
643 .arm, .armeb => 4,
644 .aarch64, .aarch64_32, .aarch64_be => 4,
645 .riscv64 => 2,
646 else => 1,
647 };
648}
src/type.zig+321-280
...@@ -5,6 +5,7 @@ const Allocator = std.mem.Allocator;...@@ -5,6 +5,7 @@ const Allocator = std.mem.Allocator;
5const Target = std.Target;5const Target = std.Target;
6const Module = @import("Module.zig");6const Module = @import("Module.zig");
7const log = std.log.scoped(.Type);7const log = std.log.scoped(.Type);
8const target_util = @import("target.zig");
89
9const file_struct = @This();10const file_struct = @This();
1011
...@@ -577,21 +578,36 @@ pub const Type = extern union {...@@ -577,21 +578,36 @@ pub const Type = extern union {
577 }578 }
578 },579 },
579 .Fn => {580 .Fn => {
580 if (!a.fnReturnType().eql(b.fnReturnType()))581 const a_info = a.fnInfo();
582 const b_info = b.fnInfo();
583
584 if (!eql(a_info.return_type, b_info.return_type))
581 return false;585 return false;
582 if (a.fnCallingConvention() != b.fnCallingConvention())586
587 if (a_info.cc != b_info.cc)
583 return false;588 return false;
584 const a_param_len = a.fnParamLen();589
585 const b_param_len = b.fnParamLen();590 if (a_info.param_types.len != b_info.param_types.len)
586 if (a_param_len != b_param_len)
587 return false;591 return false;
588 var i: usize = 0;592
589 while (i < a_param_len) : (i += 1) {593 for (a_info.param_types) |a_param_ty, i| {
590 if (!a.fnParamType(i).eql(b.fnParamType(i)))594 const b_param_ty = b_info.param_types[i];
595 if (!eql(a_param_ty, b_param_ty))
596 return false;
597
598 if (a_info.comptime_params[i] != b_info.comptime_params[i])
591 return false;599 return false;
592 }600 }
593 if (a.fnIsVarArgs() != b.fnIsVarArgs())601
602 if (a_info.alignment != b_info.alignment)
603 return false;
604
605 if (a_info.is_var_args != b_info.is_var_args)
594 return false;606 return false;
607
608 if (a_info.is_generic != b_info.is_generic)
609 return false;
610
595 return true;611 return true;
596 },612 },
597 .Optional => {613 .Optional => {
...@@ -686,6 +702,7 @@ pub const Type = extern union {...@@ -686,6 +702,7 @@ pub const Type = extern union {
686 return false;702 return false;
687 },703 },
688 .Float => return a.tag() == b.tag(),704 .Float => return a.tag() == b.tag(),
705
689 .BoundFn,706 .BoundFn,
690 .Frame,707 .Frame,
691 => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }),708 => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }),
...@@ -937,6 +954,7 @@ pub const Type = extern union {...@@ -937,6 +954,7 @@ pub const Type = extern union {
937 .return_type = try payload.return_type.copy(allocator),954 .return_type = try payload.return_type.copy(allocator),
938 .param_types = param_types,955 .param_types = param_types,
939 .cc = payload.cc,956 .cc = payload.cc,
957 .alignment = payload.alignment,
940 .is_var_args = payload.is_var_args,958 .is_var_args = payload.is_var_args,
941 .is_generic = payload.is_generic,959 .is_generic = payload.is_generic,
942 .comptime_params = comptime_params.ptr,960 .comptime_params = comptime_params.ptr,
...@@ -1114,9 +1132,15 @@ pub const Type = extern union {...@@ -1114,9 +1132,15 @@ pub const Type = extern union {
1114 }1132 }
1115 try writer.writeAll("...");1133 try writer.writeAll("...");
1116 }1134 }
1117 try writer.writeAll(") callconv(.");
1118 try writer.writeAll(@tagName(payload.cc));
1119 try writer.writeAll(") ");1135 try writer.writeAll(") ");
1136 if (payload.cc != .Unspecified) {
1137 try writer.writeAll("callconv(.");
1138 try writer.writeAll(@tagName(payload.cc));
1139 try writer.writeAll(") ");
1140 }
1141 if (payload.alignment != 0) {
1142 try writer.print("align({d}) ", .{payload.alignment});
1143 }
1120 ty = payload.return_type;1144 ty = payload.return_type;
1121 continue;1145 continue;
1122 },1146 },
...@@ -1423,170 +1447,6 @@ pub const Type = extern union {...@@ -1423,170 +1447,6 @@ pub const Type = extern union {
1423 }1447 }
1424 }1448 }
14251449
1426 /// Anything that reports hasCodeGenBits() false returns false here as well.
1427 /// `generic_poison` will return false.
1428 pub fn requiresComptime(ty: Type) bool {
1429 return switch (ty.tag()) {
1430 .u1,
1431 .u8,
1432 .i8,
1433 .u16,
1434 .i16,
1435 .u32,
1436 .i32,
1437 .u64,
1438 .i64,
1439 .u128,
1440 .i128,
1441 .usize,
1442 .isize,
1443 .c_short,
1444 .c_ushort,
1445 .c_int,
1446 .c_uint,
1447 .c_long,
1448 .c_ulong,
1449 .c_longlong,
1450 .c_ulonglong,
1451 .c_longdouble,
1452 .f16,
1453 .f32,
1454 .f64,
1455 .f128,
1456 .anyopaque,
1457 .bool,
1458 .void,
1459 .anyerror,
1460 .noreturn,
1461 .@"anyframe",
1462 .@"null",
1463 .@"undefined",
1464 .atomic_order,
1465 .atomic_rmw_op,
1466 .calling_convention,
1467 .address_space,
1468 .float_mode,
1469 .reduce_op,
1470 .call_options,
1471 .prefetch_options,
1472 .export_options,
1473 .extern_options,
1474 .manyptr_u8,
1475 .manyptr_const_u8,
1476 .manyptr_const_u8_sentinel_0,
1477 .fn_noreturn_no_args,
1478 .fn_void_no_args,
1479 .fn_naked_noreturn_no_args,
1480 .fn_ccc_void_no_args,
1481 .const_slice_u8,
1482 .const_slice_u8_sentinel_0,
1483 .anyerror_void_error_union,
1484 .empty_struct_literal,
1485 .function,
1486 .empty_struct,
1487 .error_set,
1488 .error_set_single,
1489 .error_set_inferred,
1490 .error_set_merged,
1491 .@"opaque",
1492 .generic_poison,
1493 .array_u8,
1494 .array_u8_sentinel_0,
1495 .int_signed,
1496 .int_unsigned,
1497 .enum_simple,
1498 => false,
1499
1500 .single_const_pointer_to_comptime_int,
1501 .type,
1502 .comptime_int,
1503 .comptime_float,
1504 .enum_literal,
1505 .type_info,
1506 => true,
1507
1508 .var_args_param => unreachable,
1509 .inferred_alloc_mut => unreachable,
1510 .inferred_alloc_const => unreachable,
1511 .bound_fn => unreachable,
1512
1513 .array,
1514 .array_sentinel,
1515 .vector,
1516 .pointer,
1517 .single_const_pointer,
1518 .single_mut_pointer,
1519 .many_const_pointer,
1520 .many_mut_pointer,
1521 .c_const_pointer,
1522 .c_mut_pointer,
1523 .const_slice,
1524 .mut_slice,
1525 => return requiresComptime(childType(ty)),
1526
1527 .optional,
1528 .optional_single_mut_pointer,
1529 .optional_single_const_pointer,
1530 => {
1531 var buf: Payload.ElemType = undefined;
1532 return requiresComptime(optionalChild(ty, &buf));
1533 },
1534
1535 .tuple => {
1536 const tuple = ty.castTag(.tuple).?.data;
1537 for (tuple.types) |field_ty| {
1538 if (requiresComptime(field_ty)) {
1539 return true;
1540 }
1541 }
1542 return false;
1543 },
1544
1545 .@"struct" => {
1546 const struct_obj = ty.castTag(.@"struct").?.data;
1547 switch (struct_obj.requires_comptime) {
1548 .no, .wip => return false,
1549 .yes => return true,
1550 .unknown => {
1551 struct_obj.requires_comptime = .wip;
1552 for (struct_obj.fields.values()) |field| {
1553 if (requiresComptime(field.ty)) {
1554 struct_obj.requires_comptime = .yes;
1555 return true;
1556 }
1557 }
1558 struct_obj.requires_comptime = .no;
1559 return false;
1560 },
1561 }
1562 },
1563
1564 .@"union", .union_tagged => {
1565 const union_obj = ty.cast(Payload.Union).?.data;
1566 switch (union_obj.requires_comptime) {
1567 .no, .wip => return false,
1568 .yes => return true,
1569 .unknown => {
1570 union_obj.requires_comptime = .wip;
1571 for (union_obj.fields.values()) |field| {
1572 if (requiresComptime(field.ty)) {
1573 union_obj.requires_comptime = .yes;
1574 return true;
1575 }
1576 }
1577 union_obj.requires_comptime = .no;
1578 return false;
1579 },
1580 }
1581 },
1582
1583 .error_union => return requiresComptime(errorUnionPayload(ty)),
1584 .anyframe_T => return ty.castTag(.anyframe_T).?.data.requiresComptime(),
1585 .enum_numbered => return ty.castTag(.enum_numbered).?.data.tag_ty.requiresComptime(),
1586 .enum_full, .enum_nonexhaustive => return ty.cast(Payload.EnumFull).?.data.tag_ty.requiresComptime(),
1587 };
1588 }
1589
1590 pub fn toValue(self: Type, allocator: Allocator) Allocator.Error!Value {1450 pub fn toValue(self: Type, allocator: Allocator) Allocator.Error!Value {
1591 switch (self.tag()) {1451 switch (self.tag()) {
1592 .u1 => return Value.initTag(.u1_type),1452 .u1 => return Value.initTag(.u1_type),
...@@ -1652,8 +1512,12 @@ pub const Type = extern union {...@@ -1652,8 +1512,12 @@ pub const Type = extern union {
1652 }1512 }
1653 }1513 }
16541514
1655 pub fn hasCodeGenBits(self: Type) bool {1515 /// true if and only if the type takes up space in memory at runtime.
1656 return switch (self.tag()) {1516 /// There are two reasons a type will return false:
1517 /// * the type is a comptime-only type. For example, the type `type` itself.
1518 /// * the type has only one possible value, making its ABI size 0.
1519 pub fn hasRuntimeBits(ty: Type) bool {
1520 return switch (ty.tag()) {
1657 .u1,1521 .u1,
1658 .u8,1522 .u8,
1659 .i8,1523 .i8,
...@@ -1682,13 +1546,9 @@ pub const Type = extern union {...@@ -1682,13 +1546,9 @@ pub const Type = extern union {
1682 .f128,1546 .f128,
1683 .bool,1547 .bool,
1684 .anyerror,1548 .anyerror,
1685 .single_const_pointer_to_comptime_int,
1686 .const_slice_u8,1549 .const_slice_u8,
1687 .const_slice_u8_sentinel_0,1550 .const_slice_u8_sentinel_0,
1688 .array_u8_sentinel_0,1551 .array_u8_sentinel_0,
1689 .optional,
1690 .optional_single_mut_pointer,
1691 .optional_single_const_pointer,
1692 .anyerror_void_error_union,1552 .anyerror_void_error_union,
1693 .error_set,1553 .error_set,
1694 .error_set_single,1554 .error_set_single,
...@@ -1708,9 +1568,40 @@ pub const Type = extern union {...@@ -1708,9 +1568,40 @@ pub const Type = extern union {
1708 .export_options,1568 .export_options,
1709 .extern_options,1569 .extern_options,
1710 .@"anyframe",1570 .@"anyframe",
1711 .anyframe_T,
1712 .anyopaque,1571 .anyopaque,
1713 .@"opaque",1572 .@"opaque",
1573 => true,
1574
1575 // These are false because they are comptime-only types.
1576 .single_const_pointer_to_comptime_int,
1577 .void,
1578 .type,
1579 .comptime_int,
1580 .comptime_float,
1581 .noreturn,
1582 .@"null",
1583 .@"undefined",
1584 .enum_literal,
1585 .empty_struct,
1586 .empty_struct_literal,
1587 .type_info,
1588 .bound_fn,
1589 // These are function *bodies*, not pointers.
1590 // Special exceptions have to be made when emitting functions due to
1591 // this returning false.
1592 .function,
1593 .fn_noreturn_no_args,
1594 .fn_void_no_args,
1595 .fn_naked_noreturn_no_args,
1596 .fn_ccc_void_no_args,
1597 => false,
1598
1599 // These types have more than one possible value, so the result is the same as
1600 // asking whether they are comptime-only types.
1601 .anyframe_T,
1602 .optional,
1603 .optional_single_mut_pointer,
1604 .optional_single_const_pointer,
1714 .single_const_pointer,1605 .single_const_pointer,
1715 .single_mut_pointer,1606 .single_mut_pointer,
1716 .many_const_pointer,1607 .many_const_pointer,
...@@ -1720,102 +1611,84 @@ pub const Type = extern union {...@@ -1720,102 +1611,84 @@ pub const Type = extern union {
1720 .const_slice,1611 .const_slice,
1721 .mut_slice,1612 .mut_slice,
1722 .pointer,1613 .pointer,
1723 => true,1614 => !ty.comptimeOnly(),
1724
1725 .function => !self.castTag(.function).?.data.is_generic,
1726
1727 .fn_noreturn_no_args,
1728 .fn_void_no_args,
1729 .fn_naked_noreturn_no_args,
1730 .fn_ccc_void_no_args,
1731 => true,
17321615
1733 .@"struct" => {1616 .@"struct" => {
1734 const struct_obj = self.castTag(.@"struct").?.data;1617 const struct_obj = ty.castTag(.@"struct").?.data;
1735 if (struct_obj.known_has_bits) {1618 switch (struct_obj.requires_comptime) {
1736 return true;1619 .wip => unreachable,
1620 .yes => return false,
1621 .no => if (struct_obj.known_non_opv) return true,
1622 .unknown => {},
1737 }1623 }
1738 assert(struct_obj.haveFieldTypes());1624 assert(struct_obj.haveFieldTypes());
1739 for (struct_obj.fields.values()) |value| {1625 for (struct_obj.fields.values()) |value| {
1740 if (value.ty.hasCodeGenBits())1626 if (value.ty.hasRuntimeBits())
1741 return true;1627 return true;
1742 } else {1628 } else {
1743 return false;1629 return false;
1744 }1630 }
1745 },1631 },
1632
1746 .enum_full => {1633 .enum_full => {
1747 const enum_full = self.castTag(.enum_full).?.data;1634 const enum_full = ty.castTag(.enum_full).?.data;
1748 return enum_full.fields.count() >= 2;1635 return enum_full.fields.count() >= 2;
1749 },1636 },
1750 .enum_simple => {1637 .enum_simple => {
1751 const enum_simple = self.castTag(.enum_simple).?.data;1638 const enum_simple = ty.castTag(.enum_simple).?.data;
1752 return enum_simple.fields.count() >= 2;1639 return enum_simple.fields.count() >= 2;
1753 },1640 },
1754 .enum_numbered, .enum_nonexhaustive => {1641 .enum_numbered, .enum_nonexhaustive => {
1755 var buffer: Payload.Bits = undefined;1642 var buffer: Payload.Bits = undefined;
1756 const int_tag_ty = self.intTagType(&buffer);1643 const int_tag_ty = ty.intTagType(&buffer);
1757 return int_tag_ty.hasCodeGenBits();1644 return int_tag_ty.hasRuntimeBits();
1758 },1645 },
1646
1759 .@"union" => {1647 .@"union" => {
1760 const union_obj = self.castTag(.@"union").?.data;1648 const union_obj = ty.castTag(.@"union").?.data;
1761 assert(union_obj.haveFieldTypes());1649 assert(union_obj.haveFieldTypes());
1762 for (union_obj.fields.values()) |value| {1650 for (union_obj.fields.values()) |value| {
1763 if (value.ty.hasCodeGenBits())1651 if (value.ty.hasRuntimeBits())
1764 return true;1652 return true;
1765 } else {1653 } else {
1766 return false;1654 return false;
1767 }1655 }
1768 },1656 },
1769 .union_tagged => {1657 .union_tagged => {
1770 const union_obj = self.castTag(.union_tagged).?.data;1658 const union_obj = ty.castTag(.union_tagged).?.data;
1771 if (union_obj.tag_ty.hasCodeGenBits()) {1659 if (union_obj.tag_ty.hasRuntimeBits()) {
1772 return true;1660 return true;
1773 }1661 }
1774 assert(union_obj.haveFieldTypes());1662 assert(union_obj.haveFieldTypes());
1775 for (union_obj.fields.values()) |value| {1663 for (union_obj.fields.values()) |value| {
1776 if (value.ty.hasCodeGenBits())1664 if (value.ty.hasRuntimeBits())
1777 return true;1665 return true;
1778 } else {1666 } else {
1779 return false;1667 return false;
1780 }1668 }
1781 },1669 },
17821670
1783 .array, .vector => self.elemType().hasCodeGenBits() and self.arrayLen() != 0,1671 .array, .vector => ty.arrayLen() != 0 and ty.elemType().hasRuntimeBits(),
1784 .array_u8 => self.arrayLen() != 0,1672 .array_u8 => ty.arrayLen() != 0,
17851673 .array_sentinel => ty.childType().hasRuntimeBits(),
1786 .array_sentinel => self.childType().hasCodeGenBits(),
17871674
1788 .int_signed, .int_unsigned => self.cast(Payload.Bits).?.data != 0,1675 .int_signed, .int_unsigned => ty.cast(Payload.Bits).?.data != 0,
17891676
1790 .error_union => {1677 .error_union => {
1791 const payload = self.castTag(.error_union).?.data;1678 const payload = ty.castTag(.error_union).?.data;
1792 return payload.error_set.hasCodeGenBits() or payload.payload.hasCodeGenBits();1679 return payload.error_set.hasRuntimeBits() or payload.payload.hasRuntimeBits();
1793 },1680 },
17941681
1795 .tuple => {1682 .tuple => {
1796 const tuple = self.castTag(.tuple).?.data;1683 const tuple = ty.castTag(.tuple).?.data;
1797 for (tuple.types) |ty, i| {1684 for (tuple.types) |field_ty, i| {
1798 const val = tuple.values[i];1685 const val = tuple.values[i];
1799 if (val.tag() != .unreachable_value) continue; // comptime field1686 if (val.tag() != .unreachable_value) continue; // comptime field
1800 if (ty.hasCodeGenBits()) return true;1687 if (field_ty.hasRuntimeBits()) return true;
1801 }1688 }
1802 return false;1689 return false;
1803 },1690 },
18041691
1805 .void,
1806 .type,
1807 .comptime_int,
1808 .comptime_float,
1809 .noreturn,
1810 .@"null",
1811 .@"undefined",
1812 .enum_literal,
1813 .empty_struct,
1814 .empty_struct_literal,
1815 .type_info,
1816 .bound_fn,
1817 => false,
1818
1819 .inferred_alloc_const => unreachable,1692 .inferred_alloc_const => unreachable,
1820 .inferred_alloc_mut => unreachable,1693 .inferred_alloc_mut => unreachable,
1821 .var_args_param => unreachable,1694 .var_args_param => unreachable,
...@@ -1823,6 +1696,24 @@ pub const Type = extern union {...@@ -1823,6 +1696,24 @@ pub const Type = extern union {
1823 };1696 };
1824 }1697 }
18251698
1699 pub fn isFnOrHasRuntimeBits(ty: Type) bool {
1700 switch (ty.zigTypeTag()) {
1701 .Fn => {
1702 const fn_info = ty.fnInfo();
1703 if (fn_info.is_generic) return false;
1704 if (fn_info.is_var_args) return true;
1705 switch (fn_info.cc) {
1706 // If there was a comptime calling convention, it should also return false here.
1707 .Inline => return false,
1708 else => {},
1709 }
1710 if (fn_info.return_type.comptimeOnly()) return false;
1711 return true;
1712 },
1713 else => return ty.hasRuntimeBits(),
1714 }
1715 }
1716
1826 pub fn isNoReturn(self: Type) bool {1717 pub fn isNoReturn(self: Type) bool {
1827 const definitely_correct_result =1718 const definitely_correct_result =
1828 self.tag_if_small_enough != .bound_fn and1719 self.tag_if_small_enough != .bound_fn and
...@@ -1918,12 +1809,13 @@ pub const Type = extern union {...@@ -1918,12 +1809,13 @@ pub const Type = extern union {
1918 .fn_void_no_args, // represents machine code; not a pointer1809 .fn_void_no_args, // represents machine code; not a pointer
1919 .fn_naked_noreturn_no_args, // represents machine code; not a pointer1810 .fn_naked_noreturn_no_args, // represents machine code; not a pointer
1920 .fn_ccc_void_no_args, // represents machine code; not a pointer1811 .fn_ccc_void_no_args, // represents machine code; not a pointer
1921 .function, // represents machine code; not a pointer1812 => return target_util.defaultFunctionAlignment(target),
1922 => return switch (target.cpu.arch) {1813
1923 .arm, .armeb => 4,1814 // represents machine code; not a pointer
1924 .aarch64, .aarch64_32, .aarch64_be => 4,1815 .function => {
1925 .riscv64 => 2,1816 const alignment = self.castTag(.function).?.data.alignment;
1926 else => 1,1817 if (alignment != 0) return alignment;
1818 return target_util.defaultFunctionAlignment(target);
1927 },1819 },
19281820
1929 .i16, .u16 => return 2,1821 .i16, .u16 => return 2,
...@@ -1996,7 +1888,7 @@ pub const Type = extern union {...@@ -1996,7 +1888,7 @@ pub const Type = extern union {
1996 .optional => {1888 .optional => {
1997 var buf: Payload.ElemType = undefined;1889 var buf: Payload.ElemType = undefined;
1998 const child_type = self.optionalChild(&buf);1890 const child_type = self.optionalChild(&buf);
1999 if (!child_type.hasCodeGenBits()) return 1;1891 if (!child_type.hasRuntimeBits()) return 1;
20001892
2001 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())1893 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())
2002 return @divExact(target.cpu.arch.ptrBitWidth(), 8);1894 return @divExact(target.cpu.arch.ptrBitWidth(), 8);
...@@ -2006,9 +1898,9 @@ pub const Type = extern union {...@@ -2006,9 +1898,9 @@ pub const Type = extern union {
20061898
2007 .error_union => {1899 .error_union => {
2008 const data = self.castTag(.error_union).?.data;1900 const data = self.castTag(.error_union).?.data;
2009 if (!data.error_set.hasCodeGenBits()) {1901 if (!data.error_set.hasRuntimeBits()) {
2010 return data.payload.abiAlignment(target);1902 return data.payload.abiAlignment(target);
2011 } else if (!data.payload.hasCodeGenBits()) {1903 } else if (!data.payload.hasRuntimeBits()) {
2012 return data.error_set.abiAlignment(target);1904 return data.error_set.abiAlignment(target);
2013 }1905 }
2014 return @maximum(1906 return @maximum(
...@@ -2028,7 +1920,7 @@ pub const Type = extern union {...@@ -2028,7 +1920,7 @@ pub const Type = extern union {
2028 if (!is_packed) {1920 if (!is_packed) {
2029 var big_align: u32 = 0;1921 var big_align: u32 = 0;
2030 for (fields.values()) |field| {1922 for (fields.values()) |field| {
2031 if (!field.ty.hasCodeGenBits()) continue;1923 if (!field.ty.hasRuntimeBits()) continue;
20321924
2033 const field_align = field.normalAlignment(target);1925 const field_align = field.normalAlignment(target);
2034 big_align = @maximum(big_align, field_align);1926 big_align = @maximum(big_align, field_align);
...@@ -2042,7 +1934,7 @@ pub const Type = extern union {...@@ -2042,7 +1934,7 @@ pub const Type = extern union {
2042 var running_bits: u16 = 0;1934 var running_bits: u16 = 0;
20431935
2044 for (fields.values()) |field| {1936 for (fields.values()) |field| {
2045 if (!field.ty.hasCodeGenBits()) continue;1937 if (!field.ty.hasRuntimeBits()) continue;
20461938
2047 const field_align = field.packedAlignment();1939 const field_align = field.packedAlignment();
2048 if (field_align == 0) {1940 if (field_align == 0) {
...@@ -2080,7 +1972,7 @@ pub const Type = extern union {...@@ -2080,7 +1972,7 @@ pub const Type = extern union {
2080 for (tuple.types) |field_ty, i| {1972 for (tuple.types) |field_ty, i| {
2081 const val = tuple.values[i];1973 const val = tuple.values[i];
2082 if (val.tag() != .unreachable_value) continue; // comptime field1974 if (val.tag() != .unreachable_value) continue; // comptime field
2083 if (!field_ty.hasCodeGenBits()) continue;1975 if (!field_ty.hasRuntimeBits()) continue;
20841976
2085 const field_align = field_ty.abiAlignment(target);1977 const field_align = field_ty.abiAlignment(target);
2086 big_align = @maximum(big_align, field_align);1978 big_align = @maximum(big_align, field_align);
...@@ -2123,7 +2015,7 @@ pub const Type = extern union {...@@ -2123,7 +2015,7 @@ pub const Type = extern union {
2123 }2015 }
21242016
2125 /// Asserts the type has the ABI size already resolved.2017 /// Asserts the type has the ABI size already resolved.
2126 /// Types that return false for hasCodeGenBits() return 0.2018 /// Types that return false for hasRuntimeBits() return 0.
2127 pub fn abiSize(self: Type, target: Target) u64 {2019 pub fn abiSize(self: Type, target: Target) u64 {
2128 return switch (self.tag()) {2020 return switch (self.tag()) {
2129 .fn_noreturn_no_args => unreachable, // represents machine code; not a pointer2021 .fn_noreturn_no_args => unreachable, // represents machine code; not a pointer
...@@ -2210,24 +2102,8 @@ pub const Type = extern union {...@@ -2210,24 +2102,8 @@ pub const Type = extern union {
2210 .usize,2102 .usize,
2211 .@"anyframe",2103 .@"anyframe",
2212 .anyframe_T,2104 .anyframe_T,
2213 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
2214
2215 .const_slice,
2216 .mut_slice,
2217 => {
2218 return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2;
2219 },
2220 .const_slice_u8,
2221 .const_slice_u8_sentinel_0,
2222 => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2,
2223
2224 .optional_single_const_pointer,2105 .optional_single_const_pointer,
2225 .optional_single_mut_pointer,2106 .optional_single_mut_pointer,
2226 => {
2227 if (!self.elemType().hasCodeGenBits()) return 1;
2228 return @divExact(target.cpu.arch.ptrBitWidth(), 8);
2229 },
2230
2231 .single_const_pointer,2107 .single_const_pointer,
2232 .single_mut_pointer,2108 .single_mut_pointer,
2233 .many_const_pointer,2109 .many_const_pointer,
...@@ -2239,6 +2115,12 @@ pub const Type = extern union {...@@ -2239,6 +2115,12 @@ pub const Type = extern union {
2239 .manyptr_const_u8_sentinel_0,2115 .manyptr_const_u8_sentinel_0,
2240 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),2116 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
22412117
2118 .const_slice,
2119 .mut_slice,
2120 .const_slice_u8,
2121 .const_slice_u8_sentinel_0,
2122 => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2,
2123
2242 .pointer => switch (self.castTag(.pointer).?.data.size) {2124 .pointer => switch (self.castTag(.pointer).?.data.size) {
2243 .Slice => @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2,2125 .Slice => @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2,
2244 else => @divExact(target.cpu.arch.ptrBitWidth(), 8),2126 else => @divExact(target.cpu.arch.ptrBitWidth(), 8),
...@@ -2276,7 +2158,7 @@ pub const Type = extern union {...@@ -2276,7 +2158,7 @@ pub const Type = extern union {
2276 .optional => {2158 .optional => {
2277 var buf: Payload.ElemType = undefined;2159 var buf: Payload.ElemType = undefined;
2278 const child_type = self.optionalChild(&buf);2160 const child_type = self.optionalChild(&buf);
2279 if (!child_type.hasCodeGenBits()) return 1;2161 if (!child_type.hasRuntimeBits()) return 1;
22802162
2281 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr() and !child_type.isSlice())2163 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr() and !child_type.isSlice())
2282 return @divExact(target.cpu.arch.ptrBitWidth(), 8);2164 return @divExact(target.cpu.arch.ptrBitWidth(), 8);
...@@ -2290,11 +2172,11 @@ pub const Type = extern union {...@@ -2290,11 +2172,11 @@ pub const Type = extern union {
22902172
2291 .error_union => {2173 .error_union => {
2292 const data = self.castTag(.error_union).?.data;2174 const data = self.castTag(.error_union).?.data;
2293 if (!data.error_set.hasCodeGenBits() and !data.payload.hasCodeGenBits()) {2175 if (!data.error_set.hasRuntimeBits() and !data.payload.hasRuntimeBits()) {
2294 return 0;2176 return 0;
2295 } else if (!data.error_set.hasCodeGenBits()) {2177 } else if (!data.error_set.hasRuntimeBits()) {
2296 return data.payload.abiSize(target);2178 return data.payload.abiSize(target);
2297 } else if (!data.payload.hasCodeGenBits()) {2179 } else if (!data.payload.hasRuntimeBits()) {
2298 return data.error_set.abiSize(target);2180 return data.error_set.abiSize(target);
2299 }2181 }
2300 const code_align = abiAlignment(data.error_set, target);2182 const code_align = abiAlignment(data.error_set, target);
...@@ -2414,11 +2296,7 @@ pub const Type = extern union {...@@ -2414,11 +2296,7 @@ pub const Type = extern union {
2414 .optional_single_const_pointer,2296 .optional_single_const_pointer,
2415 .optional_single_mut_pointer,2297 .optional_single_mut_pointer,
2416 => {2298 => {
2417 if (ty.elemType().hasCodeGenBits()) {2299 return target.cpu.arch.ptrBitWidth();
2418 return target.cpu.arch.ptrBitWidth();
2419 } else {
2420 return 1;
2421 }
2422 },2300 },
24232301
2424 .single_const_pointer,2302 .single_const_pointer,
...@@ -2428,11 +2306,7 @@ pub const Type = extern union {...@@ -2428,11 +2306,7 @@ pub const Type = extern union {
2428 .c_const_pointer,2306 .c_const_pointer,
2429 .c_mut_pointer,2307 .c_mut_pointer,
2430 => {2308 => {
2431 if (ty.elemType().hasCodeGenBits()) {2309 return target.cpu.arch.ptrBitWidth();
2432 return target.cpu.arch.ptrBitWidth();
2433 } else {
2434 return 0;
2435 }
2436 },2310 },
24372311
2438 .pointer => switch (ty.castTag(.pointer).?.data.size) {2312 .pointer => switch (ty.castTag(.pointer).?.data.size) {
...@@ -2468,7 +2342,7 @@ pub const Type = extern union {...@@ -2468,7 +2342,7 @@ pub const Type = extern union {
2468 .optional => {2342 .optional => {
2469 var buf: Payload.ElemType = undefined;2343 var buf: Payload.ElemType = undefined;
2470 const child_type = ty.optionalChild(&buf);2344 const child_type = ty.optionalChild(&buf);
2471 if (!child_type.hasCodeGenBits()) return 8;2345 if (!child_type.hasRuntimeBits()) return 8;
24722346
2473 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr() and !child_type.isSlice())2347 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr() and !child_type.isSlice())
2474 return target.cpu.arch.ptrBitWidth();2348 return target.cpu.arch.ptrBitWidth();
...@@ -2482,11 +2356,11 @@ pub const Type = extern union {...@@ -2482,11 +2356,11 @@ pub const Type = extern union {
24822356
2483 .error_union => {2357 .error_union => {
2484 const payload = ty.castTag(.error_union).?.data;2358 const payload = ty.castTag(.error_union).?.data;
2485 if (!payload.error_set.hasCodeGenBits() and !payload.payload.hasCodeGenBits()) {2359 if (!payload.error_set.hasRuntimeBits() and !payload.payload.hasRuntimeBits()) {
2486 return 0;2360 return 0;
2487 } else if (!payload.error_set.hasCodeGenBits()) {2361 } else if (!payload.error_set.hasRuntimeBits()) {
2488 return payload.payload.bitSize(target);2362 return payload.payload.bitSize(target);
2489 } else if (!payload.payload.hasCodeGenBits()) {2363 } else if (!payload.payload.hasRuntimeBits()) {
2490 return payload.error_set.bitSize(target);2364 return payload.error_set.bitSize(target);
2491 }2365 }
2492 @panic("TODO bitSize error union");2366 @panic("TODO bitSize error union");
...@@ -2728,7 +2602,7 @@ pub const Type = extern union {...@@ -2728,7 +2602,7 @@ pub const Type = extern union {
2728 var buf: Payload.ElemType = undefined;2602 var buf: Payload.ElemType = undefined;
2729 const child_type = self.optionalChild(&buf);2603 const child_type = self.optionalChild(&buf);
2730 // optionals of zero sized pointers behave like bools2604 // optionals of zero sized pointers behave like bools
2731 if (!child_type.hasCodeGenBits()) return false;2605 if (!child_type.hasRuntimeBits()) return false;
2732 if (child_type.zigTypeTag() != .Pointer) return false;2606 if (child_type.zigTypeTag() != .Pointer) return false;
27332607
2734 const info = child_type.ptrInfo().data;2608 const info = child_type.ptrInfo().data;
...@@ -2765,7 +2639,7 @@ pub const Type = extern union {...@@ -2765,7 +2639,7 @@ pub const Type = extern union {
2765 var buf: Payload.ElemType = undefined;2639 var buf: Payload.ElemType = undefined;
2766 const child_type = self.optionalChild(&buf);2640 const child_type = self.optionalChild(&buf);
2767 // optionals of zero sized types behave like bools, not pointers2641 // optionals of zero sized types behave like bools, not pointers
2768 if (!child_type.hasCodeGenBits()) return false;2642 if (!child_type.hasRuntimeBits()) return false;
2769 if (child_type.zigTypeTag() != .Pointer) return false;2643 if (child_type.zigTypeTag() != .Pointer) return false;
27702644
2771 const info = child_type.ptrInfo().data;2645 const info = child_type.ptrInfo().data;
...@@ -3424,6 +3298,7 @@ pub const Type = extern union {...@@ -3424,6 +3298,7 @@ pub const Type = extern union {
3424 .comptime_params = undefined,3298 .comptime_params = undefined,
3425 .return_type = initTag(.noreturn),3299 .return_type = initTag(.noreturn),
3426 .cc = .Unspecified,3300 .cc = .Unspecified,
3301 .alignment = 0,
3427 .is_var_args = false,3302 .is_var_args = false,
3428 .is_generic = false,3303 .is_generic = false,
3429 },3304 },
...@@ -3432,6 +3307,7 @@ pub const Type = extern union {...@@ -3432,6 +3307,7 @@ pub const Type = extern union {
3432 .comptime_params = undefined,3307 .comptime_params = undefined,
3433 .return_type = initTag(.void),3308 .return_type = initTag(.void),
3434 .cc = .Unspecified,3309 .cc = .Unspecified,
3310 .alignment = 0,
3435 .is_var_args = false,3311 .is_var_args = false,
3436 .is_generic = false,3312 .is_generic = false,
3437 },3313 },
...@@ -3440,6 +3316,7 @@ pub const Type = extern union {...@@ -3440,6 +3316,7 @@ pub const Type = extern union {
3440 .comptime_params = undefined,3316 .comptime_params = undefined,
3441 .return_type = initTag(.noreturn),3317 .return_type = initTag(.noreturn),
3442 .cc = .Naked,3318 .cc = .Naked,
3319 .alignment = 0,
3443 .is_var_args = false,3320 .is_var_args = false,
3444 .is_generic = false,3321 .is_generic = false,
3445 },3322 },
...@@ -3448,6 +3325,7 @@ pub const Type = extern union {...@@ -3448,6 +3325,7 @@ pub const Type = extern union {
3448 .comptime_params = undefined,3325 .comptime_params = undefined,
3449 .return_type = initTag(.void),3326 .return_type = initTag(.void),
3450 .cc = .C,3327 .cc = .C,
3328 .alignment = 0,
3451 .is_var_args = false,3329 .is_var_args = false,
3452 .is_generic = false,3330 .is_generic = false,
3453 },3331 },
...@@ -3629,7 +3507,7 @@ pub const Type = extern union {...@@ -3629,7 +3507,7 @@ pub const Type = extern union {
3629 },3507 },
3630 .enum_nonexhaustive => {3508 .enum_nonexhaustive => {
3631 const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty;3509 const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty;
3632 if (!tag_ty.hasCodeGenBits()) {3510 if (!tag_ty.hasRuntimeBits()) {
3633 return Value.zero;3511 return Value.zero;
3634 } else {3512 } else {
3635 return null;3513 return null;
...@@ -3672,6 +3550,167 @@ pub const Type = extern union {...@@ -3672,6 +3550,167 @@ pub const Type = extern union {
3672 };3550 };
3673 }3551 }
36743552
3553 /// During semantic analysis, instead call `Sema.typeRequiresComptime` which
3554 /// resolves field types rather than asserting they are already resolved.
3555 pub fn comptimeOnly(ty: Type) bool {
3556 return switch (ty.tag()) {
3557 .u1,
3558 .u8,
3559 .i8,
3560 .u16,
3561 .i16,
3562 .u32,
3563 .i32,
3564 .u64,
3565 .i64,
3566 .u128,
3567 .i128,
3568 .usize,
3569 .isize,
3570 .c_short,
3571 .c_ushort,
3572 .c_int,
3573 .c_uint,
3574 .c_long,
3575 .c_ulong,
3576 .c_longlong,
3577 .c_ulonglong,
3578 .c_longdouble,
3579 .f16,
3580 .f32,
3581 .f64,
3582 .f128,
3583 .anyopaque,
3584 .bool,
3585 .void,
3586 .anyerror,
3587 .noreturn,
3588 .@"anyframe",
3589 .@"null",
3590 .@"undefined",
3591 .atomic_order,
3592 .atomic_rmw_op,
3593 .calling_convention,
3594 .address_space,
3595 .float_mode,
3596 .reduce_op,
3597 .call_options,
3598 .prefetch_options,
3599 .export_options,
3600 .extern_options,
3601 .manyptr_u8,
3602 .manyptr_const_u8,
3603 .manyptr_const_u8_sentinel_0,
3604 .const_slice_u8,
3605 .const_slice_u8_sentinel_0,
3606 .anyerror_void_error_union,
3607 .empty_struct_literal,
3608 .empty_struct,
3609 .error_set,
3610 .error_set_single,
3611 .error_set_inferred,
3612 .error_set_merged,
3613 .@"opaque",
3614 .generic_poison,
3615 .array_u8,
3616 .array_u8_sentinel_0,
3617 .int_signed,
3618 .int_unsigned,
3619 .enum_simple,
3620 => false,
3621
3622 .single_const_pointer_to_comptime_int,
3623 .type,
3624 .comptime_int,
3625 .comptime_float,
3626 .enum_literal,
3627 .type_info,
3628 // These are function bodies, not function pointers.
3629 .fn_noreturn_no_args,
3630 .fn_void_no_args,
3631 .fn_naked_noreturn_no_args,
3632 .fn_ccc_void_no_args,
3633 .function,
3634 => true,
3635
3636 .var_args_param => unreachable,
3637 .inferred_alloc_mut => unreachable,
3638 .inferred_alloc_const => unreachable,
3639 .bound_fn => unreachable,
3640
3641 .array,
3642 .array_sentinel,
3643 .vector,
3644 => return ty.childType().comptimeOnly(),
3645
3646 .pointer,
3647 .single_const_pointer,
3648 .single_mut_pointer,
3649 .many_const_pointer,
3650 .many_mut_pointer,
3651 .c_const_pointer,
3652 .c_mut_pointer,
3653 .const_slice,
3654 .mut_slice,
3655 => {
3656 const child_ty = ty.childType();
3657 if (child_ty.zigTypeTag() == .Fn) {
3658 return false;
3659 } else {
3660 return child_ty.comptimeOnly();
3661 }
3662 },
3663
3664 .optional,
3665 .optional_single_mut_pointer,
3666 .optional_single_const_pointer,
3667 => {
3668 var buf: Type.Payload.ElemType = undefined;
3669 return ty.optionalChild(&buf).comptimeOnly();
3670 },
3671
3672 .tuple => {
3673 const tuple = ty.castTag(.tuple).?.data;
3674 for (tuple.types) |field_ty| {
3675 if (field_ty.comptimeOnly()) return true;
3676 }
3677 return false;
3678 },
3679
3680 .@"struct" => {
3681 const struct_obj = ty.castTag(.@"struct").?.data;
3682 switch (struct_obj.requires_comptime) {
3683 .wip, .unknown => unreachable, // This function asserts types already resolved.
3684 .no => return false,
3685 .yes => return true,
3686 }
3687 },
3688
3689 .@"union", .union_tagged => {
3690 const union_obj = ty.cast(Type.Payload.Union).?.data;
3691 switch (union_obj.requires_comptime) {
3692 .wip, .unknown => unreachable, // This function asserts types already resolved.
3693 .no => return false,
3694 .yes => return true,
3695 }
3696 },
3697
3698 .error_union => return ty.errorUnionPayload().comptimeOnly(),
3699 .anyframe_T => {
3700 const child_ty = ty.castTag(.anyframe_T).?.data;
3701 return child_ty.comptimeOnly();
3702 },
3703 .enum_numbered => {
3704 const tag_ty = ty.castTag(.enum_numbered).?.data.tag_ty;
3705 return tag_ty.comptimeOnly();
3706 },
3707 .enum_full, .enum_nonexhaustive => {
3708 const tag_ty = ty.cast(Type.Payload.EnumFull).?.data.tag_ty;
3709 return tag_ty.comptimeOnly();
3710 },
3711 };
3712 }
3713
3675 pub fn isIndexable(ty: Type) bool {3714 pub fn isIndexable(ty: Type) bool {
3676 return switch (ty.zigTypeTag()) {3715 return switch (ty.zigTypeTag()) {
3677 .Array, .Vector => true,3716 .Array, .Vector => true,
...@@ -3949,7 +3988,7 @@ pub const Type = extern union {...@@ -3949,7 +3988,7 @@ pub const Type = extern union {
39493988
3950 const field = it.struct_obj.fields.values()[it.field];3989 const field = it.struct_obj.fields.values()[it.field];
3951 defer it.field += 1;3990 defer it.field += 1;
3952 if (!field.ty.hasCodeGenBits()) {3991 if (!field.ty.hasRuntimeBits()) {
3953 return PackedFieldOffset{3992 return PackedFieldOffset{
3954 .field = it.field,3993 .field = it.field,
3955 .offset = it.offset,3994 .offset = it.offset,
...@@ -4018,7 +4057,7 @@ pub const Type = extern union {...@@ -4018,7 +4057,7 @@ pub const Type = extern union {
40184057
4019 const field = it.struct_obj.fields.values()[it.field];4058 const field = it.struct_obj.fields.values()[it.field];
4020 defer it.field += 1;4059 defer it.field += 1;
4021 if (!field.ty.hasCodeGenBits())4060 if (!field.ty.hasRuntimeBits())
4022 return FieldOffset{ .field = it.field, .offset = it.offset };4061 return FieldOffset{ .field = it.field, .offset = it.offset };
40234062
4024 const field_align = field.normalAlignment(it.target);4063 const field_align = field.normalAlignment(it.target);
...@@ -4572,6 +4611,8 @@ pub const Type = extern union {...@@ -4572,6 +4611,8 @@ pub const Type = extern union {
4572 param_types: []Type,4611 param_types: []Type,
4573 comptime_params: [*]bool,4612 comptime_params: [*]bool,
4574 return_type: Type,4613 return_type: Type,
4614 /// If zero use default target function code alignment.
4615 alignment: u32,
4575 cc: std.builtin.CallingConvention,4616 cc: std.builtin.CallingConvention,
4576 is_var_args: bool,4617 is_var_args: bool,
4577 is_generic: bool,4618 is_generic: bool,
src/value.zig+72-7
...@@ -1225,7 +1225,7 @@ pub const Value = extern union {...@@ -1225,7 +1225,7 @@ pub const Value = extern union {
12251225
1226 /// Asserts the value is an integer and not undefined.1226 /// Asserts the value is an integer and not undefined.
1227 /// Returns the number of bits the value requires to represent stored in twos complement form.1227 /// Returns the number of bits the value requires to represent stored in twos complement form.
1228 pub fn intBitCountTwosComp(self: Value) usize {1228 pub fn intBitCountTwosComp(self: Value, target: Target) usize {
1229 switch (self.tag()) {1229 switch (self.tag()) {
1230 .zero,1230 .zero,
1231 .bool_false,1231 .bool_false,
...@@ -1244,6 +1244,15 @@ pub const Value = extern union {...@@ -1244,6 +1244,15 @@ pub const Value = extern union {
1244 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().bitCountTwosComp(),1244 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().bitCountTwosComp(),
1245 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().bitCountTwosComp(),1245 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().bitCountTwosComp(),
12461246
1247 .decl_ref_mut,
1248 .extern_fn,
1249 .decl_ref,
1250 .function,
1251 .variable,
1252 .eu_payload_ptr,
1253 .opt_payload_ptr,
1254 => return target.cpu.arch.ptrBitWidth(),
1255
1247 else => {1256 else => {
1248 var buffer: BigIntSpace = undefined;1257 var buffer: BigIntSpace = undefined;
1249 return self.toBigInt(&buffer).bitCountTwosComp();1258 return self.toBigInt(&buffer).bitCountTwosComp();
...@@ -1333,6 +1342,20 @@ pub const Value = extern union {...@@ -1333,6 +1342,20 @@ pub const Value = extern union {
1333 return true;1342 return true;
1334 },1343 },
13351344
1345 .decl_ref_mut,
1346 .extern_fn,
1347 .decl_ref,
1348 .function,
1349 .variable,
1350 => {
1351 const info = ty.intInfo(target);
1352 const ptr_bits = target.cpu.arch.ptrBitWidth();
1353 return switch (info.signedness) {
1354 .signed => info.bits > ptr_bits,
1355 .unsigned => info.bits >= ptr_bits,
1356 };
1357 },
1358
1336 else => unreachable,1359 else => unreachable,
1337 }1360 }
1338 }1361 }
...@@ -1397,6 +1420,11 @@ pub const Value = extern union {...@@ -1397,6 +1420,11 @@ pub const Value = extern union {
13971420
1398 .one,1421 .one,
1399 .bool_true,1422 .bool_true,
1423 .decl_ref,
1424 .decl_ref_mut,
1425 .extern_fn,
1426 .function,
1427 .variable,
1400 => .gt,1428 => .gt,
14011429
1402 .int_u64 => std.math.order(lhs.castTag(.int_u64).?.data, 0),1430 .int_u64 => std.math.order(lhs.castTag(.int_u64).?.data, 0),
...@@ -1417,10 +1445,18 @@ pub const Value = extern union {...@@ -1417,10 +1445,18 @@ pub const Value = extern union {
1417 pub fn order(lhs: Value, rhs: Value) std.math.Order {1445 pub fn order(lhs: Value, rhs: Value) std.math.Order {
1418 const lhs_tag = lhs.tag();1446 const lhs_tag = lhs.tag();
1419 const rhs_tag = rhs.tag();1447 const rhs_tag = rhs.tag();
1420 const lhs_is_zero = lhs_tag == .zero;1448 const lhs_against_zero = lhs.orderAgainstZero();
1421 const rhs_is_zero = rhs_tag == .zero;1449 const rhs_against_zero = rhs.orderAgainstZero();
1422 if (lhs_is_zero) return rhs.orderAgainstZero().invert();1450 switch (lhs_against_zero) {
1423 if (rhs_is_zero) return lhs.orderAgainstZero();1451 .lt => if (rhs_against_zero != .lt) return .lt,
1452 .eq => return rhs_against_zero.invert(),
1453 .gt => {},
1454 }
1455 switch (rhs_against_zero) {
1456 .lt => if (lhs_against_zero != .lt) return .gt,
1457 .eq => return lhs_against_zero,
1458 .gt => {},
1459 }
14241460
1425 const lhs_float = lhs.isFloat();1461 const lhs_float = lhs.isFloat();
1426 const rhs_float = rhs.isFloat();1462 const rhs_float = rhs.isFloat();
...@@ -1451,6 +1487,27 @@ pub const Value = extern union {...@@ -1451,6 +1487,27 @@ pub const Value = extern union {
1451 /// Asserts the value is comparable. Does not take a type parameter because it supports1487 /// Asserts the value is comparable. Does not take a type parameter because it supports
1452 /// comparisons between heterogeneous types.1488 /// comparisons between heterogeneous types.
1453 pub fn compareHetero(lhs: Value, op: std.math.CompareOperator, rhs: Value) bool {1489 pub fn compareHetero(lhs: Value, op: std.math.CompareOperator, rhs: Value) bool {
1490 if (lhs.pointerDecl()) |lhs_decl| {
1491 if (rhs.pointerDecl()) |rhs_decl| {
1492 switch (op) {
1493 .eq => return lhs_decl == rhs_decl,
1494 .neq => return lhs_decl != rhs_decl,
1495 else => {},
1496 }
1497 } else {
1498 switch (op) {
1499 .eq => return false,
1500 .neq => return true,
1501 else => {},
1502 }
1503 }
1504 } else if (rhs.pointerDecl()) |_| {
1505 switch (op) {
1506 .eq => return false,
1507 .neq => return true,
1508 else => {},
1509 }
1510 }
1454 return order(lhs, rhs).compare(op);1511 return order(lhs, rhs).compare(op);
1455 }1512 }
14561513
...@@ -1520,6 +1577,11 @@ pub const Value = extern union {...@@ -1520,6 +1577,11 @@ pub const Value = extern union {
1520 }1577 }
1521 return true;1578 return true;
1522 },1579 },
1580 .function => {
1581 const a_payload = a.castTag(.function).?.data;
1582 const b_payload = b.castTag(.function).?.data;
1583 return a_payload == b_payload;
1584 },
1523 else => {},1585 else => {},
1524 }1586 }
1525 } else if (a_tag == .null_value or b_tag == .null_value) {1587 } else if (a_tag == .null_value or b_tag == .null_value) {
...@@ -1573,6 +1635,7 @@ pub const Value = extern union {...@@ -1573,6 +1635,7 @@ pub const Value = extern union {
1573 pub fn hash(val: Value, ty: Type, hasher: *std.hash.Wyhash) void {1635 pub fn hash(val: Value, ty: Type, hasher: *std.hash.Wyhash) void {
1574 const zig_ty_tag = ty.zigTypeTag();1636 const zig_ty_tag = ty.zigTypeTag();
1575 std.hash.autoHash(hasher, zig_ty_tag);1637 std.hash.autoHash(hasher, zig_ty_tag);
1638 if (val.isUndef()) return;
15761639
1577 switch (zig_ty_tag) {1640 switch (zig_ty_tag) {
1578 .BoundFn => unreachable, // TODO remove this from the language1641 .BoundFn => unreachable, // TODO remove this from the language
...@@ -1694,7 +1757,8 @@ pub const Value = extern union {...@@ -1694,7 +1757,8 @@ pub const Value = extern union {
1694 union_obj.val.hash(active_field_ty, hasher);1757 union_obj.val.hash(active_field_ty, hasher);
1695 },1758 },
1696 .Fn => {1759 .Fn => {
1697 @panic("TODO implement hashing function values");1760 const func = val.castTag(.function).?.data;
1761 return std.hash.autoHash(hasher, func.owner_decl);
1698 },1762 },
1699 .Frame => {1763 .Frame => {
1700 @panic("TODO implement hashing frame values");1764 @panic("TODO implement hashing frame values");
...@@ -1703,7 +1767,8 @@ pub const Value = extern union {...@@ -1703,7 +1767,8 @@ pub const Value = extern union {
1703 @panic("TODO implement hashing anyframe values");1767 @panic("TODO implement hashing anyframe values");
1704 },1768 },
1705 .EnumLiteral => {1769 .EnumLiteral => {
1706 @panic("TODO implement hashing enum literal values");1770 const bytes = val.castTag(.enum_literal).?.data;
1771 hasher.update(bytes);
1707 },1772 },
1708 }1773 }
1709 }1774 }
test/behavior.zig+9-12
...@@ -2,22 +2,23 @@ const builtin = @import("builtin");...@@ -2,22 +2,23 @@ const builtin = @import("builtin");
22
3test {3test {
4 // Tests that pass for stage1, llvm backend, C backend, wasm backend, arm backend and x86_64 backend.4 // Tests that pass for stage1, llvm backend, C backend, wasm backend, arm backend and x86_64 backend.
5 _ = @import("behavior/align.zig");
6 _ = @import("behavior/array.zig");
7 _ = @import("behavior/bool.zig");
8 _ = @import("behavior/bugs/655.zig");
9 _ = @import("behavior/bugs/679.zig");
5 _ = @import("behavior/bugs/1111.zig");10 _ = @import("behavior/bugs/1111.zig");
6 _ = @import("behavior/bugs/2346.zig");11 _ = @import("behavior/bugs/2346.zig");
7 _ = @import("behavior/slice_sentinel_comptime.zig");
8 _ = @import("behavior/bugs/679.zig");
9 _ = @import("behavior/bugs/6850.zig");12 _ = @import("behavior/bugs/6850.zig");
13 _ = @import("behavior/cast.zig");
14 _ = @import("behavior/comptime_memory.zig");
10 _ = @import("behavior/fn_in_struct_in_comptime.zig");15 _ = @import("behavior/fn_in_struct_in_comptime.zig");
11 _ = @import("behavior/hasdecl.zig");16 _ = @import("behavior/hasdecl.zig");
12 _ = @import("behavior/hasfield.zig");17 _ = @import("behavior/hasfield.zig");
13 _ = @import("behavior/prefetch.zig");18 _ = @import("behavior/prefetch.zig");
14 _ = @import("behavior/pub_enum.zig");19 _ = @import("behavior/pub_enum.zig");
20 _ = @import("behavior/slice_sentinel_comptime.zig");
15 _ = @import("behavior/type.zig");21 _ = @import("behavior/type.zig");
16 _ = @import("behavior/bugs/655.zig");
17 _ = @import("behavior/bool.zig");
18 _ = @import("behavior/align.zig");
19 _ = @import("behavior/array.zig");
20 _ = @import("behavior/cast.zig");
2122
22 if (builtin.zig_backend != .stage2_arm and builtin.zig_backend != .stage2_x86_64) {23 if (builtin.zig_backend != .stage2_arm and builtin.zig_backend != .stage2_x86_64) {
23 // Tests that pass for stage1, llvm backend, C backend, wasm backend.24 // Tests that pass for stage1, llvm backend, C backend, wasm backend.
...@@ -113,11 +114,7 @@ test {...@@ -113,11 +114,7 @@ test {
113 _ = @import("behavior/switch.zig");114 _ = @import("behavior/switch.zig");
114 _ = @import("behavior/widening.zig");115 _ = @import("behavior/widening.zig");
115116
116 if (builtin.zig_backend != .stage1) {117 if (builtin.zig_backend == .stage1) {
117 // When all comptime_memory.zig tests pass, #9646 can be closed.
118 // _ = @import("behavior/comptime_memory.zig");
119 _ = @import("behavior/slice_stage2.zig");
120 } else {
121 // Tests that only pass for the stage1 backend.118 // Tests that only pass for the stage1 backend.
122 _ = @import("behavior/align_stage1.zig");119 _ = @import("behavior/align_stage1.zig");
123 if (builtin.os.tag != .wasi) {120 if (builtin.os.tag != .wasi) {
test/behavior/align.zig+25-2
...@@ -165,8 +165,9 @@ fn give() anyerror!u128 {...@@ -165,8 +165,9 @@ fn give() anyerror!u128 {
165}165}
166166
167test "page aligned array on stack" {167test "page aligned array on stack" {
168 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm or168 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
169 builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;169 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
170 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
170171
171 // Large alignment value to make it hard to accidentally pass.172 // Large alignment value to make it hard to accidentally pass.
172 var array align(0x1000) = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };173 var array align(0x1000) = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
...@@ -181,3 +182,25 @@ test "page aligned array on stack" {...@@ -181,3 +182,25 @@ test "page aligned array on stack" {
181 try expect(number1 == 42);182 try expect(number1 == 42);
182 try expect(number2 == 43);183 try expect(number2 == 43);
183}184}
185
186fn derp() align(@sizeOf(usize) * 2) i32 {
187 return 1234;
188}
189fn noop1() align(1) void {}
190fn noop4() align(4) void {}
191
192test "function alignment" {
193 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
194 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
195 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
196 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
197
198 // function alignment is a compile error on wasm32/wasm64
199 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
200
201 try expect(derp() == 1234);
202 try expect(@TypeOf(noop1) == fn () align(1) void);
203 try expect(@TypeOf(noop4) == fn () align(4) void);
204 noop1();
205 noop4();
206}
test/behavior/align_stage1.zig-17
...@@ -3,23 +3,6 @@ const expect = std.testing.expect;...@@ -3,23 +3,6 @@ const expect = std.testing.expect;
3const builtin = @import("builtin");3const builtin = @import("builtin");
4const native_arch = builtin.target.cpu.arch;4const native_arch = builtin.target.cpu.arch;
55
6fn derp() align(@sizeOf(usize) * 2) i32 {
7 return 1234;
8}
9fn noop1() align(1) void {}
10fn noop4() align(4) void {}
11
12test "function alignment" {
13 // function alignment is a compile error on wasm32/wasm64
14 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
15
16 try expect(derp() == 1234);
17 try expect(@TypeOf(noop1) == fn () align(1) void);
18 try expect(@TypeOf(noop4) == fn () align(4) void);
19 noop1();
20 noop4();
21}
22
23test "implicitly decreasing fn alignment" {6test "implicitly decreasing fn alignment" {
24 // function alignment is a compile error on wasm32/wasm647 // function alignment is a compile error on wasm32/wasm64
25 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;8 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
test/behavior/basic.zig+3-1
...@@ -259,6 +259,8 @@ fn fB() []const u8 {...@@ -259,6 +259,8 @@ fn fB() []const u8 {
259}259}
260260
261test "call function pointer in struct" {261test "call function pointer in struct" {
262 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
263
262 try expect(mem.eql(u8, f3(true), "a"));264 try expect(mem.eql(u8, f3(true), "a"));
263 try expect(mem.eql(u8, f3(false), "b"));265 try expect(mem.eql(u8, f3(false), "b"));
264}266}
...@@ -276,7 +278,7 @@ fn f3(x: bool) []const u8 {...@@ -276,7 +278,7 @@ fn f3(x: bool) []const u8 {
276}278}
277279
278const FnPtrWrapper = struct {280const FnPtrWrapper = struct {
279 fn_ptr: fn () []const u8,281 fn_ptr: *const fn () []const u8,
280};282};
281283
282test "const ptr from var variable" {284test "const ptr from var variable" {
test/behavior/basic_llvm.zig+3-1
...@@ -205,9 +205,11 @@ test "multiline string literal is null terminated" {...@@ -205,9 +205,11 @@ test "multiline string literal is null terminated" {
205}205}
206206
207test "self reference through fn ptr field" {207test "self reference through fn ptr field" {
208 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
209
208 const S = struct {210 const S = struct {
209 const A = struct {211 const A = struct {
210 f: fn (A) u8,212 f: *const fn (A) u8,
211 };213 };
212214
213 fn foo(a: A) u8 {215 fn foo(a: A) u8 {
test/behavior/bugs/1500.zig+1-1
...@@ -2,7 +2,7 @@ const A = struct {...@@ -2,7 +2,7 @@ const A = struct {
2 b: B,2 b: B,
3};3};
44
5const B = fn (A) void;5const B = *const fn (A) void;
66
7test "allow these dependencies" {7test "allow these dependencies" {
8 var a: A = undefined;8 var a: A = undefined;
test/behavior/bugs/3112.zig+4-1
...@@ -1,9 +1,10 @@...@@ -1,9 +1,10 @@
1const builtin = @import("builtin");
1const std = @import("std");2const std = @import("std");
2const expect = std.testing.expect;3const expect = std.testing.expect;
34
4const State = struct {5const State = struct {
5 const Self = @This();6 const Self = @This();
6 enter: fn (previous: ?Self) void,7 enter: *const fn (previous: ?Self) void,
7};8};
89
9fn prev(p: ?State) void {10fn prev(p: ?State) void {
...@@ -11,6 +12,8 @@ fn prev(p: ?State) void {...@@ -11,6 +12,8 @@ fn prev(p: ?State) void {
11}12}
1213
13test "zig test crash" {14test "zig test crash" {
15 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
16
14 var global: State = undefined;17 var global: State = undefined;
15 global.enter = prev;18 global.enter = prev;
16 global.enter(null);19 global.enter(null);
test/behavior/cast_llvm.zig+9-3
...@@ -47,12 +47,14 @@ fn incrementVoidPtrArray(array: ?*anyopaque, len: usize) void {...@@ -47,12 +47,14 @@ fn incrementVoidPtrArray(array: ?*anyopaque, len: usize) void {
47}47}
4848
49test "compile time int to ptr of function" {49test "compile time int to ptr of function" {
50 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
50 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) return error.SkipZigTest; // TODO51 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) return error.SkipZigTest; // TODO
52
51 try foobar(FUNCTION_CONSTANT);53 try foobar(FUNCTION_CONSTANT);
52}54}
5355
54pub const FUNCTION_CONSTANT = @intToPtr(PFN_void, maxInt(usize));56pub const FUNCTION_CONSTANT = @intToPtr(PFN_void, maxInt(usize));
55pub const PFN_void = fn (*anyopaque) callconv(.C) void;57pub const PFN_void = *const fn (*anyopaque) callconv(.C) void;
5658
57fn foobar(func: PFN_void) !void {59fn foobar(func: PFN_void) !void {
58 try std.testing.expect(@ptrToInt(func) == maxInt(usize));60 try std.testing.expect(@ptrToInt(func) == maxInt(usize));
...@@ -153,8 +155,12 @@ test "implicit cast *[0]T to E![]const u8" {...@@ -153,8 +155,12 @@ test "implicit cast *[0]T to E![]const u8" {
153}155}
154156
155var global_array: [4]u8 = undefined;157var global_array: [4]u8 = undefined;
156test "cast from array reference to fn" {158test "cast from array reference to fn: comptime fn ptr" {
157 const f = @ptrCast(fn () callconv(.C) void, &global_array);159 const f = @ptrCast(*const fn () callconv(.C) void, &global_array);
160 try expect(@ptrToInt(f) == @ptrToInt(&global_array));
161}
162test "cast from array reference to fn: runtime fn ptr" {
163 var f = @ptrCast(*const fn () callconv(.C) void, &global_array);
158 try expect(@ptrToInt(f) == @ptrToInt(&global_array));164 try expect(@ptrToInt(f) == @ptrToInt(&global_array));
159}165}
160166
test/behavior/comptime_memory.zig+98-1
...@@ -1,8 +1,15 @@...@@ -1,8 +1,15 @@
1const endian = @import("builtin").cpu.arch.endian();1const builtin = @import("builtin");
2const endian = builtin.cpu.arch.endian();
2const testing = @import("std").testing;3const testing = @import("std").testing;
3const ptr_size = @sizeOf(usize);4const ptr_size = @sizeOf(usize);
45
5test "type pun signed and unsigned as single pointer" {6test "type pun signed and unsigned as single pointer" {
7 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
8 if (builtin.zig_backend != .stage1) {
9 // TODO https://github.com/ziglang/zig/issues/9646
10 return error.SkipZigTest;
11 }
12
6 comptime {13 comptime {
7 var x: u32 = 0;14 var x: u32 = 0;
8 const y = @ptrCast(*i32, &x);15 const y = @ptrCast(*i32, &x);
...@@ -12,6 +19,12 @@ test "type pun signed and unsigned as single pointer" {...@@ -12,6 +19,12 @@ test "type pun signed and unsigned as single pointer" {
12}19}
1320
14test "type pun signed and unsigned as many pointer" {21test "type pun signed and unsigned as many pointer" {
22 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
23 if (builtin.zig_backend != .stage1) {
24 // TODO https://github.com/ziglang/zig/issues/9646
25 return error.SkipZigTest;
26 }
27
15 comptime {28 comptime {
16 var x: u32 = 0;29 var x: u32 = 0;
17 const y = @ptrCast([*]i32, &x);30 const y = @ptrCast([*]i32, &x);
...@@ -21,6 +34,12 @@ test "type pun signed and unsigned as many pointer" {...@@ -21,6 +34,12 @@ test "type pun signed and unsigned as many pointer" {
21}34}
2235
23test "type pun signed and unsigned as array pointer" {36test "type pun signed and unsigned as array pointer" {
37 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
38 if (builtin.zig_backend != .stage1) {
39 // TODO https://github.com/ziglang/zig/issues/9646
40 return error.SkipZigTest;
41 }
42
24 comptime {43 comptime {
25 var x: u32 = 0;44 var x: u32 = 0;
26 const y = @ptrCast(*[1]i32, &x);45 const y = @ptrCast(*[1]i32, &x);
...@@ -30,6 +49,12 @@ test "type pun signed and unsigned as array pointer" {...@@ -30,6 +49,12 @@ test "type pun signed and unsigned as array pointer" {
30}49}
3150
32test "type pun signed and unsigned as offset many pointer" {51test "type pun signed and unsigned as offset many pointer" {
52 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
53 if (builtin.zig_backend != .stage1) {
54 // TODO https://github.com/ziglang/zig/issues/9646
55 return error.SkipZigTest;
56 }
57
33 comptime {58 comptime {
34 var x: u32 = 0;59 var x: u32 = 0;
35 var y = @ptrCast([*]i32, &x);60 var y = @ptrCast([*]i32, &x);
...@@ -40,6 +65,12 @@ test "type pun signed and unsigned as offset many pointer" {...@@ -40,6 +65,12 @@ test "type pun signed and unsigned as offset many pointer" {
40}65}
4166
42test "type pun signed and unsigned as array pointer" {67test "type pun signed and unsigned as array pointer" {
68 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
69 if (builtin.zig_backend != .stage1) {
70 // TODO https://github.com/ziglang/zig/issues/9646
71 return error.SkipZigTest;
72 }
73
43 comptime {74 comptime {
44 var x: u32 = 0;75 var x: u32 = 0;
45 const y = @ptrCast([*]i32, &x) - 10;76 const y = @ptrCast([*]i32, &x) - 10;
...@@ -50,6 +81,12 @@ test "type pun signed and unsigned as array pointer" {...@@ -50,6 +81,12 @@ test "type pun signed and unsigned as array pointer" {
50}81}
5182
52test "type pun value and struct" {83test "type pun value and struct" {
84 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
85 if (builtin.zig_backend != .stage1) {
86 // TODO https://github.com/ziglang/zig/issues/9646
87 return error.SkipZigTest;
88 }
89
53 comptime {90 comptime {
54 const StructOfU32 = extern struct { x: u32 };91 const StructOfU32 = extern struct { x: u32 };
55 var inst: StructOfU32 = .{ .x = 0 };92 var inst: StructOfU32 = .{ .x = 0 };
...@@ -64,6 +101,12 @@ fn bigToNativeEndian(comptime T: type, v: T) T {...@@ -64,6 +101,12 @@ fn bigToNativeEndian(comptime T: type, v: T) T {
64 return if (endian == .Big) v else @byteSwap(T, v);101 return if (endian == .Big) v else @byteSwap(T, v);
65}102}
66test "type pun endianness" {103test "type pun endianness" {
104 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
105 if (builtin.zig_backend != .stage1) {
106 // TODO https://github.com/ziglang/zig/issues/9646
107 return error.SkipZigTest;
108 }
109
67 comptime {110 comptime {
68 const StructOfBytes = extern struct { x: [4]u8 };111 const StructOfBytes = extern struct { x: [4]u8 };
69 var inst: StructOfBytes = .{ .x = [4]u8{ 0, 0, 0, 0 } };112 var inst: StructOfBytes = .{ .x = [4]u8{ 0, 0, 0, 0 } };
...@@ -155,6 +198,12 @@ fn doTypePunBitsTest(as_bits: *Bits) !void {...@@ -155,6 +198,12 @@ fn doTypePunBitsTest(as_bits: *Bits) !void {
155}198}
156199
157test "type pun bits" {200test "type pun bits" {
201 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
202 if (builtin.zig_backend != .stage1) {
203 // TODO https://github.com/ziglang/zig/issues/9646
204 return error.SkipZigTest;
205 }
206
158 comptime {207 comptime {
159 var v: u32 = undefined;208 var v: u32 = undefined;
160 try doTypePunBitsTest(@ptrCast(*Bits, &v));209 try doTypePunBitsTest(@ptrCast(*Bits, &v));
...@@ -167,6 +216,12 @@ const imports = struct {...@@ -167,6 +216,12 @@ const imports = struct {
167216
168// Make sure lazy values work on their own, before getting into more complex tests217// Make sure lazy values work on their own, before getting into more complex tests
169test "basic pointer preservation" {218test "basic pointer preservation" {
219 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
220 if (builtin.zig_backend != .stage1) {
221 // TODO https://github.com/ziglang/zig/issues/9646
222 return error.SkipZigTest;
223 }
224
170 comptime {225 comptime {
171 const lazy_address = @ptrToInt(&imports.global_u32);226 const lazy_address = @ptrToInt(&imports.global_u32);
172 try testing.expectEqual(@ptrToInt(&imports.global_u32), lazy_address);227 try testing.expectEqual(@ptrToInt(&imports.global_u32), lazy_address);
...@@ -175,6 +230,12 @@ test "basic pointer preservation" {...@@ -175,6 +230,12 @@ test "basic pointer preservation" {
175}230}
176231
177test "byte copy preserves linker value" {232test "byte copy preserves linker value" {
233 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
234 if (builtin.zig_backend != .stage1) {
235 // TODO https://github.com/ziglang/zig/issues/9646
236 return error.SkipZigTest;
237 }
238
178 const ct_value = comptime blk: {239 const ct_value = comptime blk: {
179 const lazy = &imports.global_u32;240 const lazy = &imports.global_u32;
180 var result: *u32 = undefined;241 var result: *u32 = undefined;
...@@ -193,6 +254,12 @@ test "byte copy preserves linker value" {...@@ -193,6 +254,12 @@ test "byte copy preserves linker value" {
193}254}
194255
195test "unordered byte copy preserves linker value" {256test "unordered byte copy preserves linker value" {
257 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
258 if (builtin.zig_backend != .stage1) {
259 // TODO https://github.com/ziglang/zig/issues/9646
260 return error.SkipZigTest;
261 }
262
196 const ct_value = comptime blk: {263 const ct_value = comptime blk: {
197 const lazy = &imports.global_u32;264 const lazy = &imports.global_u32;
198 var result: *u32 = undefined;265 var result: *u32 = undefined;
...@@ -212,6 +279,12 @@ test "unordered byte copy preserves linker value" {...@@ -212,6 +279,12 @@ test "unordered byte copy preserves linker value" {
212}279}
213280
214test "shuffle chunks of linker value" {281test "shuffle chunks of linker value" {
282 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
283 if (builtin.zig_backend != .stage1) {
284 // TODO https://github.com/ziglang/zig/issues/9646
285 return error.SkipZigTest;
286 }
287
215 const lazy_address = @ptrToInt(&imports.global_u32);288 const lazy_address = @ptrToInt(&imports.global_u32);
216 const shuffled1_rt = shuffle(lazy_address, Bits, ShuffledBits);289 const shuffled1_rt = shuffle(lazy_address, Bits, ShuffledBits);
217 const unshuffled1_rt = shuffle(shuffled1_rt, ShuffledBits, Bits);290 const unshuffled1_rt = shuffle(shuffled1_rt, ShuffledBits, Bits);
...@@ -225,6 +298,12 @@ test "shuffle chunks of linker value" {...@@ -225,6 +298,12 @@ test "shuffle chunks of linker value" {
225}298}
226299
227test "dance on linker values" {300test "dance on linker values" {
301 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
302 if (builtin.zig_backend != .stage1) {
303 // TODO https://github.com/ziglang/zig/issues/9646
304 return error.SkipZigTest;
305 }
306
228 comptime {307 comptime {
229 var arr: [2]usize = undefined;308 var arr: [2]usize = undefined;
230 arr[0] = @ptrToInt(&imports.global_u32);309 arr[0] = @ptrToInt(&imports.global_u32);
...@@ -251,6 +330,12 @@ test "dance on linker values" {...@@ -251,6 +330,12 @@ test "dance on linker values" {
251}330}
252331
253test "offset array ptr by element size" {332test "offset array ptr by element size" {
333 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
334 if (builtin.zig_backend != .stage1) {
335 // TODO https://github.com/ziglang/zig/issues/9646
336 return error.SkipZigTest;
337 }
338
254 comptime {339 comptime {
255 const VirtualStruct = struct { x: u32 };340 const VirtualStruct = struct { x: u32 };
256 var arr: [4]VirtualStruct = .{341 var arr: [4]VirtualStruct = .{
...@@ -273,6 +358,12 @@ test "offset array ptr by element size" {...@@ -273,6 +358,12 @@ test "offset array ptr by element size" {
273}358}
274359
275test "offset instance by field size" {360test "offset instance by field size" {
361 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
362 if (builtin.zig_backend != .stage1) {
363 // TODO https://github.com/ziglang/zig/issues/9646
364 return error.SkipZigTest;
365 }
366
276 comptime {367 comptime {
277 const VirtualStruct = struct { x: u32, y: u32, z: u32, w: u32 };368 const VirtualStruct = struct { x: u32, y: u32, z: u32, w: u32 };
278 var inst = VirtualStruct{ .x = 0, .y = 1, .z = 2, .w = 3 };369 var inst = VirtualStruct{ .x = 0, .y = 1, .z = 2, .w = 3 };
...@@ -293,6 +384,12 @@ test "offset instance by field size" {...@@ -293,6 +384,12 @@ test "offset instance by field size" {
293}384}
294385
295test "offset field ptr by enclosing array element size" {386test "offset field ptr by enclosing array element size" {
387 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
388 if (builtin.zig_backend != .stage1) {
389 // TODO https://github.com/ziglang/zig/issues/9646
390 return error.SkipZigTest;
391 }
392
296 comptime {393 comptime {
297 const VirtualStruct = struct { x: u32 };394 const VirtualStruct = struct { x: u32 };
298 var arr: [4]VirtualStruct = .{395 var arr: [4]VirtualStruct = .{
test/behavior/error.zig+1
...@@ -1,3 +1,4 @@...@@ -1,3 +1,4 @@
1const builtin = @import("builtin");
1const std = @import("std");2const std = @import("std");
2const expect = std.testing.expect;3const expect = std.testing.expect;
3const expectError = std.testing.expectError;4const expectError = std.testing.expectError;
test/behavior/fn.zig+9-3
...@@ -57,7 +57,7 @@ test "assign inline fn to const variable" {...@@ -57,7 +57,7 @@ test "assign inline fn to const variable" {
5757
58inline fn inlineFn() void {}58inline fn inlineFn() void {}
5959
60fn outer(y: u32) fn (u32) u32 {60fn outer(y: u32) *const fn (u32) u32 {
61 const Y = @TypeOf(y);61 const Y = @TypeOf(y);
62 const st = struct {62 const st = struct {
63 fn get(z: u32) u32 {63 fn get(z: u32) u32 {
...@@ -68,6 +68,8 @@ fn outer(y: u32) fn (u32) u32 {...@@ -68,6 +68,8 @@ fn outer(y: u32) fn (u32) u32 {
68}68}
6969
70test "return inner function which references comptime variable of outer function" {70test "return inner function which references comptime variable of outer function" {
71 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
72
71 var func = outer(10);73 var func = outer(10);
72 try expect(func(3) == 7);74 try expect(func(3) == 7);
73}75}
...@@ -92,6 +94,8 @@ test "discard the result of a function that returns a struct" {...@@ -92,6 +94,8 @@ test "discard the result of a function that returns a struct" {
92}94}
9395
94test "inline function call that calls optional function pointer, return pointer at callsite interacts correctly with callsite return type" {96test "inline function call that calls optional function pointer, return pointer at callsite interacts correctly with callsite return type" {
97 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
98
95 const S = struct {99 const S = struct {
96 field: u32,100 field: u32,
97101
...@@ -113,7 +117,7 @@ test "inline function call that calls optional function pointer, return pointer...@@ -113,7 +117,7 @@ test "inline function call that calls optional function pointer, return pointer
113 return bar2.?();117 return bar2.?();
114 }118 }
115119
116 var bar2: ?fn () u32 = null;120 var bar2: ?*const fn () u32 = null;
117121
118 fn actualFn() u32 {122 fn actualFn() u32 {
119 return 1234;123 return 1234;
...@@ -135,8 +139,10 @@ fn fnWithUnreachable() noreturn {...@@ -135,8 +139,10 @@ fn fnWithUnreachable() noreturn {
135}139}
136140
137test "extern struct with stdcallcc fn pointer" {141test "extern struct with stdcallcc fn pointer" {
142 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
143
138 const S = extern struct {144 const S = extern struct {
139 ptr: fn () callconv(if (builtin.target.cpu.arch == .i386) .Stdcall else .C) i32,145 ptr: *const fn () callconv(if (builtin.target.cpu.arch == .i386) .Stdcall else .C) i32,
140146
141 fn foo() callconv(if (builtin.target.cpu.arch == .i386) .Stdcall else .C) i32 {147 fn foo() callconv(if (builtin.target.cpu.arch == .i386) .Stdcall else .C) i32 {
142 return 1234;148 return 1234;
test/behavior/inttoptr.zig+7-5
...@@ -1,14 +1,16 @@...@@ -1,14 +1,16 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
22
3test "casting random address to function pointer" {3test "casting integer address to function pointer" {
4 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
4 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) return error.SkipZigTest; // TODO5 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) return error.SkipZigTest; // TODO
5 randomAddressToFunction();6
6 comptime randomAddressToFunction();7 addressToFunction();
8 comptime addressToFunction();
7}9}
810
9fn randomAddressToFunction() void {11fn addressToFunction() void {
10 var addr: usize = 0xdeadbeef;12 var addr: usize = 0xdeadbeef;
11 _ = @intToPtr(fn () void, addr);13 _ = @intToPtr(*const fn () void, addr);
12}14}
1315
14test "mutate through ptr initialized with constant intToPtr value" {16test "mutate through ptr initialized with constant intToPtr value" {
test/behavior/member_func.zig+8-2
...@@ -1,8 +1,10 @@...@@ -1,8 +1,10 @@
1const expect = @import("std").testing.expect;1const builtin = @import("builtin");
2const std = @import("std");
3const expect = std.testing.expect;
24
3const HasFuncs = struct {5const HasFuncs = struct {
4 state: u32,6 state: u32,
5 func_field: fn (u32) u32,7 func_field: *const fn (u32) u32,
68
7 fn inc(self: *HasFuncs) void {9 fn inc(self: *HasFuncs) void {
8 self.state += 1;10 self.state += 1;
...@@ -25,6 +27,8 @@ const HasFuncs = struct {...@@ -25,6 +27,8 @@ const HasFuncs = struct {
25};27};
2628
27test "standard field calls" {29test "standard field calls" {
30 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
31
28 try expect(HasFuncs.one(0) == 1);32 try expect(HasFuncs.one(0) == 1);
29 try expect(HasFuncs.two(0) == 2);33 try expect(HasFuncs.two(0) == 2);
3034
...@@ -64,6 +68,8 @@ test "standard field calls" {...@@ -64,6 +68,8 @@ test "standard field calls" {
64}68}
6569
66test "@field field calls" {70test "@field field calls" {
71 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
72
67 try expect(@field(HasFuncs, "one")(0) == 1);73 try expect(@field(HasFuncs, "one")(0) == 1);
68 try expect(@field(HasFuncs, "two")(0) == 2);74 try expect(@field(HasFuncs, "two")(0) == 2);
6975
test/behavior/slice.zig+13
...@@ -1,3 +1,4 @@...@@ -1,3 +1,4 @@
1const builtin = @import("builtin");
1const std = @import("std");2const std = @import("std");
2const expect = std.testing.expect;3const expect = std.testing.expect;
3const expectEqualSlices = std.testing.expectEqualSlices;4const expectEqualSlices = std.testing.expectEqualSlices;
...@@ -166,3 +167,15 @@ test "slicing zero length array" {...@@ -166,3 +167,15 @@ test "slicing zero length array" {
166 try expect(mem.eql(u8, s1, ""));167 try expect(mem.eql(u8, s1, ""));
167 try expect(mem.eql(u32, s2, &[_]u32{}));168 try expect(mem.eql(u32, s2, &[_]u32{}));
168}169}
170
171const x = @intToPtr([*]i32, 0x1000)[0..0x500];
172const y = x[0x100..];
173test "compile time slice of pointer to hard coded address" {
174 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
175
176 try expect(@ptrToInt(x) == 0x1000);
177 try expect(x.len == 0x500);
178
179 try expect(@ptrToInt(y) == 0x1400);
180 try expect(y.len == 0x400);
181}
test/behavior/slice_stage2.zig deleted-12
...@@ -1,12 +0,0 @@
1const std = @import("std");
2const expect = std.testing.expect;
3
4const x = @intToPtr([*]i32, 0x1000)[0..0x500];
5const y = x[0x100..];
6test "compile time slice of pointer to hard coded address" {
7 try expect(@ptrToInt(x) == 0x1000);
8 try expect(x.len == 0x500);
9
10 try expect(@ptrToInt(y) == 0x1400);
11 try expect(y.len == 0x400);
12}
test/behavior/union.zig+4-1
...@@ -1,3 +1,4 @@...@@ -1,3 +1,4 @@
1const builtin = @import("builtin");
1const std = @import("std");2const std = @import("std");
2const expect = std.testing.expect;3const expect = std.testing.expect;
3const expectEqual = std.testing.expectEqual;4const expectEqual = std.testing.expectEqual;
...@@ -166,8 +167,10 @@ test "union with specified enum tag" {...@@ -166,8 +167,10 @@ test "union with specified enum tag" {
166}167}
167168
168test "packed union generates correctly aligned LLVM type" {169test "packed union generates correctly aligned LLVM type" {
170 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
171
169 const U = packed union {172 const U = packed union {
170 f1: fn () error{TestUnexpectedResult}!void,173 f1: *const fn () error{TestUnexpectedResult}!void,
171 f2: u32,174 f2: u32,
172 };175 };
173 var foo = [_]U{176 var foo = [_]U{
test/stage2/arm.zig+1-1
...@@ -751,7 +751,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -751,7 +751,7 @@ pub fn addCases(ctx: *TestContext) !void {
751 {751 {
752 var case = ctx.exe("function pointers", linux_arm);752 var case = ctx.exe("function pointers", linux_arm);
753 case.addCompareOutput(753 case.addCompareOutput(
754 \\const PrintFn = fn () void;754 \\const PrintFn = *const fn () void;
755 \\755 \\
756 \\pub fn main() void {756 \\pub fn main() void {
757 \\ var printFn: PrintFn = stopSayingThat;757 \\ var printFn: PrintFn = stopSayingThat;