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) {
730730/// therefore must be kept in sync with the compiler implementation.
731731pub const TestFn = struct {
732732 name: []const u8,
733 func: fn () anyerror!void,
733 func: testFnProto,
734734 async_frame_size: ?usize,
735735};
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
737743/// This function type is used by the Zig language code generation and
738744/// therefore must be kept in sync with the compiler implementation.
739745pub const PanicFn = fn ([]const u8, ?*StackTrace) noreturn;
src/AstGen.zig+321-18
......@@ -3240,7 +3240,8 @@ fn fnDecl(
32403240 const doc_comment_index = try astgen.docCommentAsString(fn_proto.firstToken());
32413241
32423242 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
32453246 var params_scope = &fn_gz.base;
32463247 const is_var_args = is_var_args: {
......@@ -3380,7 +3381,7 @@ fn fnDecl(
33803381 .param_block = block_inst,
33813382 .body_gz = null,
33823383 .cc = cc,
3383 .align_inst = .none, // passed in the per-decl data
3384 .align_inst = align_inst,
33843385 .lib_name = lib_name,
33853386 .is_var_args = is_var_args,
33863387 .is_inferred_error = false,
......@@ -3423,7 +3424,7 @@ fn fnDecl(
34233424 .ret_br = ret_br,
34243425 .body_gz = &fn_gz,
34253426 .cc = cc,
3426 .align_inst = .none, // passed in the per-decl data
3427 .align_inst = align_inst,
34273428 .lib_name = lib_name,
34283429 .is_var_args = is_var_args,
34293430 .is_inferred_error = is_inferred_error,
......@@ -3449,9 +3450,6 @@ fn fnDecl(
34493450 wip_members.appendToDecl(fn_name_str_index);
34503451 wip_members.appendToDecl(block_inst);
34513452 wip_members.appendToDecl(doc_comment_index);
3452 if (align_inst != .none) {
3453 wip_members.appendToDecl(@enumToInt(align_inst));
3454 }
34553453 if (has_section_or_addrspace) {
34563454 wip_members.appendToDecl(@enumToInt(section_inst));
34573455 wip_members.appendToDecl(@enumToInt(addrspace_inst));
......@@ -3830,7 +3828,8 @@ fn structDeclInner(
38303828 .fields_len = 0,
38313829 .body_len = 0,
38323830 .decls_len = 0,
3833 .known_has_bits = false,
3831 .known_non_opv = false,
3832 .known_comptime_only = false,
38343833 });
38353834 return indexToRef(decl_inst);
38363835 }
......@@ -3871,7 +3870,8 @@ fn structDeclInner(
38713870 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size);
38723871 defer wip_members.deinit();
38733872
3874 var known_has_bits = false;
3873 var known_non_opv = false;
3874 var known_comptime_only = false;
38753875 for (container_decl.ast.members) |member_node| {
38763876 const member = switch (try containerMember(gz, &namespace.base, &wip_members, member_node)) {
38773877 .decl => continue,
......@@ -3894,7 +3894,10 @@ fn structDeclInner(
38943894 const doc_comment_index = try astgen.docCommentAsString(member.firstToken());
38953895 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
38993902 const have_align = member.ast.align_expr != 0;
39003903 const have_value = member.ast.value_expr != 0;
......@@ -3928,7 +3931,8 @@ fn structDeclInner(
39283931 .body_len = @intCast(u32, body.len),
39293932 .fields_len = field_count,
39303933 .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,
39323936 });
39333937
39343938 wip_members.finishBits(bits_per_field);
......@@ -8197,7 +8201,9 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.Ev
81978201 }
81988202}
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 {
82018207 const node_tags = tree.nodes.items(.tag);
82028208 const node_datas = tree.nodes.items(.data);
82038209
......@@ -8243,7 +8249,6 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {
82438249 .multiline_string_literal,
82448250 .char_literal,
82458251 .unreachable_literal,
8246 .identifier,
82478252 .error_set_decl,
82488253 .container_decl,
82498254 .container_decl_trailing,
......@@ -8357,6 +8362,11 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {
83578362 .builtin_call_comma,
83588363 .builtin_call_two,
83598364 .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,
83608370 => return false,
83618371
83628372 // Forward the question to the LHS sub-expression.
......@@ -8368,10 +8378,6 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {
83688378 .unwrap_optional,
83698379 => node = node_datas[node].lhs,
83708380
8371 .fn_proto_simple,
8372 .fn_proto_multi,
8373 .fn_proto_one,
8374 .fn_proto,
83758381 .ptr_type_aligned,
83768382 .ptr_type_sentinel,
83778383 .ptr_type,
......@@ -8380,6 +8386,301 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {
83808386 .anyframe_type,
83818387 .array_type_sentinel,
83828388 => 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 },
83838684 }
83848685 }
83858686}
......@@ -10120,7 +10421,8 @@ const GenZir = struct {
1012010421 fields_len: u32,
1012110422 decls_len: u32,
1012210423 layout: std.builtin.TypeInfo.ContainerLayout,
10123 known_has_bits: bool,
10424 known_non_opv: bool,
10425 known_comptime_only: bool,
1012410426 }) !void {
1012510427 const astgen = gz.astgen;
1012610428 const gpa = astgen.gpa;
......@@ -10150,7 +10452,8 @@ const GenZir = struct {
1015010452 .has_body_len = args.body_len != 0,
1015110453 .has_fields_len = args.fields_len != 0,
1015210454 .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,
1015410457 .name_strategy = gz.anon_name_strategy,
1015510458 .layout = args.layout,
1015610459 }),
src/Compilation.zig-1
......@@ -2703,7 +2703,6 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress
27032703
27042704 const module = comp.bin_file.options.module.?;
27052705 assert(decl.has_tv);
2706 assert(decl.ty.hasCodeGenBits());
27072706
27082707 if (decl.alive) {
27092708 try module.linkerUpdateDecl(decl);
src/Module.zig+141-17
......@@ -848,9 +848,11 @@ pub const Struct = struct {
848848 // which `have_layout` does not ensure.
849849 fully_resolved,
850850 },
851 /// If true, definitely nonzero size at runtime. If false, resolving the fields
852 /// is necessary to determine whether it has bits at runtime.
853 known_has_bits: bool,
851 /// If true, has more than one possible value. However it may still be non-runtime type
852 /// if it is a comptime-only type.
853 /// If false, resolving the fields is necessary to determine whether the type has only
854 /// one possible value.
855 known_non_opv: bool,
854856 requires_comptime: RequiresComptime = .unknown,
855857
856858 pub const Fields = std.StringArrayHashMapUnmanaged(Field);
......@@ -898,6 +900,45 @@ pub const Struct = struct {
898900 };
899901 }
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
901942 pub fn haveFieldTypes(s: Struct) bool {
902943 return switch (s.status) {
903944 .none,
......@@ -1063,6 +1104,33 @@ pub const Union = struct {
10631104 };
10641105 }
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
10661134 pub fn haveFieldTypes(u: Union) bool {
10671135 return switch (u.status) {
10681136 .none,
......@@ -1080,7 +1148,7 @@ pub const Union = struct {
10801148 pub fn hasAllZeroBitFieldTypes(u: Union) bool {
10811149 assert(u.haveFieldTypes());
10821150 for (u.fields.values()) |field| {
1083 if (field.ty.hasCodeGenBits()) return false;
1151 if (field.ty.hasRuntimeBits()) return false;
10841152 }
10851153 return true;
10861154 }
......@@ -1090,7 +1158,7 @@ pub const Union = struct {
10901158 var most_alignment: u32 = 0;
10911159 var most_index: usize = undefined;
10921160 for (u.fields.values()) |field, i| {
1093 if (!field.ty.hasCodeGenBits()) continue;
1161 if (!field.ty.hasRuntimeBits()) continue;
10941162
10951163 const field_align = a: {
10961164 if (field.abi_align.tag() == .abi_align_default) {
......@@ -1111,7 +1179,7 @@ pub const Union = struct {
11111179 var max_align: u32 = 0;
11121180 if (have_tag) max_align = u.tag_ty.abiAlignment(target);
11131181 for (u.fields.values()) |field| {
1114 if (!field.ty.hasCodeGenBits()) continue;
1182 if (!field.ty.hasRuntimeBits()) continue;
11151183
11161184 const field_align = a: {
11171185 if (field.abi_align.tag() == .abi_align_default) {
......@@ -1164,7 +1232,7 @@ pub const Union = struct {
11641232 var payload_size: u64 = 0;
11651233 var payload_align: u32 = 0;
11661234 for (u.fields.values()) |field, i| {
1167 if (!field.ty.hasCodeGenBits()) continue;
1235 if (!field.ty.hasRuntimeBits()) continue;
11681236
11691237 const field_align = a: {
11701238 if (field.abi_align.tag() == .abi_align_default) {
......@@ -3391,7 +3459,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
33913459 .zir_index = undefined, // set below
33923460 .layout = .Auto,
33933461 .status = .none,
3394 .known_has_bits = undefined,
3462 .known_non_opv = undefined,
33953463 .namespace = .{
33963464 .parent = null,
33973465 .ty = struct_ty,
......@@ -3628,7 +3696,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
36283696 var type_changed = true;
36293697
36303698 if (decl.has_tv) {
3631 prev_type_has_bits = decl.ty.hasCodeGenBits();
3699 prev_type_has_bits = decl.ty.isFnOrHasRuntimeBits();
36323700 type_changed = !decl.ty.eql(decl_tv.ty);
36333701 if (decl.getFunction()) |prev_func| {
36343702 prev_is_inline = prev_func.state == .inline_only;
......@@ -3648,8 +3716,9 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
36483716 decl.analysis = .complete;
36493717 decl.generation = mod.generation;
36503718
3651 const is_inline = decl_tv.ty.fnCallingConvention() == .Inline;
3652 if (!is_inline and decl_tv.ty.hasCodeGenBits()) {
3719 const has_runtime_bits = try sema.fnHasRuntimeBits(&block_scope, src, decl.ty);
3720
3721 if (has_runtime_bits) {
36533722 // We don't fully codegen the decl until later, but we do need to reserve a global
36543723 // offset table index for it. This allows us to codegen decls out of dependency
36553724 // order, increasing how many computations can be done in parallel.
......@@ -3662,6 +3731,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
36623731 mod.comp.bin_file.freeDecl(decl);
36633732 }
36643733
3734 const is_inline = decl.ty.fnCallingConvention() == .Inline;
36653735 if (decl.is_exported) {
36663736 const export_src = src; // TODO make this point at `export` token
36673737 if (is_inline) {
......@@ -3682,6 +3752,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
36823752
36833753 decl.owns_tv = false;
36843754 var queue_linker_work = false;
3755 var is_extern = false;
36853756 switch (decl_tv.val.tag()) {
36863757 .variable => {
36873758 const variable = decl_tv.val.castTag(.variable).?.data;
......@@ -3698,6 +3769,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
36983769 if (decl == owner_decl) {
36993770 decl.owns_tv = true;
37003771 queue_linker_work = true;
3772 is_extern = true;
37013773 }
37023774 },
37033775
......@@ -3723,7 +3795,10 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
37233795 decl.analysis = .complete;
37243796 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) {
37273802 log.debug("queue linker work for {*} ({s})", .{ decl, decl.name });
37283803
37293804 try mod.comp.bin_file.allocateDeclIndexes(decl);
......@@ -4224,7 +4299,7 @@ pub fn clearDecl(
42244299 mod.deleteDeclExports(decl);
42254300
42264301 if (decl.has_tv) {
4227 if (decl.ty.hasCodeGenBits()) {
4302 if (decl.ty.isFnOrHasRuntimeBits()) {
42284303 mod.comp.bin_file.freeDecl(decl);
42294304
42304305 // TODO instead of a union, put this memory trailing Decl objects,
......@@ -4277,7 +4352,7 @@ pub fn deleteUnusedDecl(mod: *Module, decl: *Decl) void {
42774352 switch (mod.comp.bin_file.tag) {
42784353 .c => {}, // this linker backend has already migrated to the new API
42794354 else => if (decl.has_tv) {
4280 if (decl.ty.hasCodeGenBits()) {
4355 if (decl.ty.isFnOrHasRuntimeBits()) {
42814356 mod.comp.bin_file.freeDecl(decl);
42824357 }
42834358 },
......@@ -4662,8 +4737,8 @@ pub fn createAnonymousDeclFromDeclNamed(
46624737 new_decl.src_line = src_decl.src_line;
46634738 new_decl.ty = typed_value.ty;
46644739 new_decl.val = typed_value.val;
4665 new_decl.align_val = Value.initTag(.null_value);
4666 new_decl.linksection_val = Value.initTag(.null_value);
4740 new_decl.align_val = Value.@"null";
4741 new_decl.linksection_val = Value.@"null";
46674742 new_decl.has_tv = true;
46684743 new_decl.analysis = .complete;
46694744 new_decl.generation = mod.generation;
......@@ -4674,7 +4749,7 @@ pub fn createAnonymousDeclFromDeclNamed(
46744749 // if the Decl is referenced by an instruction or another constant. Otherwise,
46754750 // the Decl will be garbage collected by the `codegen_decl` task instead of sent
46764751 // to the linker.
4677 if (typed_value.ty.hasCodeGenBits()) {
4752 if (typed_value.ty.isFnOrHasRuntimeBits()) {
46784753 try mod.comp.bin_file.allocateDeclIndexes(new_decl);
46794754 try mod.comp.anon_work_queue.writeItem(.{ .codegen_decl = new_decl });
46804755 }
......@@ -4905,6 +4980,55 @@ pub const PeerTypeCandidateSrc = union(enum) {
49054980 }
49064981};
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
49085032/// Called from `performAllTheWork`, after all AstGen workers have finished,
49095033/// and before the main semantic analysis loop begins.
49105034pub fn processOutdatedAndDeletedDecls(mod: *Module) !void {
src/Sema.zig+590-185
......@@ -437,9 +437,10 @@ pub const Block = struct {
437437 }
438438 }
439439
440 pub fn startAnonDecl(block: *Block) !WipAnonDecl {
440 pub fn startAnonDecl(block: *Block, src: LazySrcLoc) !WipAnonDecl {
441441 return WipAnonDecl{
442442 .block = block,
443 .src = src,
443444 .new_decl_arena = std.heap.ArenaAllocator.init(block.sema.gpa),
444445 .finished = false,
445446 };
......@@ -447,6 +448,7 @@ pub const Block = struct {
447448
448449 pub const WipAnonDecl = struct {
449450 block: *Block,
451 src: LazySrcLoc,
450452 new_decl_arena: std.heap.ArenaAllocator,
451453 finished: bool,
452454
......@@ -462,11 +464,15 @@ pub const Block = struct {
462464 }
463465
464466 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, .{
466472 .ty = ty,
467473 .val = val,
468474 });
469 errdefer wad.block.sema.mod.abortAnonDecl(new_decl);
475 errdefer sema.mod.abortAnonDecl(new_decl);
470476 try new_decl.finalizeNewArena(&wad.new_decl_arena);
471477 wad.finished = true;
472478 return new_decl;
......@@ -487,20 +493,23 @@ pub fn deinit(sema: *Sema) void {
487493/// Returns only the result from the body that is specified.
488494/// Only appropriate to call when it is determined at comptime that this body
489495/// 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 {
491504 const break_inst = try sema.analyzeBody(block, body);
492505 const break_data = sema.code.instructions.items(.data)[break_inst].@"break";
493506 // For comptime control flow, we need to detect when `analyzeBody` reports
494507 // that we need to break from an outer block. In such case we
495508 // use Zig's error mechanism to send control flow up the stack until
496509 // we find the corresponding block to this break.
497 if (block.is_comptime) {
498 if (block.label) |label| {
499 if (label.zir_block != break_data.block_inst) {
500 sema.comptime_break_inst = break_inst;
501 return error.ComptimeBreak;
502 }
503 }
510 if (block.is_comptime and break_data.block_inst != body_inst) {
511 sema.comptime_break_inst = break_inst;
512 return error.ComptimeBreak;
504513 }
505514 return sema.resolveInst(break_data.operand);
506515}
......@@ -1502,9 +1511,6 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
15021511 const ptr = sema.resolveInst(bin_inst.rhs);
15031512 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
15081514 if (Air.refToIndex(ptr)) |ptr_inst| {
15091515 if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) {
15101516 const air_datas = sema.air_instructions.items(.data);
......@@ -1535,7 +1541,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
15351541 const iac = ptr_val.castTag(.inferred_alloc_comptime).?;
15361542 // There will be only one coerce_result_ptr because we are running at comptime.
15371543 // The alloc will turn into a Decl.
1538 var anon_decl = try block.startAnonDecl();
1544 var anon_decl = try block.startAnonDecl(src);
15391545 defer anon_decl.deinit();
15401546 iac.data.decl = try anon_decl.finish(
15411547 try pointee_ty.copy(anon_decl.arena()),
......@@ -1654,7 +1660,10 @@ pub fn analyzeStructDecl(
16541660 assert(extended.opcode == .struct_decl);
16551661 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
16591668 var extra_index: usize = extended.operand;
16601669 extra_index += @boolToInt(small.has_src_node);
......@@ -1702,7 +1711,7 @@ fn zirStructDecl(
17021711 .zir_index = inst,
17031712 .layout = small.layout,
17041713 .status = .none,
1705 .known_has_bits = undefined,
1714 .known_non_opv = undefined,
17061715 .namespace = .{
17071716 .parent = block.namespace,
17081717 .ty = struct_ty,
......@@ -2528,7 +2537,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
25282537 const bitcast_ty_ref = air_datas[bitcast_inst].ty_op.ty;
25292538
25302539 const new_decl = d: {
2531 var anon_decl = try block.startAnonDecl();
2540 var anon_decl = try block.startAnonDecl(src);
25322541 defer anon_decl.deinit();
25332542 const new_decl = try anon_decl.finish(
25342543 try final_elem_ty.copy(anon_decl.arena()),
......@@ -3112,7 +3121,7 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi
31123121 if (operand_val.tag() == .variable) {
31133122 return sema.failWithNeededComptime(block, src);
31143123 }
3115 var anon_decl = try block.startAnonDecl();
3124 var anon_decl = try block.startAnonDecl(src);
31163125 defer anon_decl.deinit();
31173126 iac.data.decl = try anon_decl.finish(
31183127 try operand_ty.copy(anon_decl.arena()),
......@@ -3184,8 +3193,7 @@ fn addStrLit(sema: *Sema, block: *Block, zir_bytes: []const u8) CompileError!Air
31843193 // after semantic analysis is complete, for example in the case of the initialization
31853194 // expression of a variable declaration. We need the memory to be in the new
31863195 // anonymous Decl's arena.
3187
3188 var anon_decl = try block.startAnonDecl();
3196 var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded);
31893197 defer anon_decl.deinit();
31903198
31913199 const bytes = try anon_decl.arena().dupeZ(u8, zir_bytes);
......@@ -3508,10 +3516,13 @@ fn resolveBlockBody(
35083516 src: LazySrcLoc,
35093517 child_block: *Block,
35103518 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,
35113522 merges: *Block.Merges,
35123523) CompileError!Air.Inst.Ref {
35133524 if (child_block.is_comptime) {
3514 return sema.resolveBody(child_block, body);
3525 return sema.resolveBody(child_block, body, body_inst);
35153526 } else {
35163527 _ = try sema.analyzeBody(child_block, body);
35173528 return sema.analyzeBlockBody(parent_block, src, child_block, merges);
......@@ -4147,7 +4158,7 @@ fn analyzeCall(
41474158 const gpa = sema.gpa;
41484159
41494160 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);
41514162 const is_inline_call = is_comptime_call or modifier == .always_inline or
41524163 func_ty_info.cc == .Inline;
41534164 const result: Air.Inst.Ref = if (is_inline_call) res: {
......@@ -4251,7 +4262,7 @@ fn analyzeCall(
42514262 const param_src = pl_tok.src();
42524263 const extra = sema.code.extraData(Zir.Inst.Param, pl_tok.payload_index);
42534264 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);
42554266 const param_ty = try sema.analyzeAsType(&child_block, param_src, param_ty_inst);
42564267 const arg_src = call_src; // TODO: better source location
42574268 const casted_arg = try sema.coerce(&child_block, param_ty, uncasted_args[arg_i], arg_src);
......@@ -4308,7 +4319,7 @@ fn analyzeCall(
43084319 // on parameters, we must now do the same for the return type as we just did with
43094320 // each of the parameters, resolving the return type and providing it to the child
43104321 // `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);
43124323 const ret_ty_src = func_src; // TODO better source location
43134324 const bare_return_type = try sema.analyzeAsType(&child_block, ret_ty_src, ret_ty_inst);
43144325 // Create a fresh inferred error set type for inline/comptime calls.
......@@ -4576,7 +4587,7 @@ fn analyzeCall(
45764587 }
45774588 } else if (is_anytype) {
45784589 const arg_ty = sema.typeOf(arg);
4579 if (arg_ty.requiresComptime()) {
4590 if (try sema.typeRequiresComptime(block, arg_src, arg_ty)) {
45804591 const arg_val = try sema.resolveConstValue(block, arg_src, arg);
45814592 const child_arg = try child_sema.addConstant(arg_ty, arg_val);
45824593 child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
......@@ -4589,7 +4600,7 @@ fn analyzeCall(
45894600 }
45904601 arg_i += 1;
45914602 }
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| {
45934604 // TODO look up the compile error that happened here and attach a note to it
45944605 // pointing here, at the generic instantiation callsite.
45954606 if (sema.owner_func) |owner_func| {
......@@ -4997,7 +5008,7 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
49975008
49985009 // TODO do we really want to create a Decl for this?
49995010 // 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);
50015012 defer anon_decl.deinit();
50025013
50035014 var names = Module.ErrorSet.NameMap{};
......@@ -5388,10 +5399,9 @@ fn zirFunc(
53885399 const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len];
53895400 extra_index += ret_ty_body.len;
53905401
5391 var body_inst: Zir.Inst.Index = 0;
53925402 var src_locs: Zir.Inst.Func.SrcLocs = undefined;
5393 if (extra.data.body_len != 0) {
5394 body_inst = inst;
5403 const has_body = extra.data.body_len != 0;
5404 if (has_body) {
53955405 extra_index += extra.data.body_len;
53965406 src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
53975407 }
......@@ -5404,13 +5414,14 @@ fn zirFunc(
54045414 return sema.funcCommon(
54055415 block,
54065416 inst_data.src_node,
5407 body_inst,
5417 inst,
54085418 ret_ty_body,
54095419 cc,
54105420 Value.@"null",
54115421 false,
54125422 inferred_error_set,
54135423 false,
5424 has_body,
54145425 src_locs,
54155426 null,
54165427 );
......@@ -5420,17 +5431,17 @@ fn funcCommon(
54205431 sema: *Sema,
54215432 block: *Block,
54225433 src_node_offset: i32,
5423 body_inst: Zir.Inst.Index,
5434 func_inst: Zir.Inst.Index,
54245435 ret_ty_body: []const Zir.Inst.Index,
54255436 cc: std.builtin.CallingConvention,
54265437 align_val: Value,
54275438 var_args: bool,
54285439 inferred_error_set: bool,
54295440 is_extern: bool,
5441 has_body: bool,
54305442 src_locs: Zir.Inst.Func.SrcLocs,
54315443 opt_lib_name: ?[]const u8,
54325444) CompileError!Air.Inst.Ref {
5433 const src: LazySrcLoc = .{ .node_offset = src_node_offset };
54345445 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
54355446
54365447 // The return type body might be a type expression that depends on generic parameters.
......@@ -5448,7 +5459,7 @@ fn funcCommon(
54485459 block.params.deinit(sema.gpa);
54495460 block.params = prev_params;
54505461 }
5451 if (sema.resolveBody(block, ret_ty_body)) |ret_ty_inst| {
5462 if (sema.resolveBody(block, ret_ty_body, func_inst)) |ret_ty_inst| {
54525463 if (sema.analyzeAsType(block, ret_ty_src, ret_ty_inst)) |ret_ty| {
54535464 break :ret_ty ret_ty;
54545465 } else |err| break :err err;
......@@ -5467,25 +5478,36 @@ fn funcCommon(
54675478 const mod = sema.mod;
54685479
54695480 const new_func: *Module.Fn = new_func: {
5470 if (body_inst == 0) break :new_func undefined;
5471 if (sema.comptime_args_fn_inst == body_inst) {
5481 if (!has_body) break :new_func undefined;
5482 if (sema.comptime_args_fn_inst == func_inst) {
54725483 const new_func = sema.preallocated_new_func.?;
54735484 sema.preallocated_new_func = null; // take ownership
54745485 break :new_func new_func;
54755486 }
54765487 break :new_func try sema.gpa.create(Module.Fn);
54775488 };
5478 errdefer if (body_inst != 0) sema.gpa.destroy(new_func);
5489 errdefer if (has_body) sema.gpa.destroy(new_func);
54795490
54805491 var maybe_inferred_error_set_node: ?*Module.Fn.InferredErrorSetListNode = null;
54815492 errdefer if (maybe_inferred_error_set_node) |node| sema.gpa.destroy(node);
54825493 // 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
54845497 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
54855507 // Hot path for some common function types.
54865508 // TODO can we eliminate some of these Type tag values? seems unnecessarily complicated.
54875509 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)
54895511 {
54905512 if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {
54915513 break :fn_ty Type.initTag(.fn_noreturn_no_args);
......@@ -5507,16 +5529,15 @@ fn funcCommon(
55075529 const param_types = try sema.arena.alloc(Type, block.params.items.len);
55085530 const comptime_params = try sema.arena.alloc(bool, block.params.items.len);
55095531 for (block.params.items) |param, i| {
5532 const param_src: LazySrcLoc = .{ .node_offset = src_node_offset }; // TODO better src
55105533 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);
55125536 is_generic = is_generic or comptime_params[i] or param.ty.tag() == .generic_poison;
55135537 }
55145538
5515 if (align_val.tag() != .null_value) {
5516 return sema.fail(block, src, "TODO implement support for function prototypes to have alignment specified", .{});
5517 }
5518
5519 is_generic = is_generic or bare_return_type.requiresComptime();
5539 is_generic = is_generic or
5540 try sema.typeRequiresComptime(block, ret_ty_src, bare_return_type);
55205541
55215542 const return_type = if (!inferred_error_set or bare_return_type.tag() == .generic_poison)
55225543 bare_return_type
......@@ -5537,6 +5558,7 @@ fn funcCommon(
55375558 .comptime_params = comptime_params.ptr,
55385559 .return_type = return_type,
55395560 .cc = cc,
5561 .alignment = alignment,
55405562 .is_var_args = var_args,
55415563 .is_generic = is_generic,
55425564 });
......@@ -5550,7 +5572,6 @@ fn funcCommon(
55505572 lib_name, @errorName(err),
55515573 });
55525574 };
5553 const target = mod.getTarget();
55545575 if (target_util.is_libc_lib_name(target, lib_name)) {
55555576 if (!mod.comp.bin_file.options.link_libc) {
55565577 return sema.fail(
......@@ -5590,26 +5611,21 @@ fn funcCommon(
55905611 );
55915612 }
55925613
5593 if (body_inst == 0) {
5594 const fn_ptr_ty = try Type.ptr(sema.arena, .{
5595 .pointee_type = fn_ty,
5596 .@"addrspace" = .generic,
5597 .mutable = false,
5598 });
5599 return sema.addType(fn_ptr_ty);
5614 if (!has_body) {
5615 return sema.addType(fn_ty);
56005616 }
56015617
56025618 const is_inline = fn_ty.fnCallingConvention() == .Inline;
56035619 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: {
56065622 break :blk if (sema.comptime_args.len == 0) null else sema.comptime_args.ptr;
56075623 } else null;
56085624
56095625 const fn_payload = try sema.arena.create(Value.Payload.Function);
56105626 new_func.* = .{
56115627 .state = anal_state,
5612 .zir_body_inst = body_inst,
5628 .zir_body_inst = func_inst,
56135629 .owner_decl = sema.owner_decl,
56145630 .comptime_args = comptime_args,
56155631 .lbrace_line = src_locs.lbrace_line,
......@@ -5632,7 +5648,7 @@ fn zirParam(
56325648 sema: *Sema,
56335649 block: *Block,
56345650 inst: Zir.Inst.Index,
5635 is_comptime: bool,
5651 comptime_syntax: bool,
56365652) CompileError!void {
56375653 const inst_data = sema.code.instructions.items(.data)[inst].pl_tok;
56385654 const src = inst_data.src();
......@@ -5656,7 +5672,7 @@ fn zirParam(
56565672 block.params = prev_params;
56575673 }
56585674
5659 if (sema.resolveBody(block, body)) |param_ty_inst| {
5675 if (sema.resolveBody(block, body, inst)) |param_ty_inst| {
56605676 if (sema.analyzeAsType(block, src, param_ty_inst)) |param_ty| {
56615677 break :param_ty param_ty;
56625678 } else |err| break :err err;
......@@ -5669,7 +5685,7 @@ fn zirParam(
56695685 // insert an anytype parameter.
56705686 try block.params.append(sema.gpa, .{
56715687 .ty = Type.initTag(.generic_poison),
5672 .is_comptime = is_comptime,
5688 .is_comptime = comptime_syntax,
56735689 });
56745690 try sema.inst_map.putNoClobber(sema.gpa, inst, .generic_poison);
56755691 return;
......@@ -5677,8 +5693,10 @@ fn zirParam(
56775693 else => |e| return e,
56785694 }
56795695 };
5696 const is_comptime = comptime_syntax or
5697 try sema.typeRequiresComptime(block, src, param_ty);
56805698 if (sema.inst_map.get(inst)) |arg| {
5681 if (is_comptime or param_ty.requiresComptime()) {
5699 if (is_comptime) {
56825700 // We have a comptime value for this parameter so it should be elided from the
56835701 // function type of the function instruction in this block.
56845702 const coerced_arg = try sema.coerce(block, param_ty, arg, src);
......@@ -5692,7 +5710,7 @@ fn zirParam(
56925710
56935711 try block.params.append(sema.gpa, .{
56945712 .ty = param_ty,
5695 .is_comptime = is_comptime or param_ty.requiresComptime(),
5713 .is_comptime = is_comptime,
56965714 });
56975715 const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison));
56985716 try sema.inst_map.putNoClobber(sema.gpa, inst, result);
......@@ -5702,9 +5720,10 @@ fn zirParamAnytype(
57025720 sema: *Sema,
57035721 block: *Block,
57045722 inst: Zir.Inst.Index,
5705 is_comptime: bool,
5723 comptime_syntax: bool,
57065724) CompileError!void {
57075725 const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
5726 const src = inst_data.src();
57085727 const param_name = inst_data.get(sema.code);
57095728
57105729 // TODO check if param_name shadows a Decl. This only needs to be done if
......@@ -5713,7 +5732,7 @@ fn zirParamAnytype(
57135732
57145733 if (sema.inst_map.get(inst)) |air_ref| {
57155734 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)) {
57175736 // We have a comptime value for this parameter so it should be elided from the
57185737 // function type of the function instruction in this block.
57195738 return;
......@@ -5730,7 +5749,7 @@ fn zirParamAnytype(
57305749
57315750 try block.params.append(sema.gpa, .{
57325751 .ty = Type.initTag(.generic_poison),
5733 .is_comptime = is_comptime,
5752 .is_comptime = comptime_syntax,
57345753 });
57355754 try sema.inst_map.put(sema.gpa, inst, .generic_poison);
57365755}
......@@ -5770,15 +5789,16 @@ fn zirPtrToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
57705789 defer tracy.end();
57715790
57725791 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 };
57735793 const ptr = sema.resolveInst(inst_data.operand);
57745794 const ptr_ty = sema.typeOf(ptr);
57755795 if (!ptr_ty.isPtrAtRuntime()) {
5776 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
57775796 return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty});
57785797 }
5779 // TODO handle known-pointer-address
5780 const src = inst_data.src();
5781 try sema.requireRuntimeBlock(block, src);
5798 if (try sema.resolveMaybeUndefVal(block, ptr_src, ptr)) |ptr_val| {
5799 return sema.addConstant(Type.usize, ptr_val);
5800 }
5801 try sema.requireRuntimeBlock(block, ptr_src);
57825802 return block.addUnOp(.ptrtoint, ptr);
57835803}
57845804
......@@ -6802,7 +6822,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
68026822 // Validation above ensured these will succeed.
68036823 const item_val = sema.resolveConstValue(&child_block, .unneeded, item) catch unreachable;
68046824 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);
68066826 }
68076827 }
68086828 }
......@@ -6824,7 +6844,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
68246844 // Validation above ensured these will succeed.
68256845 const item_val = sema.resolveConstValue(&child_block, .unneeded, item) catch unreachable;
68266846 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);
68286848 }
68296849 }
68306850
......@@ -6841,18 +6861,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
68416861 if (Value.compare(operand_val, .gte, first_tv.val, operand_ty) and
68426862 Value.compare(operand_val, .lte, last_tv.val, operand_ty))
68436863 {
6844 return sema.resolveBlockBody(block, src, &child_block, body, merges);
6864 return sema.resolveBlockBody(block, src, &child_block, body, inst, merges);
68456865 }
68466866 }
68476867
68486868 extra_index += body_len;
68496869 }
68506870 }
6851 return sema.resolveBlockBody(block, src, &child_block, special.body, merges);
6871 return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges);
68526872 }
68536873
68546874 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);
68566876 }
68576877
68586878 try sema.requireRuntimeBlock(block, src);
......@@ -7395,7 +7415,7 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
73957415 },
73967416 };
73977417
7398 var anon_decl = try block.startAnonDecl();
7418 var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded);
73997419 defer anon_decl.deinit();
74007420
74017421 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
76597679 const is_pointer = lhs_ty.zigTypeTag() == .Pointer;
76607680 const lhs_sub_val = if (is_pointer) (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? else lhs_val;
76617681 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);
76637683 defer anon_decl.deinit();
76647684
76657685 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
77437763
77447764 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);
77477767 defer anon_decl.deinit();
77487768
77497769 const final_ty = if (mulinfo.sentinel) |sent|
......@@ -9357,7 +9377,7 @@ fn zirBuiltinSrc(
93579377 const func = sema.func orelse return sema.fail(block, src, "@src outside function", .{});
93589378
93599379 const func_name_val = blk: {
9360 var anon_decl = try block.startAnonDecl();
9380 var anon_decl = try block.startAnonDecl(src);
93619381 defer anon_decl.deinit();
93629382 const name = std.mem.span(func.owner_decl.name);
93639383 const bytes = try anon_decl.arena().dupe(u8, name[0 .. name.len + 1]);
......@@ -9369,7 +9389,7 @@ fn zirBuiltinSrc(
93699389 };
93709390
93719391 const file_name_val = blk: {
9372 var anon_decl = try block.startAnonDecl();
9392 var anon_decl = try block.startAnonDecl(src);
93739393 defer anon_decl.deinit();
93749394 const name = try func.owner_decl.getFileScope().fullPathZ(anon_decl.arena());
93759395 const new_decl = try anon_decl.finish(
......@@ -9619,7 +9639,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
96199639
96209640 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);
96239643 defer fields_anon_decl.deinit();
96249644
96259645 const enum_field_ty = t: {
......@@ -9650,7 +9670,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
96509670
96519671 const name = enum_fields.keys()[i];
96529672 const name_val = v: {
9653 var anon_decl = try block.startAnonDecl();
9673 var anon_decl = try block.startAnonDecl(src);
96549674 defer anon_decl.deinit();
96559675 const bytes = try anon_decl.arena().dupeZ(u8, name);
96569676 const new_decl = try anon_decl.finish(
......@@ -9715,7 +9735,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
97159735 .Union => {
97169736 // TODO: look into memoizing this result.
97179737
9718 var fields_anon_decl = try block.startAnonDecl();
9738 var fields_anon_decl = try block.startAnonDecl(src);
97199739 defer fields_anon_decl.deinit();
97209740
97219741 const union_field_ty = t: {
......@@ -9739,7 +9759,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
97399759 const field = union_fields.values()[i];
97409760 const name = union_fields.keys()[i];
97419761 const name_val = v: {
9742 var anon_decl = try block.startAnonDecl();
9762 var anon_decl = try block.startAnonDecl(src);
97439763 defer anon_decl.deinit();
97449764 const bytes = try anon_decl.arena().dupeZ(u8, name);
97459765 const new_decl = try anon_decl.finish(
......@@ -9810,7 +9830,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
98109830 .Opaque => {
98119831 // TODO: look into memoizing this result.
98129832
9813 var fields_anon_decl = try block.startAnonDecl();
9833 var fields_anon_decl = try block.startAnonDecl(src);
98149834 defer fields_anon_decl.deinit();
98159835
98169836 const opaque_ty = try sema.resolveTypeFields(block, src, ty);
......@@ -9848,7 +9868,7 @@ fn typeInfoDecls(
98489868 const decls_len = namespace.decls.count();
98499869 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);
98529872 defer decls_anon_decl.deinit();
98539873
98549874 const declaration_ty = t: {
......@@ -9869,7 +9889,7 @@ fn typeInfoDecls(
98699889 const decl = namespace.decls.values()[i];
98709890 const name = namespace.decls.keys()[i];
98719891 const name_val = v: {
9872 var anon_decl = try block.startAnonDecl();
9892 var anon_decl = try block.startAnonDecl(src);
98739893 defer anon_decl.deinit();
98749894 const bytes = try anon_decl.arena().dupeZ(u8, name);
98759895 const new_decl = try anon_decl.finish(
......@@ -10031,7 +10051,7 @@ fn zirBoolBr(
1003110051 // comptime-known left-hand side. No need for a block here; the result
1003210052 // is simply the rhs expression. Here we rely on there only being 1
1003310053 // break instruction (`break_inline`).
10034 return sema.resolveBody(parent_block, body);
10054 return sema.resolveBody(parent_block, body, inst);
1003510055 }
1003610056
1003710057 const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
......@@ -10061,7 +10081,7 @@ fn zirBoolBr(
1006110081 const lhs_result: Air.Inst.Ref = if (is_bool_or) .bool_true else .bool_false;
1006210082 _ = 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);
1006510085 _ = try rhs_block.addBr(block_inst, rhs_result);
1006610086
1006710087 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +
......@@ -10654,7 +10674,7 @@ fn zirArrayInit(
1065410674 } else null;
1065510675
1065610676 const runtime_src = opt_runtime_src orelse {
10657 var anon_decl = try block.startAnonDecl();
10677 var anon_decl = try block.startAnonDecl(src);
1065810678 defer anon_decl.deinit();
1065910679
1066010680 const elem_vals = try anon_decl.arena().alloc(Value, resolved_args.len);
......@@ -10740,7 +10760,7 @@ fn zirArrayInitAnon(
1074010760 const tuple_val = try Value.Tag.@"struct".create(sema.arena, values);
1074110761 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);
1074410764 defer anon_decl.deinit();
1074510765 const decl = try anon_decl.finish(
1074610766 try tuple_ty.copy(anon_decl.arena()),
......@@ -11032,7 +11052,7 @@ fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1103211052 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
1103311053 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);
1103611056 defer anon_decl.deinit();
1103711057
1103811058 const bytes = try ty.nameAlloc(anon_decl.arena());
......@@ -11118,8 +11138,7 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1111811138
1111911139 const type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
1112011140 const type_res = try sema.resolveType(block, src, extra.lhs);
11121 if (type_res.zigTypeTag() != .Pointer)
11122 return sema.fail(block, type_src, "expected pointer, found '{}'", .{type_res});
11141 try sema.checkPtrType(block, type_src, type_res);
1112311142 const ptr_align = type_res.ptrAlignment(sema.mod.getTarget());
1112411143
1112511144 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
1117611195 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
1117711196 const operand = sema.resolveInst(extra.rhs);
1117811197 const operand_ty = sema.typeOf(operand);
11179 if (operand_ty.zigTypeTag() != .Pointer) {
11180 return sema.fail(block, operand_src, "expected pointer, found {s} type '{}'", .{
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 }
11198 try sema.checkPtrType(block, dest_ty_src, dest_ty);
11199 try sema.checkPtrOperand(block, operand_src, operand_ty);
1118911200 return sema.coerceCompatiblePtrs(block, dest_ty, operand, operand_src);
1119011201}
1119111202
......@@ -11264,7 +11275,7 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1126411275
1126511276 // TODO in addition to pointers, this instruction is supposed to work for
1126611277 // pointer-like optionals and slices.
11267 try sema.checkPtrType(block, ptr_src, ptr_ty);
11278 try sema.checkPtrOperand(block, ptr_src, ptr_ty);
1126811279
1126911280 // TODO compile error if the result pointer is comptime known and would have an
1127011281 // alignment that disagrees with the Decl's alignment.
......@@ -11462,6 +11473,34 @@ fn checkIntType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileEr
1146211473 }
1146311474}
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
1146511504fn checkPtrType(
1146611505 sema: *Sema,
1146711506 block: *Block,
......@@ -11470,6 +11509,22 @@ fn checkPtrType(
1147011509) CompileError!void {
1147111510 switch (ty.zigTypeTag()) {
1147211511 .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 },
1147311528 else => return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty}),
1147411529 }
1147511530}
......@@ -12139,20 +12194,14 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
1213912194 const dest_ptr = sema.resolveInst(extra.dest);
1214012195 const dest_ptr_ty = sema.typeOf(dest_ptr);
1214112196
12142 if (dest_ptr_ty.zigTypeTag() != .Pointer) {
12143 return sema.fail(block, dest_src, "expected pointer, found '{}'", .{dest_ptr_ty});
12144 }
12197 try sema.checkPtrOperand(block, dest_src, dest_ptr_ty);
1214512198 if (dest_ptr_ty.isConstPtr()) {
1214612199 return sema.fail(block, dest_src, "cannot store through const pointer '{}'", .{dest_ptr_ty});
1214712200 }
1214812201
1214912202 const uncasted_src_ptr = sema.resolveInst(extra.source);
1215012203 const uncasted_src_ptr_ty = sema.typeOf(uncasted_src_ptr);
12151 if (uncasted_src_ptr_ty.zigTypeTag() != .Pointer) {
12152 return sema.fail(block, src_src, "expected pointer, found '{}'", .{
12153 uncasted_src_ptr_ty,
12154 });
12155 }
12204 try sema.checkPtrOperand(block, src_src, uncasted_src_ptr_ty);
1215612205 const src_ptr_info = uncasted_src_ptr_ty.ptrInfo().data;
1215712206 const wanted_src_ptr_ty = try Type.ptr(sema.arena, .{
1215812207 .pointee_type = dest_ptr_ty.elemType2(),
......@@ -12203,9 +12252,7 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
1220312252 const len_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
1220412253 const dest_ptr = sema.resolveInst(extra.dest);
1220512254 const dest_ptr_ty = sema.typeOf(dest_ptr);
12206 if (dest_ptr_ty.zigTypeTag() != .Pointer) {
12207 return sema.fail(block, dest_src, "expected pointer, found '{}'", .{dest_ptr_ty});
12208 }
12255 try sema.checkPtrOperand(block, dest_src, dest_ptr_ty);
1220912256 if (dest_ptr_ty.isConstPtr()) {
1221012257 return sema.fail(block, dest_src, "cannot store through const pointer '{}'", .{dest_ptr_ty});
1221112258 }
......@@ -12385,10 +12432,9 @@ fn zirFuncExtended(
1238512432 const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len];
1238612433 extra_index += ret_ty_body.len;
1238712434
12388 var body_inst: Zir.Inst.Index = 0;
1238912435 var src_locs: Zir.Inst.Func.SrcLocs = undefined;
12390 if (extra.data.body_len != 0) {
12391 body_inst = inst;
12436 const has_body = extra.data.body_len != 0;
12437 if (has_body) {
1239212438 extra_index += extra.data.body_len;
1239312439 src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
1239412440 }
......@@ -12400,13 +12446,14 @@ fn zirFuncExtended(
1240012446 return sema.funcCommon(
1240112447 block,
1240212448 extra.data.src_node,
12403 body_inst,
12449 inst,
1240412450 ret_ty_body,
1240512451 cc,
1240612452 align_val,
1240712453 is_var_args,
1240812454 is_inferred_error,
1240912455 is_extern,
12456 has_body,
1241012457 src_locs,
1241112458 lib_name,
1241212459 );
......@@ -12487,7 +12534,7 @@ fn zirPrefetch(
1248712534 const opts_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
1248812535 const options_ty = try sema.getBuiltinType(block, opts_src, "PrefetchOptions");
1248912536 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));
1249112538 const options = try sema.coerce(block, options_ty, sema.resolveInst(extra.rhs), opts_src);
1249212539
1249312540 const rw = try sema.fieldVal(block, opts_src, options, "rw", opts_src);
......@@ -12568,12 +12615,15 @@ fn validateVarType(
1256812615 .Type,
1256912616 .Undefined,
1257012617 .Null,
12618 .Fn,
1257112619 => break,
1257212620
1257312621 .Pointer => {
1257412622 const elem_ty = ty.childType();
12575 if (elem_ty.zigTypeTag() == .Opaque) return;
12576 ty = elem_ty;
12623 switch (elem_ty.zigTypeTag()) {
12624 .Opaque, .Fn => return,
12625 else => ty = elem_ty,
12626 }
1257712627 },
1257812628 .Opaque => if (is_extern) return else break,
1257912629
......@@ -12586,9 +12636,9 @@ fn validateVarType(
1258612636
1258712637 .ErrorUnion => ty = ty.errorUnionPayload(),
1258812638
12589 .Fn, .Struct, .Union => {
12639 .Struct, .Union => {
1259012640 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
12591 if (resolved_ty.requiresComptime()) {
12641 if (try sema.typeRequiresComptime(block, src, resolved_ty)) {
1259212642 break;
1259312643 } else {
1259412644 return;
......@@ -12596,7 +12646,99 @@ fn validateVarType(
1259612646 },
1259712647 } 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 }
1260012742}
1260112743
1260212744pub const PanicId = enum {
......@@ -12731,7 +12873,7 @@ fn safetyPanic(
1273112873 const msg_inst = msg_inst: {
1273212874 // TODO instead of making a new decl for every panic in the entire compilation,
1273312875 // 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);
1273512877 defer anon_decl.deinit();
1273612878 break :msg_inst try sema.analyzeDeclRef(try anon_decl.finish(
1273712879 try Type.Tag.array_u8.create(anon_decl.arena(), msg.len),
......@@ -12941,7 +13083,7 @@ fn fieldPtr(
1294113083 switch (inner_ty.zigTypeTag()) {
1294213084 .Array => {
1294313085 if (mem.eql(u8, field_name, "len")) {
12944 var anon_decl = try block.startAnonDecl();
13086 var anon_decl = try block.startAnonDecl(src);
1294513087 defer anon_decl.deinit();
1294613088 return sema.analyzeDeclRef(try anon_decl.finish(
1294713089 Type.initTag(.comptime_int),
......@@ -12967,7 +13109,7 @@ fn fieldPtr(
1296713109 const slice_ptr_ty = inner_ty.slicePtrFieldType(buf);
1296813110
1296913111 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);
1297113113 defer anon_decl.deinit();
1297213114
1297313115 return sema.analyzeDeclRef(try anon_decl.finish(
......@@ -12986,7 +13128,7 @@ fn fieldPtr(
1298613128 return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr);
1298713129 } else if (mem.eql(u8, field_name, "len")) {
1298813130 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);
1299013132 defer anon_decl.deinit();
1299113133
1299213134 return sema.analyzeDeclRef(try anon_decl.finish(
......@@ -13036,7 +13178,7 @@ fn fieldPtr(
1303613178 });
1303713179 } else (try sema.mod.getErrorValue(field_name)).key;
1303813180
13039 var anon_decl = try block.startAnonDecl();
13181 var anon_decl = try block.startAnonDecl(src);
1304013182 defer anon_decl.deinit();
1304113183 return sema.analyzeDeclRef(try anon_decl.finish(
1304213184 try child_type.copy(anon_decl.arena()),
......@@ -13052,7 +13194,7 @@ fn fieldPtr(
1305213194 if (child_type.unionTagType()) |enum_ty| {
1305313195 if (enum_ty.enumFieldIndex(field_name)) |field_index| {
1305413196 const field_index_u32 = @intCast(u32, field_index);
13055 var anon_decl = try block.startAnonDecl();
13197 var anon_decl = try block.startAnonDecl(src);
1305613198 defer anon_decl.deinit();
1305713199 return sema.analyzeDeclRef(try anon_decl.finish(
1305813200 try enum_ty.copy(anon_decl.arena()),
......@@ -13072,7 +13214,7 @@ fn fieldPtr(
1307213214 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
1307313215 };
1307413216 const field_index_u32 = @intCast(u32, field_index);
13075 var anon_decl = try block.startAnonDecl();
13217 var anon_decl = try block.startAnonDecl(src);
1307613218 defer anon_decl.deinit();
1307713219 return sema.analyzeDeclRef(try anon_decl.finish(
1307813220 try child_type.copy(anon_decl.arena()),
......@@ -13328,7 +13470,7 @@ fn structFieldPtr(
1332813470 var offset: u64 = 0;
1332913471 var running_bits: u16 = 0;
1333013472 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
1333313475 const field_align = f.packedAlignment();
1333413476 if (field_align == 0) {
......@@ -13883,6 +14025,9 @@ fn coerce(
1388314025 {
1388414026 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
1388514027 }
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);
1388614031 },
1388714032 .Int, .ComptimeInt => switch (inst_ty.zigTypeTag()) {
1388814033 .Float, .ComptimeFloat => float: {
......@@ -14683,7 +14828,8 @@ const ComptimePtrLoadKit = struct {
1468314828 /// The Type of the parent Value.
1468414829 ty: Type,
1468514830 /// 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,
1468714833 /// Whether the `root_val` could be mutated by further
1468814834 /// semantic analysis and a copy must be performed.
1468914835 is_mutable: bool,
......@@ -14738,12 +14884,24 @@ fn beginComptimePtrLoad(
1473814884 });
1473914885 }
1474014886 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 };
1474214900 return ComptimePtrLoadKit{
1474314901 .root_val = parent.root_val,
1474414902 .val = try parent.val.elemValue(sema.arena, elem_ptr.index),
1474514903 .ty = elem_ty,
14746 .byte_offset = try sema.usizeCast(block, src, parent.byte_offset + elem_size * elem_ptr.index),
14904 .byte_offset = byte_offset,
1474714905 .is_mutable = parent.is_mutable,
1474814906 };
1474914907 },
......@@ -14768,13 +14926,24 @@ fn beginComptimePtrLoad(
1476814926 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
1476914927 const parent = try beginComptimePtrLoad(sema, block, src, field_ptr.container_ptr);
1477014928 const field_index = @intCast(u32, field_ptr.field_index);
14771 try sema.resolveTypeLayout(block, src, parent.ty);
14772 const field_offset = parent.ty.structFieldOffset(field_index, target);
14929 const byte_offset: ?usize = bo: {
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 };
1477314942 return ComptimePtrLoadKit{
1477414943 .root_val = parent.root_val,
1477514944 .val = try parent.val.fieldValue(sema.arena, field_index),
1477614945 .ty = parent.ty.structFieldType(field_index),
14777 .byte_offset = try sema.usizeCast(block, src, parent.byte_offset + field_offset),
14946 .byte_offset = byte_offset,
1477814947 .is_mutable = parent.is_mutable,
1477914948 };
1478014949 },
......@@ -14785,7 +14954,7 @@ fn beginComptimePtrLoad(
1478514954 .root_val = parent.root_val,
1478614955 .val = parent.val.castTag(.eu_payload).?.data,
1478714956 .ty = parent.ty.errorUnionPayload(),
14788 .byte_offset = undefined,
14957 .byte_offset = null,
1478914958 .is_mutable = parent.is_mutable,
1479014959 };
1479114960 },
......@@ -14796,7 +14965,7 @@ fn beginComptimePtrLoad(
1479614965 .root_val = parent.root_val,
1479714966 .val = parent.val.castTag(.opt_payload).?.data,
1479814967 .ty = try parent.ty.optionalChildAlloc(sema.arena),
14799 .byte_offset = undefined,
14968 .byte_offset = null,
1480014969 .is_mutable = parent.is_mutable,
1480114970 };
1480214971 },
......@@ -15176,7 +15345,7 @@ fn analyzeRef(
1517615345 const operand_ty = sema.typeOf(operand);
1517715346
1517815347 if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| {
15179 var anon_decl = try block.startAnonDecl();
15348 var anon_decl = try block.startAnonDecl(src);
1518015349 defer anon_decl.deinit();
1518115350 return sema.analyzeDeclRef(try anon_decl.finish(
1518215351 try operand_ty.copy(anon_decl.arena()),
......@@ -15590,7 +15759,7 @@ fn cmpNumeric(
1559015759 lhs_bits = bigint.toConst().bitCountTwosComp();
1559115760 break :x (zcmp != .lt);
1559215761 } else x: {
15593 lhs_bits = lhs_val.intBitCountTwosComp();
15762 lhs_bits = lhs_val.intBitCountTwosComp(target);
1559415763 break :x (lhs_val.orderAgainstZero() != .lt);
1559515764 };
1559615765 lhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);
......@@ -15625,7 +15794,7 @@ fn cmpNumeric(
1562515794 rhs_bits = bigint.toConst().bitCountTwosComp();
1562615795 break :x (zcmp != .lt);
1562715796 } else x: {
15628 rhs_bits = rhs_val.intBitCountTwosComp();
15797 rhs_bits = rhs_val.intBitCountTwosComp(target);
1562915798 break :x (rhs_val.orderAgainstZero() != .lt);
1563015799 };
1563115800 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
1609016259 switch (ty.tag()) {
1609116260 .@"struct" => {
1609216261 const struct_obj = ty.castTag(.@"struct").?.data;
16093 switch (struct_obj.status) {
16094 .none => {},
16095 .field_types_wip => {
16096 return sema.fail(block, src, "struct {} depends on itself", .{ty});
16097 },
16098 .have_field_types,
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
16262 try sema.resolveTypeFieldsStruct(block, src, ty, struct_obj);
16263 return ty;
16264 },
16265 .@"union", .union_tagged => {
16266 const union_obj = ty.cast(Type.Payload.Union).?.data;
16267 try sema.resolveTypeFieldsUnion(block, src, ty, union_obj);
1611516268 return ty;
1611616269 },
1611716270 .type_info => return sema.resolveBuiltinTypeFields(block, src, "TypeInfo"),
......@@ -16126,29 +16279,63 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp
1612616279 .call_options => return sema.resolveBuiltinTypeFields(block, src, "CallOptions"),
1612716280 .prefetch_options => return sema.resolveBuiltinTypeFields(block, src, "PrefetchOptions"),
1612816281
16129 .@"union", .union_tagged => {
16130 const union_obj = ty.cast(Type.Payload.Union).?.data;
16131 switch (union_obj.status) {
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 }
16282 else => return ty,
16283 }
16284}
1614316285
16144 union_obj.status = .field_types_wip;
16145 try semaUnionFields(sema.mod, union_obj);
16146 union_obj.status = .have_field_types;
16286fn resolveTypeFieldsStruct(
16287 sema: *Sema,
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});
1614916327 },
16150 else => return ty,
16328 .have_field_types,
16329 .have_layout,
16330 .layout_wip,
16331 .fully_resolved_wip,
16332 .fully_resolved,
16333 => return,
1615116334 }
16335
16336 union_obj.status = .field_types_wip;
16337 try semaUnionFields(sema.mod, union_obj);
16338 union_obj.status = .have_field_types;
1615216339}
1615316340
1615416341fn resolveBuiltinTypeFields(
......@@ -16695,6 +16882,7 @@ fn getBuiltinType(
1669516882/// in `Sema` is for calling during semantic analysis, and performs field resolution
1669616883/// to get the answer. The one in `Type` is for calling during codegen and asserts
1669716884/// that the types are already resolved.
16885/// TODO assert the return value matches `ty.onePossibleValue`
1669816886pub fn typeHasOnePossibleValue(
1669916887 sema: *Sema,
1670016888 block: *Block,
......@@ -16842,7 +17030,7 @@ pub fn typeHasOnePossibleValue(
1684217030 },
1684317031 .enum_nonexhaustive => {
1684417032 const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty;
16845 if (!tag_ty.hasCodeGenBits()) {
17033 if (!(try sema.typeHasRuntimeBits(block, src, tag_ty))) {
1684617034 return Value.zero;
1684717035 } else {
1684817036 return null;
......@@ -17106,7 +17294,7 @@ fn analyzeComptimeAlloc(
1710617294 .@"align" = alignment,
1710717295 });
1710817296
17109 var anon_decl = try block.startAnonDecl();
17297 var anon_decl = try block.startAnonDecl(src);
1711017298 defer anon_decl.deinit();
1711117299
1711217300 const align_val = if (alignment == 0)
......@@ -17295,3 +17483,220 @@ fn typePtrOrOptionalPtrTy(
1729517483 else => return null,
1729617484 }
1729717485}
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 {
25992599 has_body_len: bool,
26002600 has_fields_len: bool,
26012601 has_decls_len: bool,
2602 known_has_bits: bool,
2602 known_non_opv: bool,
2603 known_comptime_only: bool,
26032604 name_strategy: NameStrategy,
26042605 layout: std.builtin.TypeInfo.ContainerLayout,
2605 _: u7 = undefined,
2606 _: u6 = undefined,
26062607 };
26072608 };
26082609
......@@ -3273,6 +3274,7 @@ fn findDeclsBody(
32733274
32743275pub const FnInfo = struct {
32753276 param_body: []const Inst.Index,
3277 param_body_inst: Inst.Index,
32763278 ret_ty_body: []const Inst.Index,
32773279 body: []const Inst.Index,
32783280 total_params_len: u32,
......@@ -3338,6 +3340,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
33383340 }
33393341 return .{
33403342 .param_body = param_body,
3343 .param_body_inst = info.param_block,
33413344 .ret_ty_body = info.ret_ty_body,
33423345 .body = info.body,
33433346 .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 {
713713fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
714714 switch (self.debug_output) {
715715 .dwarf => |dbg_out| {
716 assert(ty.hasCodeGenBits());
716 assert(ty.hasRuntimeBits());
717717 const index = dbg_out.dbg_info.items.len;
718718 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 {
12791279 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
12801280 const elem_ty = self.air.typeOfIndex(inst);
12811281 const result: MCValue = result: {
1282 if (!elem_ty.hasCodeGenBits())
1282 if (!elem_ty.hasRuntimeBits())
12831283 break :result MCValue.none;
12841284
12851285 const ptr = try self.resolveInst(ty_op.operand);
......@@ -2155,7 +2155,7 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {
21552155fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
21562156 const block_data = self.blocks.getPtr(block).?;
21572157
2158 if (self.air.typeOf(operand).hasCodeGenBits()) {
2158 if (self.air.typeOf(operand).hasRuntimeBits()) {
21592159 const operand_mcv = try self.resolveInst(operand);
21602160 const block_mcv = block_data.mcv;
21612161 if (block_mcv == .none) {
......@@ -2608,7 +2608,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
26082608 const ref_int = @enumToInt(inst);
26092609 if (ref_int < Air.Inst.Ref.typed_value_map.len) {
26102610 const tv = Air.Inst.Ref.typed_value_map[ref_int];
2611 if (!tv.ty.hasCodeGenBits()) {
2611 if (!tv.ty.hasRuntimeBits()) {
26122612 return MCValue{ .none = {} };
26132613 }
26142614 return self.genTypedValue(tv);
......@@ -2616,7 +2616,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
26162616
26172617 // If the type has no codegen bits, no need to store it.
26182618 const inst_ty = self.air.typeOf(inst);
2619 if (!inst_ty.hasCodeGenBits())
2619 if (!inst_ty.hasRuntimeBits())
26202620 return MCValue{ .none = {} };
26212621
26222622 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
26722672 return mcv;
26732673}
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
26752700fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
26762701 if (typed_value.val.isUndef())
26772702 return MCValue{ .undef = {} };
26782703 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
26802712 switch (typed_value.ty.zigTypeTag()) {
26812713 .Pointer => switch (typed_value.ty.ptrSize()) {
26822714 .Slice => {
......@@ -2693,28 +2725,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
26932725 return self.fail("TODO codegen for const slices", .{});
26942726 },
26952727 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 }
27182728 if (typed_value.val.tag() == .int_u64) {
27192729 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
27202730 }
......@@ -2794,7 +2804,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
27942804 const payload_type = typed_value.ty.errorUnionPayload();
27952805 const sub_val = typed_value.val.castTag(.eu_payload).?.data;
27962806
2797 if (!payload_type.hasCodeGenBits()) {
2807 if (!payload_type.hasRuntimeBits()) {
27982808 // We use the error type directly as the type.
27992809 return self.genTypedValue(.{ .ty = error_type, .val = sub_val });
28002810 }
......@@ -2888,7 +2898,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
28882898
28892899 if (ret_ty.zigTypeTag() == .NoReturn) {
28902900 result.return_value = .{ .unreach = {} };
2891 } else if (!ret_ty.hasCodeGenBits()) {
2901 } else if (!ret_ty.hasRuntimeBits()) {
28922902 result.return_value = .{ .none = {} };
28932903 } else switch (cc) {
28942904 .Naked => unreachable,
src/arch/arm/CodeGen.zig+47-35
......@@ -1074,7 +1074,7 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
10741074 const error_union_ty = self.air.typeOf(ty_op.operand);
10751075 const payload_ty = error_union_ty.errorUnionPayload();
10761076 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
10791079 return self.fail("TODO implement unwrap error union error for non-empty payloads", .{});
10801080 };
......@@ -1086,7 +1086,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
10861086 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
10871087 const error_union_ty = self.air.typeOf(ty_op.operand);
10881088 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
10911091 return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{});
10921092 };
......@@ -1135,7 +1135,7 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
11351135 const error_union_ty = self.air.getRefType(ty_op.ty);
11361136 const payload_ty = error_union_ty.errorUnionPayload();
11371137 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
11401140 return self.fail("TODO implement wrap errunion error for non-empty payloads", .{});
11411141 };
......@@ -1506,7 +1506,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
15061506 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
15071507 const elem_ty = self.air.typeOfIndex(inst);
15081508 const result: MCValue = result: {
1509 if (!elem_ty.hasCodeGenBits())
1509 if (!elem_ty.hasRuntimeBits())
15101510 break :result MCValue.none;
15111511
15121512 const ptr = try self.resolveInst(ty_op.operand);
......@@ -2666,9 +2666,9 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
26662666 const error_type = ty.errorUnionSet();
26672667 const payload_type = ty.errorUnionPayload();
26682668
2669 if (!error_type.hasCodeGenBits()) {
2669 if (!error_type.hasRuntimeBits()) {
26702670 return MCValue{ .immediate = 0 }; // always false
2671 } else if (!payload_type.hasCodeGenBits()) {
2671 } else if (!payload_type.hasRuntimeBits()) {
26722672 if (error_type.abiSize(self.target.*) <= 4) {
26732673 const reg_mcv: MCValue = switch (operand) {
26742674 .register => operand,
......@@ -2900,7 +2900,7 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {
29002900fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
29012901 const block_data = self.blocks.getPtr(block).?;
29022902
2903 if (self.air.typeOf(operand).hasCodeGenBits()) {
2903 if (self.air.typeOf(operand).hasRuntimeBits()) {
29042904 const operand_mcv = try self.resolveInst(operand);
29052905 const block_mcv = block_data.mcv;
29062906 if (block_mcv == .none) {
......@@ -3658,7 +3658,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
36583658 const ref_int = @enumToInt(inst);
36593659 if (ref_int < Air.Inst.Ref.typed_value_map.len) {
36603660 const tv = Air.Inst.Ref.typed_value_map[ref_int];
3661 if (!tv.ty.hasCodeGenBits()) {
3661 if (!tv.ty.hasRuntimeBits()) {
36623662 return MCValue{ .none = {} };
36633663 }
36643664 return self.genTypedValue(tv);
......@@ -3666,7 +3666,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
36663666
36673667 // If the type has no codegen bits, no need to store it.
36683668 const inst_ty = self.air.typeOf(inst);
3669 if (!inst_ty.hasCodeGenBits())
3669 if (!inst_ty.hasRuntimeBits())
36703670 return MCValue{ .none = {} };
36713671
36723672 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 {
37013701 }
37023702}
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
37043731fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
37053732 if (typed_value.val.isUndef())
37063733 return MCValue{ .undef = {} };
37073734 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
37093743 switch (typed_value.ty.zigTypeTag()) {
37103744 .Pointer => switch (typed_value.ty.ptrSize()) {
37113745 .Slice => {
......@@ -3722,28 +3756,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
37223756 return self.fail("TODO codegen for const slices", .{});
37233757 },
37243758 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 }
37473759 if (typed_value.val.tag() == .int_u64) {
37483760 return MCValue{ .immediate = @intCast(u32, typed_value.val.toUnsignedInt()) };
37493761 }
......@@ -3812,7 +3824,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
38123824 const payload_type = typed_value.ty.errorUnionPayload();
38133825
38143826 if (typed_value.val.castTag(.eu_payload)) |pl| {
3815 if (!payload_type.hasCodeGenBits()) {
3827 if (!payload_type.hasRuntimeBits()) {
38163828 // We use the error type directly as the type.
38173829 return MCValue{ .immediate = 0 };
38183830 }
......@@ -3820,7 +3832,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
38203832 _ = pl;
38213833 return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty});
38223834 } else {
3823 if (!payload_type.hasCodeGenBits()) {
3835 if (!payload_type.hasRuntimeBits()) {
38243836 // We use the error type directly as the type.
38253837 return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val });
38263838 }
......@@ -3918,7 +3930,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
39183930
39193931 if (ret_ty.zigTypeTag() == .NoReturn) {
39203932 result.return_value = .{ .unreach = {} };
3921 } else if (!ret_ty.hasCodeGenBits()) {
3933 } else if (!ret_ty.hasRuntimeBits()) {
39223934 result.return_value = .{ .none = {} };
39233935 } else switch (cc) {
39243936 .Naked => unreachable,
src/arch/arm/Emit.zig+1-1
......@@ -372,7 +372,7 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
372372fn addDbgInfoTypeReloc(self: *Emit, ty: Type) !void {
373373 switch (self.debug_output) {
374374 .dwarf => |dbg_out| {
375 assert(ty.hasCodeGenBits());
375 assert(ty.hasRuntimeBits());
376376 const index = dbg_out.dbg_info.items.len;
377377 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 {
691691fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
692692 switch (self.debug_output) {
693693 .dwarf => |dbg_out| {
694 assert(ty.hasCodeGenBits());
694 assert(ty.hasRuntimeBits());
695695 const index = dbg_out.dbg_info.items.len;
696696 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 {
12231223 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
12241224 const elem_ty = self.air.typeOfIndex(inst);
12251225 const result: MCValue = result: {
1226 if (!elem_ty.hasCodeGenBits())
1226 if (!elem_ty.hasRuntimeBits())
12271227 break :result MCValue.none;
12281228
12291229 const ptr = try self.resolveInst(ty_op.operand);
......@@ -1769,7 +1769,7 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {
17691769fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
17701770 const block_data = self.blocks.getPtr(block).?;
17711771
1772 if (self.air.typeOf(operand).hasCodeGenBits()) {
1772 if (self.air.typeOf(operand).hasRuntimeBits()) {
17731773 const operand_mcv = try self.resolveInst(operand);
17741774 const block_mcv = block_data.mcv;
17751775 if (block_mcv == .none) {
......@@ -2107,7 +2107,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
21072107 const ref_int = @enumToInt(inst);
21082108 if (ref_int < Air.Inst.Ref.typed_value_map.len) {
21092109 const tv = Air.Inst.Ref.typed_value_map[ref_int];
2110 if (!tv.ty.hasCodeGenBits()) {
2110 if (!tv.ty.hasRuntimeBits()) {
21112111 return MCValue{ .none = {} };
21122112 }
21132113 return self.genTypedValue(tv);
......@@ -2115,7 +2115,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
21152115
21162116 // If the type has no codegen bits, no need to store it.
21172117 const inst_ty = self.air.typeOf(inst);
2118 if (!inst_ty.hasCodeGenBits())
2118 if (!inst_ty.hasRuntimeBits())
21192119 return MCValue{ .none = {} };
21202120
21212121 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
21712171 return mcv;
21722172}
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
21742199fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
21752200 if (typed_value.val.isUndef())
21762201 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 }
21772209 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
2178 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
21792210 switch (typed_value.ty.zigTypeTag()) {
21802211 .Pointer => switch (typed_value.ty.ptrSize()) {
21812212 .Slice => {
......@@ -2192,28 +2223,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
21922223 return self.fail("TODO codegen for const slices", .{});
21932224 },
21942225 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 }
22172226 if (typed_value.val.tag() == .int_u64) {
22182227 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
22192228 }
......@@ -2290,7 +2299,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
22902299 const payload_type = typed_value.ty.errorUnionPayload();
22912300 const sub_val = typed_value.val.castTag(.eu_payload).?.data;
22922301
2293 if (!payload_type.hasCodeGenBits()) {
2302 if (!payload_type.hasRuntimeBits()) {
22942303 // We use the error type directly as the type.
22952304 return self.genTypedValue(.{ .ty = error_type, .val = sub_val });
22962305 }
......@@ -2381,7 +2390,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
23812390
23822391 if (ret_ty.zigTypeTag() == .NoReturn) {
23832392 result.return_value = .{ .unreach = {} };
2384 } else if (!ret_ty.hasCodeGenBits()) {
2393 } else if (!ret_ty.hasRuntimeBits()) {
23852394 result.return_value = .{ .none = {} };
23862395 } else switch (cc) {
23872396 .Naked => unreachable,
src/arch/wasm/CodeGen.zig+35-35
......@@ -598,7 +598,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!WValue {
598598 // means we must generate it from a constant.
599599 const val = self.air.value(ref).?;
600600 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
603603 // When we need to pass the value by reference (such as a struct), we will
604604 // 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 {
790790 defer gpa.free(fn_params);
791791 fn_ty.fnParamTypes(fn_params);
792792 for (fn_params) |param_type| {
793 if (!param_type.hasCodeGenBits()) continue;
793 if (!param_type.hasRuntimeBits()) continue;
794794 try params.append(typeToValtype(param_type, target));
795795 }
796796 }
797797
798798 // return type
799 if (!want_sret and return_type.hasCodeGenBits()) {
799 if (!want_sret and return_type.hasRuntimeBits()) {
800800 try returns.append(typeToValtype(return_type, target));
801801 }
802802
......@@ -935,7 +935,7 @@ pub const DeclGen = struct {
935935 const abi_size = @intCast(usize, ty.abiSize(self.target()));
936936 const offset = abi_size - @intCast(usize, payload_type.abiSize(self.target()));
937937
938 if (!payload_type.hasCodeGenBits()) {
938 if (!payload_type.hasRuntimeBits()) {
939939 try writer.writeByteNTimes(@boolToInt(is_pl), abi_size);
940940 return Result{ .appended = {} };
941941 }
......@@ -1044,7 +1044,7 @@ pub const DeclGen = struct {
10441044 const field_vals = val.castTag(.@"struct").?.data;
10451045 for (field_vals) |field_val, index| {
10461046 const field_ty = ty.structFieldType(index);
1047 if (!field_ty.hasCodeGenBits()) continue;
1047 if (!field_ty.hasRuntimeBits()) continue;
10481048 switch (try self.genTypedValue(field_ty, field_val, writer)) {
10491049 .appended => {},
10501050 .externally_managed => |payload| try writer.writeAll(payload),
......@@ -1093,7 +1093,7 @@ pub const DeclGen = struct {
10931093 .appended => {},
10941094 }
10951095
1096 if (payload_ty.hasCodeGenBits()) {
1096 if (payload_ty.hasRuntimeBits()) {
10971097 const pl_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef);
10981098 switch (try self.genTypedValue(payload_ty, pl_val, writer)) {
10991099 .externally_managed => |data| try writer.writeAll(data),
......@@ -1180,7 +1180,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu
11801180 .Naked => return result,
11811181 .Unspecified, .C => {
11821182 for (param_types) |ty, ty_index| {
1183 if (!ty.hasCodeGenBits()) {
1183 if (!ty.hasRuntimeBits()) {
11841184 result.args[ty_index] = .{ .none = {} };
11851185 continue;
11861186 }
......@@ -1243,7 +1243,7 @@ fn moveStack(self: *Self, offset: u32, local: u32) !void {
12431243///
12441244/// Asserts Type has codegenbits
12451245fn allocStack(self: *Self, ty: Type) !WValue {
1246 assert(ty.hasCodeGenBits());
1246 assert(ty.hasRuntimeBits());
12471247
12481248 // calculate needed stack space
12491249 const abi_size = std.math.cast(u32, ty.abiSize(self.target)) catch {
......@@ -1319,22 +1319,22 @@ fn isByRef(ty: Type, target: std.Target) bool {
13191319 .Struct,
13201320 .Frame,
13211321 .Union,
1322 => return ty.hasCodeGenBits(),
1322 => return ty.hasRuntimeBits(),
13231323 .Int => return if (ty.intInfo(target).bits > 64) true else false,
13241324 .ErrorUnion => {
1325 const has_tag = ty.errorUnionSet().hasCodeGenBits();
1326 const has_pl = ty.errorUnionPayload().hasCodeGenBits();
1325 const has_tag = ty.errorUnionSet().hasRuntimeBits();
1326 const has_pl = ty.errorUnionPayload().hasRuntimeBits();
13271327 if (!has_tag or !has_pl) return false;
1328 return ty.hasCodeGenBits();
1328 return ty.hasRuntimeBits();
13291329 },
13301330 .Optional => {
13311331 if (ty.isPtrLikeOptional()) return false;
13321332 var buf: Type.Payload.ElemType = undefined;
1333 return ty.optionalChild(&buf).hasCodeGenBits();
1333 return ty.optionalChild(&buf).hasRuntimeBits();
13341334 },
13351335 .Pointer => {
13361336 // Slices act like struct and will be passed by reference
1337 if (ty.isSlice()) return ty.hasCodeGenBits();
1337 if (ty.isSlice()) return ty.hasRuntimeBits();
13381338 return false;
13391339 },
13401340 }
......@@ -1563,7 +1563,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
15631563 const un_op = self.air.instructions.items(.data)[inst].un_op;
15641564 const operand = try self.resolveInst(un_op);
15651565 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
15681568 if (!isByRef(ret_ty, self.target)) {
15691569 const result = try self.load(operand, ret_ty, 0);
......@@ -1611,7 +1611,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
16111611 const arg_val = try self.resolveInst(arg_ref);
16121612
16131613 const arg_ty = self.air.typeOf(arg_ref);
1614 if (!arg_ty.hasCodeGenBits()) continue;
1614 if (!arg_ty.hasRuntimeBits()) continue;
16151615 try self.emitWValue(arg_val);
16161616 }
16171617
......@@ -1631,7 +1631,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
16311631 try self.addLabel(.call_indirect, fn_type_index);
16321632 }
16331633
1634 if (self.liveness.isUnused(inst) or !ret_ty.hasCodeGenBits()) {
1634 if (self.liveness.isUnused(inst) or !ret_ty.hasRuntimeBits()) {
16351635 return WValue.none;
16361636 } else if (ret_ty.isNoReturn()) {
16371637 try self.addTag(.@"unreachable");
......@@ -1653,7 +1653,7 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
16531653 try self.initializeStack();
16541654 }
16551655
1656 if (!pointee_type.hasCodeGenBits()) {
1656 if (!pointee_type.hasRuntimeBits()) {
16571657 // when the pointee is zero-sized, we still want to create a pointer.
16581658 // but instead use a default pointer type as storage.
16591659 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
16781678 .ErrorUnion => {
16791679 const err_ty = ty.errorUnionSet();
16801680 const pl_ty = ty.errorUnionPayload();
1681 if (!pl_ty.hasCodeGenBits()) {
1681 if (!pl_ty.hasRuntimeBits()) {
16821682 const err_val = try self.load(rhs, err_ty, 0);
16831683 return self.store(lhs, err_val, err_ty, 0);
16841684 }
......@@ -1691,7 +1691,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
16911691 }
16921692 var buf: Type.Payload.ElemType = undefined;
16931693 const pl_ty = ty.optionalChild(&buf);
1694 if (!pl_ty.hasCodeGenBits()) {
1694 if (!pl_ty.hasRuntimeBits()) {
16951695 return self.store(lhs, rhs, Type.initTag(.u8), 0);
16961696 }
16971697
......@@ -1750,7 +1750,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
17501750 const operand = try self.resolveInst(ty_op.operand);
17511751 const ty = self.air.getRefType(ty_op.ty);
17521752
1753 if (!ty.hasCodeGenBits()) return WValue{ .none = {} };
1753 if (!ty.hasRuntimeBits()) return WValue{ .none = {} };
17541754
17551755 if (isByRef(ty, self.target)) {
17561756 const new_local = try self.allocStack(ty);
......@@ -2146,7 +2146,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner
21462146 if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) {
21472147 var buf: Type.Payload.ElemType = undefined;
21482148 const payload_ty = operand_ty.optionalChild(&buf);
2149 if (payload_ty.hasCodeGenBits()) {
2149 if (payload_ty.hasRuntimeBits()) {
21502150 // When we hit this case, we must check the value of optionals
21512151 // that are not pointers. This means first checking against non-null for
21522152 // 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 {
21902190 const block = self.blocks.get(br.block_inst).?;
21912191
21922192 // 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()) {
21942194 try self.emitWValue(try self.resolveInst(br.operand));
21952195
21962196 if (block.value != .none) {
......@@ -2282,7 +2282,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
22822282 const operand = try self.resolveInst(struct_field.struct_operand);
22832283 const field_index = struct_field.field_index;
22842284 const field_ty = struct_ty.structFieldType(field_index);
2285 if (!field_ty.hasCodeGenBits()) return WValue{ .none = {} };
2285 if (!field_ty.hasRuntimeBits()) return WValue{ .none = {} };
22862286 const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, self.target)) catch {
22872287 return self.fail("Field type '{}' too big to fit into stack frame", .{field_ty});
22882288 };
......@@ -2452,7 +2452,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!W
24522452
24532453 // load the error tag value
24542454 try self.emitWValue(operand);
2455 if (pl_ty.hasCodeGenBits()) {
2455 if (pl_ty.hasRuntimeBits()) {
24562456 try self.addMemArg(.i32_load16_u, .{
24572457 .offset = 0,
24582458 .alignment = err_ty.errorUnionSet().abiAlignment(self.target),
......@@ -2474,7 +2474,7 @@ fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue
24742474 const operand = try self.resolveInst(ty_op.operand);
24752475 const err_ty = self.air.typeOf(ty_op.operand);
24762476 const payload_ty = err_ty.errorUnionPayload();
2477 if (!payload_ty.hasCodeGenBits()) return WValue{ .none = {} };
2477 if (!payload_ty.hasRuntimeBits()) return WValue{ .none = {} };
24782478 const offset = @intCast(u32, err_ty.errorUnionSet().abiSize(self.target));
24792479 if (isByRef(payload_ty, self.target)) {
24802480 return self.buildPointerOffset(operand, offset, .new);
......@@ -2489,7 +2489,7 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
24892489 const operand = try self.resolveInst(ty_op.operand);
24902490 const err_ty = self.air.typeOf(ty_op.operand);
24912491 const payload_ty = err_ty.errorUnionPayload();
2492 if (!payload_ty.hasCodeGenBits()) {
2492 if (!payload_ty.hasRuntimeBits()) {
24932493 return operand;
24942494 }
24952495
......@@ -2502,7 +2502,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
25022502 const operand = try self.resolveInst(ty_op.operand);
25032503
25042504 const op_ty = self.air.typeOf(ty_op.operand);
2505 if (!op_ty.hasCodeGenBits()) return operand;
2505 if (!op_ty.hasRuntimeBits()) return operand;
25062506 const err_ty = self.air.getRefType(ty_op.ty);
25072507 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)
25802580 const payload_ty = optional_ty.optionalChild(&buf);
25812581 // When payload is zero-bits, we can treat operand as a value, rather than
25822582 // a pointer to the stack value
2583 if (payload_ty.hasCodeGenBits()) {
2583 if (payload_ty.hasRuntimeBits()) {
25842584 try self.addMemArg(.i32_load8_u, .{ .offset = 0, .alignment = 1 });
25852585 }
25862586 }
......@@ -2600,7 +2600,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
26002600 const operand = try self.resolveInst(ty_op.operand);
26012601 const opt_ty = self.air.typeOf(ty_op.operand);
26022602 const payload_ty = self.air.typeOfIndex(inst);
2603 if (!payload_ty.hasCodeGenBits()) return WValue{ .none = {} };
2603 if (!payload_ty.hasRuntimeBits()) return WValue{ .none = {} };
26042604 if (opt_ty.isPtrLikeOptional()) return operand;
26052605
26062606 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 {
26212621
26222622 var buf: Type.Payload.ElemType = undefined;
26232623 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()) {
26252625 return operand;
26262626 }
26272627
......@@ -2635,7 +2635,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue
26352635 const opt_ty = self.air.typeOf(ty_op.operand).childType();
26362636 var buf: Type.Payload.ElemType = undefined;
26372637 const payload_ty = opt_ty.optionalChild(&buf);
2638 if (!payload_ty.hasCodeGenBits()) {
2638 if (!payload_ty.hasRuntimeBits()) {
26392639 return self.fail("TODO: Implement OptionalPayloadPtrSet for optional with zero-sized type {}", .{payload_ty});
26402640 }
26412641
......@@ -2659,7 +2659,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
26592659
26602660 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
26612661 const payload_ty = self.air.typeOf(ty_op.operand);
2662 if (!payload_ty.hasCodeGenBits()) {
2662 if (!payload_ty.hasRuntimeBits()) {
26632663 const non_null_bit = try self.allocStack(Type.initTag(.u1));
26642664 try self.addLabel(.local_get, non_null_bit.local);
26652665 try self.addImm32(1);
......@@ -2851,7 +2851,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
28512851 const slice_local = try self.allocStack(slice_ty);
28522852
28532853 // store the array ptr in the slice
2854 if (array_ty.hasCodeGenBits()) {
2854 if (array_ty.hasRuntimeBits()) {
28552855 try self.store(slice_local, operand, ty, 0);
28562856 }
28572857
......@@ -3105,7 +3105,7 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
31053105}
31063106
31073107fn 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());
31093109 assert(op == .eq or op == .neq);
31103110 var buf: Type.Payload.ElemType = undefined;
31113111 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 {
12021202 const err_union_ty = self.air.typeOf(ty_op.operand);
12031203 const payload_ty = err_union_ty.errorUnionPayload();
12041204 const mcv = try self.resolveInst(ty_op.operand);
1205 if (!payload_ty.hasCodeGenBits()) break :result mcv;
1205 if (!payload_ty.hasRuntimeBits()) break :result mcv;
12061206 return self.fail("TODO implement unwrap error union error for non-empty payloads", .{});
12071207 };
12081208 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
......@@ -1213,7 +1213,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
12131213 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
12141214 const err_union_ty = self.air.typeOf(ty_op.operand);
12151215 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;
12171217 return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{});
12181218 };
12191219 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
......@@ -1270,7 +1270,7 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
12701270 const error_union_ty = self.air.getRefType(ty_op.ty);
12711271 const payload_ty = error_union_ty.errorUnionPayload();
12721272 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
12751275 return self.fail("TODO implement wrap errunion error for non-empty payloads", .{});
12761276 };
......@@ -1636,7 +1636,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
16361636 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
16371637 const elem_ty = self.air.typeOfIndex(inst);
16381638 const result: MCValue = result: {
1639 if (!elem_ty.hasCodeGenBits())
1639 if (!elem_ty.hasRuntimeBits())
16401640 break :result MCValue.none;
16411641
16421642 const ptr = try self.resolveInst(ty_op.operand);
......@@ -2739,9 +2739,9 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {
27392739fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
27402740 const err_type = ty.errorUnionSet();
27412741 const payload_type = ty.errorUnionPayload();
2742 if (!err_type.hasCodeGenBits()) {
2742 if (!err_type.hasRuntimeBits()) {
27432743 return MCValue{ .immediate = 0 }; // always false
2744 } else if (!payload_type.hasCodeGenBits()) {
2744 } else if (!payload_type.hasRuntimeBits()) {
27452745 if (err_type.abiSize(self.target.*) <= 8) {
27462746 try self.genBinMathOpMir(.cmp, err_type, .unsigned, operand, MCValue{ .immediate = 0 });
27472747 return MCValue{ .compare_flags_unsigned = .gt };
......@@ -2962,7 +2962,7 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {
29622962fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
29632963 const block_data = self.blocks.getPtr(block).?;
29642964
2965 if (self.air.typeOf(operand).hasCodeGenBits()) {
2965 if (self.air.typeOf(operand).hasRuntimeBits()) {
29662966 const operand_mcv = try self.resolveInst(operand);
29672967 const block_mcv = block_data.mcv;
29682968 if (block_mcv == .none) {
......@@ -3913,7 +3913,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
39133913 const ref_int = @enumToInt(inst);
39143914 if (ref_int < Air.Inst.Ref.typed_value_map.len) {
39153915 const tv = Air.Inst.Ref.typed_value_map[ref_int];
3916 if (!tv.ty.hasCodeGenBits()) {
3916 if (!tv.ty.hasRuntimeBits()) {
39173917 return MCValue{ .none = {} };
39183918 }
39193919 return self.genTypedValue(tv);
......@@ -3921,7 +3921,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
39213921
39223922 // If the type has no codegen bits, no need to store it.
39233923 const inst_ty = self.air.typeOf(inst);
3924 if (!inst_ty.hasCodeGenBits())
3924 if (!inst_ty.hasRuntimeBits())
39253925 return MCValue{ .none = {} };
39263926
39273927 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
39773977 return mcv;
39783978}
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
39804007fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
39814008 if (typed_value.val.isUndef())
39824009 return MCValue{ .undef = {} };
39834010 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
39854019 switch (typed_value.ty.zigTypeTag()) {
39864020 .Pointer => switch (typed_value.ty.ptrSize()) {
39874021 .Slice => {
......@@ -3998,28 +4032,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
39984032 return self.fail("TODO codegen for const slices", .{});
39994033 },
40004034 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 }
40234035 if (typed_value.val.tag() == .int_u64) {
40244036 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
40254037 }
......@@ -4091,7 +4103,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
40914103 const payload_type = typed_value.ty.errorUnionPayload();
40924104
40934105 if (typed_value.val.castTag(.eu_payload)) |pl| {
4094 if (!payload_type.hasCodeGenBits()) {
4106 if (!payload_type.hasRuntimeBits()) {
40954107 // We use the error type directly as the type.
40964108 return MCValue{ .immediate = 0 };
40974109 }
......@@ -4099,7 +4111,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
40994111 _ = pl;
41004112 return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty});
41014113 } else {
4102 if (!payload_type.hasCodeGenBits()) {
4114 if (!payload_type.hasRuntimeBits()) {
41034115 // We use the error type directly as the type.
41044116 return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val });
41054117 }
......@@ -4156,7 +4168,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
41564168 var by_reg = std.AutoHashMap(usize, usize).init(self.bin_file.allocator);
41574169 defer by_reg.deinit();
41584170 for (param_types) |ty, i| {
4159 if (!ty.hasCodeGenBits()) continue;
4171 if (!ty.hasRuntimeBits()) continue;
41604172 const param_size = @intCast(u32, ty.abiSize(self.target.*));
41614173 const pass_in_reg = switch (ty.zigTypeTag()) {
41624174 .Bool => true,
......@@ -4178,7 +4190,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
41784190 // for (param_types) |ty, i| {
41794191 const i = count - 1;
41804192 const ty = param_types[i];
4181 if (!ty.hasCodeGenBits()) {
4193 if (!ty.hasRuntimeBits()) {
41824194 assert(cc != .C);
41834195 result.args[i] = .{ .none = {} };
41844196 continue;
......@@ -4207,7 +4219,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
42074219
42084220 if (ret_ty.zigTypeTag() == .NoReturn) {
42094221 result.return_value = .{ .unreach = {} };
4210 } else if (!ret_ty.hasCodeGenBits()) {
4222 } else if (!ret_ty.hasRuntimeBits()) {
42114223 result.return_value = .{ .none = {} };
42124224 } else switch (cc) {
42134225 .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 {
885885fn addDbgInfoTypeReloc(emit: *Emit, ty: Type) !void {
886886 switch (emit.debug_output) {
887887 .dwarf => |dbg_out| {
888 assert(ty.hasCodeGenBits());
888 assert(ty.hasRuntimeBits());
889889 const index = dbg_out.dbg_info.items.len;
890890 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(
377377 const field_vals = typed_value.val.castTag(.@"struct").?.data;
378378 for (field_vals) |field_val, index| {
379379 const field_ty = typed_value.ty.structFieldType(index);
380 if (!field_ty.hasCodeGenBits()) continue;
380 if (!field_ty.hasRuntimeBits()) continue;
381381 switch (try generateSymbol(bin_file, src_loc, .{
382382 .ty = field_ty,
383383 .val = field_val,
src/codegen/c.zig+14-14
......@@ -507,7 +507,7 @@ pub const DeclGen = struct {
507507 const error_type = ty.errorUnionSet();
508508 const payload_type = ty.errorUnionPayload();
509509
510 if (!payload_type.hasCodeGenBits()) {
510 if (!payload_type.hasRuntimeBits()) {
511511 // We use the error type directly as the type.
512512 const err_val = if (val.errorUnionIsPayload()) Value.initTag(.zero) else val;
513513 return dg.renderValue(writer, error_type, err_val);
......@@ -581,7 +581,7 @@ pub const DeclGen = struct {
581581
582582 for (field_vals) |field_val, i| {
583583 const field_ty = ty.structFieldType(i);
584 if (!field_ty.hasCodeGenBits()) continue;
584 if (!field_ty.hasRuntimeBits()) continue;
585585
586586 if (i != 0) try writer.writeAll(",");
587587 try dg.renderValue(writer, field_ty, field_val);
......@@ -611,7 +611,7 @@ pub const DeclGen = struct {
611611 const index = union_ty.tag_ty.enumTagFieldIndex(union_obj.tag).?;
612612 const field_ty = ty.unionFields().values()[index].ty;
613613 const field_name = ty.unionFields().keys()[index];
614 if (field_ty.hasCodeGenBits()) {
614 if (field_ty.hasRuntimeBits()) {
615615 try writer.print(".{} = ", .{fmtIdent(field_name)});
616616 try dg.renderValue(writer, field_ty, union_obj.val);
617617 }
......@@ -652,7 +652,7 @@ pub const DeclGen = struct {
652652 }
653653 }
654654 const return_ty = dg.decl.ty.fnReturnType();
655 if (return_ty.hasCodeGenBits()) {
655 if (return_ty.hasRuntimeBits()) {
656656 try dg.renderType(w, return_ty);
657657 } else if (return_ty.zigTypeTag() == .NoReturn) {
658658 try w.writeAll("zig_noreturn void");
......@@ -784,7 +784,7 @@ pub const DeclGen = struct {
784784 var it = struct_obj.fields.iterator();
785785 while (it.next()) |entry| {
786786 const field_ty = entry.value_ptr.ty;
787 if (!field_ty.hasCodeGenBits()) continue;
787 if (!field_ty.hasRuntimeBits()) continue;
788788
789789 const alignment = entry.value_ptr.abi_align;
790790 const name: CValue = .{ .identifier = entry.key_ptr.* };
......@@ -837,7 +837,7 @@ pub const DeclGen = struct {
837837 var it = t.unionFields().iterator();
838838 while (it.next()) |entry| {
839839 const field_ty = entry.value_ptr.ty;
840 if (!field_ty.hasCodeGenBits()) continue;
840 if (!field_ty.hasRuntimeBits()) continue;
841841 const alignment = entry.value_ptr.abi_align;
842842 const name: CValue = .{ .identifier = entry.key_ptr.* };
843843 try buffer.append(' ');
......@@ -1582,7 +1582,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
15821582
15831583 const elem_type = inst_ty.elemType();
15841584 const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;
1585 if (!elem_type.hasCodeGenBits()) {
1585 if (!elem_type.isFnOrHasRuntimeBits()) {
15861586 const target = f.object.dg.module.getTarget();
15871587 const literal = switch (target.cpu.arch.ptrBitWidth()) {
15881588 32 => "(void *)0xaaaaaaaa",
......@@ -1683,7 +1683,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
16831683fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {
16841684 const un_op = f.air.instructions.items(.data)[inst].un_op;
16851685 const writer = f.object.writer();
1686 if (f.air.typeOf(un_op).hasCodeGenBits()) {
1686 if (f.air.typeOf(un_op).isFnOrHasRuntimeBits()) {
16871687 const operand = try f.resolveInst(un_op);
16881688 try writer.writeAll("return ");
16891689 try f.writeCValue(writer, operand);
......@@ -1699,7 +1699,7 @@ fn airRetLoad(f: *Function, inst: Air.Inst.Index) !CValue {
16991699 const writer = f.object.writer();
17001700 const ptr_ty = f.air.typeOf(un_op);
17011701 const ret_ty = ptr_ty.childType();
1702 if (!ret_ty.hasCodeGenBits()) {
1702 if (!ret_ty.isFnOrHasRuntimeBits()) {
17031703 try writer.writeAll("return;\n");
17041704 }
17051705 const ptr = try f.resolveInst(un_op);
......@@ -2315,7 +2315,7 @@ fn airCall(f: *Function, inst: Air.Inst.Index) !CValue {
23152315
23162316 var result_local: CValue = .none;
23172317 if (unused_result) {
2318 if (ret_ty.hasCodeGenBits()) {
2318 if (ret_ty.hasRuntimeBits()) {
23192319 try writer.print("(void)", .{});
23202320 }
23212321 } else {
......@@ -2832,7 +2832,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
28322832 const operand_ty = f.air.typeOf(ty_op.operand);
28332833
28342834 const payload_ty = operand_ty.errorUnionPayload();
2835 if (!payload_ty.hasCodeGenBits()) {
2835 if (!payload_ty.hasRuntimeBits()) {
28362836 if (operand_ty.zigTypeTag() == .Pointer) {
28372837 const local = try f.allocLocal(inst_ty, .Const);
28382838 try writer.writeAll(" = *");
......@@ -2864,7 +2864,7 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []cons
28642864 const operand_ty = f.air.typeOf(ty_op.operand);
28652865
28662866 const payload_ty = operand_ty.errorUnionPayload();
2867 if (!payload_ty.hasCodeGenBits()) {
2867 if (!payload_ty.hasRuntimeBits()) {
28682868 return CValue.none;
28692869 }
28702870
......@@ -2908,7 +2908,7 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
29082908 const operand = try f.resolveInst(ty_op.operand);
29092909 const err_un_ty = f.air.typeOfIndex(inst);
29102910 const payload_ty = err_un_ty.errorUnionPayload();
2911 if (!payload_ty.hasCodeGenBits()) {
2911 if (!payload_ty.hasRuntimeBits()) {
29122912 return operand;
29132913 }
29142914
......@@ -2951,7 +2951,7 @@ fn airIsErr(
29512951 const operand_ty = f.air.typeOf(un_op);
29522952 const local = try f.allocLocal(Type.initTag(.bool), .Const);
29532953 const payload_ty = operand_ty.errorUnionPayload();
2954 if (!payload_ty.hasCodeGenBits()) {
2954 if (!payload_ty.hasRuntimeBits()) {
29552955 try writer.print(" = {s}", .{deref_prefix});
29562956 try f.writeCValue(writer, operand);
29572957 try writer.print(" {s} 0;\n", .{op_str});
src/codegen/llvm.zig+90-71
......@@ -176,7 +176,7 @@ pub const Object = struct {
176176 /// the compiler, but the Type/Value memory here is backed by `type_map_arena`.
177177 /// TODO we need to remove entries from this map in response to incremental compilation
178178 /// 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.
180180 type_map: TypeMap,
181181 /// The backing memory for `type_map`. Periodically garbage collected after flush().
182182 /// The code for doing the periodical GC is not yet implemented.
......@@ -463,7 +463,7 @@ pub const Object = struct {
463463
464464 const param_offset: c_uint = @boolToInt(ret_ptr != null);
465465 for (fn_info.param_types) |param_ty| {
466 if (!param_ty.hasCodeGenBits()) continue;
466 if (!param_ty.hasRuntimeBits()) continue;
467467
468468 const llvm_arg_i = @intCast(c_uint, args.items.len) + param_offset;
469469 try args.append(llvm_func.getParam(llvm_arg_i));
......@@ -662,6 +662,7 @@ pub const DeclGen = struct {
662662 new_global.setAlignment(global.getAlignment());
663663 new_global.setInitializer(llvm_init);
664664 global.replaceAllUsesWith(new_global);
665 dg.object.decl_map.putAssumeCapacity(decl, new_global);
665666 new_global.takeName(global);
666667 global.deleteGlobal();
667668 }
......@@ -709,7 +710,7 @@ pub const DeclGen = struct {
709710 // Set parameter attributes.
710711 var llvm_param_i: c_uint = @boolToInt(sret);
711712 for (fn_info.param_types) |param_ty| {
712 if (!param_ty.hasCodeGenBits()) continue;
713 if (!param_ty.hasRuntimeBits()) continue;
713714
714715 if (isByRef(param_ty)) {
715716 dg.addArgAttr(llvm_fn, llvm_param_i, "nonnull");
......@@ -725,6 +726,10 @@ pub const DeclGen = struct {
725726 llvm_fn.setFunctionCallConv(toLlvmCallConv(fn_info.cc, target));
726727 }
727728
729 if (fn_info.alignment != 0) {
730 llvm_fn.setAlignment(fn_info.alignment);
731 }
732
728733 // Function attributes that are independent of analysis results of the function body.
729734 dg.addCommonFnAttributes(llvm_fn);
730735
......@@ -840,7 +845,11 @@ pub const DeclGen = struct {
840845 }
841846 const llvm_addrspace = dg.llvmAddressSpace(t.ptrAddressSpace());
842847 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)
844853 try dg.llvmType(elem_ty)
845854 else
846855 dg.context.intType(8);
......@@ -878,13 +887,13 @@ pub const DeclGen = struct {
878887 .Optional => {
879888 var buf: Type.Payload.ElemType = undefined;
880889 const child_type = t.optionalChild(&buf);
881 if (!child_type.hasCodeGenBits()) {
890 if (!child_type.hasRuntimeBits()) {
882891 return dg.context.intType(1);
883892 }
884893 const payload_llvm_ty = try dg.llvmType(child_type);
885894 if (t.isPtrLikeOptional()) {
886895 return payload_llvm_ty;
887 } else if (!child_type.hasCodeGenBits()) {
896 } else if (!child_type.hasRuntimeBits()) {
888897 return dg.context.intType(1);
889898 }
890899
......@@ -897,7 +906,7 @@ pub const DeclGen = struct {
897906 const error_type = t.errorUnionSet();
898907 const payload_type = t.errorUnionPayload();
899908 const llvm_error_type = try dg.llvmType(error_type);
900 if (!payload_type.hasCodeGenBits()) {
909 if (!payload_type.hasRuntimeBits()) {
901910 return llvm_error_type;
902911 }
903912 const llvm_payload_type = try dg.llvmType(payload_type);
......@@ -962,7 +971,7 @@ pub const DeclGen = struct {
962971 var big_align: u32 = 0;
963972 var running_bits: u16 = 0;
964973 for (struct_obj.fields.values()) |field| {
965 if (!field.ty.hasCodeGenBits()) continue;
974 if (!field.ty.hasRuntimeBits()) continue;
966975
967976 const field_align = field.packedAlignment();
968977 if (field_align == 0) {
......@@ -1029,7 +1038,7 @@ pub const DeclGen = struct {
10291038 }
10301039 } else {
10311040 for (struct_obj.fields.values()) |field| {
1032 if (!field.ty.hasCodeGenBits()) continue;
1041 if (!field.ty.hasRuntimeBits()) continue;
10331042 llvm_field_types.appendAssumeCapacity(try dg.llvmType(field.ty));
10341043 }
10351044 }
......@@ -1123,7 +1132,7 @@ pub const DeclGen = struct {
11231132 const sret = firstParamSRet(fn_info, target);
11241133 const return_type = fn_info.return_type;
11251134 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)
11271136 dg.context.voidType()
11281137 else
11291138 raw_llvm_ret_ty;
......@@ -1136,7 +1145,7 @@ pub const DeclGen = struct {
11361145 }
11371146
11381147 for (fn_info.param_types) |param_ty| {
1139 if (!param_ty.hasCodeGenBits()) continue;
1148 if (!param_ty.hasRuntimeBits()) continue;
11401149
11411150 const raw_llvm_ty = try dg.llvmType(param_ty);
11421151 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 {
11761185 const llvm_type = try dg.llvmType(tv.ty);
11771186 return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull();
11781187 },
1179 .Int => {
1180 var bigint_space: Value.BigIntSpace = undefined;
1181 const bigint = tv.val.toBigInt(&bigint_space);
1182 const target = dg.module.getTarget();
1183 const int_info = tv.ty.intInfo(target);
1184 const llvm_type = dg.context.intType(int_info.bits);
1188 // TODO this duplicates code with Pointer but they should share the handling
1189 // of the tv.val.tag() and then Int should do extra constPtrToInt on top
1190 .Int => switch (tv.val.tag()) {
1191 .decl_ref_mut => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref_mut).?.data.decl),
1192 .decl_ref => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref).?.data),
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: {
1187 if (bigint.limbs.len == 1) {
1188 break :v llvm_type.constInt(bigint.limbs[0], .False);
1189 }
1190 if (@sizeOf(usize) == @sizeOf(u64)) {
1191 break :v llvm_type.constIntOfArbitraryPrecision(
1192 @intCast(c_uint, bigint.limbs.len),
1193 bigint.limbs.ptr,
1194 );
1200 const unsigned_val = v: {
1201 if (bigint.limbs.len == 1) {
1202 break :v llvm_type.constInt(bigint.limbs[0], .False);
1203 }
1204 if (@sizeOf(usize) == @sizeOf(u64)) {
1205 break :v llvm_type.constIntOfArbitraryPrecision(
1206 @intCast(c_uint, bigint.limbs.len),
1207 bigint.limbs.ptr,
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);
11951214 }
1196 @panic("TODO implement bigint to llvm int for 32-bit compiler builds");
1197 };
1198 if (!bigint.positive) {
1199 return llvm.constNeg(unsigned_val);
1200 }
1201 return unsigned_val;
1215 return unsigned_val;
1216 },
12021217 },
12031218 .Enum => {
12041219 var int_buffer: Value.Payload.U64 = undefined;
......@@ -1370,7 +1385,7 @@ pub const DeclGen = struct {
13701385 const llvm_i1 = dg.context.intType(1);
13711386 const is_pl = !tv.val.isNull();
13721387 const non_null_bit = if (is_pl) llvm_i1.constAllOnes() else llvm_i1.constNull();
1373 if (!payload_ty.hasCodeGenBits()) {
1388 if (!payload_ty.hasRuntimeBits()) {
13741389 return non_null_bit;
13751390 }
13761391 if (tv.ty.isPtrLikeOptional()) {
......@@ -1383,6 +1398,7 @@ pub const DeclGen = struct {
13831398 return llvm_ty.constNull();
13841399 }
13851400 }
1401 assert(payload_ty.zigTypeTag() != .Fn);
13861402 const fields: [2]*const llvm.Value = .{
13871403 try dg.genTypedValue(.{
13881404 .ty = payload_ty,
......@@ -1420,7 +1436,7 @@ pub const DeclGen = struct {
14201436 const payload_type = tv.ty.errorUnionPayload();
14211437 const is_pl = tv.val.errorUnionIsPayload();
14221438
1423 if (!payload_type.hasCodeGenBits()) {
1439 if (!payload_type.hasRuntimeBits()) {
14241440 // We use the error type directly as the type.
14251441 const err_val = if (!is_pl) tv.val else Value.initTag(.zero);
14261442 return dg.genTypedValue(.{ .ty = error_type, .val = err_val });
......@@ -1458,7 +1474,7 @@ pub const DeclGen = struct {
14581474 var running_int: *const llvm.Value = llvm_struct_ty.structGetTypeAtIndex(0).constNull();
14591475 for (field_vals) |field_val, i| {
14601476 const field = fields[i];
1461 if (!field.ty.hasCodeGenBits()) continue;
1477 if (!field.ty.hasRuntimeBits()) continue;
14621478
14631479 const field_align = field.packedAlignment();
14641480 if (field_align == 0) {
......@@ -1540,7 +1556,7 @@ pub const DeclGen = struct {
15401556 } else {
15411557 for (field_vals) |field_val, i| {
15421558 const field_ty = tv.ty.structFieldType(i);
1543 if (!field_ty.hasCodeGenBits()) continue;
1559 if (!field_ty.hasRuntimeBits()) continue;
15441560
15451561 llvm_fields.appendAssumeCapacity(try dg.genTypedValue(.{
15461562 .ty = field_ty,
......@@ -1572,7 +1588,7 @@ pub const DeclGen = struct {
15721588 assert(union_obj.haveFieldTypes());
15731589 const field_ty = union_obj.fields.values()[field_index].ty;
15741590 const payload = p: {
1575 if (!field_ty.hasCodeGenBits()) {
1591 if (!field_ty.hasRuntimeBits()) {
15761592 const padding_len = @intCast(c_uint, layout.payload_size);
15771593 break :p dg.context.intType(8).arrayType(padding_len).getUndef();
15781594 }
......@@ -1784,13 +1800,14 @@ pub const DeclGen = struct {
17841800 return self.context.constStruct(&fields, fields.len, .False);
17851801 }
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()) {
17881805 return self.lowerPtrToVoid(tv.ty);
17891806 }
17901807
17911808 decl.markAlive();
17921809
1793 const llvm_val = if (decl.ty.zigTypeTag() == .Fn)
1810 const llvm_val = if (is_fn_body)
17941811 try self.resolveLlvmFunction(decl)
17951812 else
17961813 try self.resolveGlobalDecl(decl);
......@@ -2182,7 +2199,7 @@ pub const FuncGen = struct {
21822199 } else {
21832200 for (args) |arg, i| {
21842201 const param_ty = fn_info.param_types[i];
2185 if (!param_ty.hasCodeGenBits()) continue;
2202 if (!param_ty.hasRuntimeBits()) continue;
21862203
21872204 try llvm_args.append(try self.resolveInst(arg));
21882205 }
......@@ -2200,7 +2217,7 @@ pub const FuncGen = struct {
22002217 if (return_type.isNoReturn()) {
22012218 _ = self.builder.buildUnreachable();
22022219 return null;
2203 } else if (self.liveness.isUnused(inst) or !return_type.hasCodeGenBits()) {
2220 } else if (self.liveness.isUnused(inst) or !return_type.hasRuntimeBits()) {
22042221 return null;
22052222 } else if (sret) {
22062223 call.setCallSret(llvm_ret_ty);
......@@ -2224,7 +2241,7 @@ pub const FuncGen = struct {
22242241 _ = self.builder.buildRetVoid();
22252242 return null;
22262243 }
2227 if (!ret_ty.hasCodeGenBits()) {
2244 if (!ret_ty.hasRuntimeBits()) {
22282245 _ = self.builder.buildRetVoid();
22292246 return null;
22302247 }
......@@ -2237,7 +2254,7 @@ pub const FuncGen = struct {
22372254 const un_op = self.air.instructions.items(.data)[inst].un_op;
22382255 const ptr_ty = self.air.typeOf(un_op);
22392256 const ret_ty = ptr_ty.childType();
2240 if (!ret_ty.hasCodeGenBits() or isByRef(ret_ty)) {
2257 if (!ret_ty.hasRuntimeBits() or isByRef(ret_ty)) {
22412258 _ = self.builder.buildRetVoid();
22422259 return null;
22432260 }
......@@ -2273,7 +2290,7 @@ pub const FuncGen = struct {
22732290 .Int, .Bool, .Pointer, .ErrorSet => operand_ty,
22742291 .Optional => blk: {
22752292 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()) {
22772294 break :blk operand_ty;
22782295 }
22792296 // We need to emit instructions to check for equality/inequality
......@@ -2397,7 +2414,8 @@ pub const FuncGen = struct {
23972414 self.builder.positionBuilderAtEnd(parent_bb);
23982415
23992416 // 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
24022420 const raw_llvm_ty = try self.dg.llvmType(inst_ty);
24032421
......@@ -2406,7 +2424,7 @@ pub const FuncGen = struct {
24062424 // a pointer to it. LLVM IR allows the call instruction to use function bodies instead
24072425 // of function pointers, however the phi makes it a runtime value and therefore
24082426 // 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)) {
24102428 break :ty raw_llvm_ty.pointerType(0);
24112429 }
24122430 break :ty raw_llvm_ty;
......@@ -2427,7 +2445,8 @@ pub const FuncGen = struct {
24272445
24282446 // If the break doesn't break a value, then we don't have to add
24292447 // 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) {
24312450 const val = try self.resolveInst(branch.operand);
24322451
24332452 // For the phi node, we need the basic blocks and the values of the
......@@ -2531,7 +2550,7 @@ pub const FuncGen = struct {
25312550 const llvm_usize = try self.dg.llvmType(Type.usize);
25322551 const len = llvm_usize.constInt(array_ty.arrayLen(), .False);
25332552 const slice_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));
2534 if (!array_ty.hasCodeGenBits()) {
2553 if (!array_ty.hasRuntimeBits()) {
25352554 return self.builder.buildInsertValue(slice_llvm_ty.getUndef(), len, 1, "");
25362555 }
25372556 const operand = try self.resolveInst(ty_op.operand);
......@@ -2662,7 +2681,7 @@ pub const FuncGen = struct {
26622681 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
26632682 const ptr_ty = self.air.typeOf(bin_op.lhs);
26642683 const elem_ty = ptr_ty.childType();
2665 if (!elem_ty.hasCodeGenBits()) return null;
2684 if (!elem_ty.hasRuntimeBits()) return null;
26662685
26672686 const base_ptr = try self.resolveInst(bin_op.lhs);
26682687 const rhs = try self.resolveInst(bin_op.rhs);
......@@ -2709,7 +2728,7 @@ pub const FuncGen = struct {
27092728 const struct_llvm_val = try self.resolveInst(struct_field.struct_operand);
27102729 const field_index = struct_field.field_index;
27112730 const field_ty = struct_ty.structFieldType(field_index);
2712 if (!field_ty.hasCodeGenBits()) {
2731 if (!field_ty.hasRuntimeBits()) {
27132732 return null;
27142733 }
27152734 const target = self.dg.module.getTarget();
......@@ -2914,7 +2933,7 @@ pub const FuncGen = struct {
29142933
29152934 var buf: Type.Payload.ElemType = undefined;
29162935 const payload_ty = optional_ty.optionalChild(&buf);
2917 if (!payload_ty.hasCodeGenBits()) {
2936 if (!payload_ty.hasRuntimeBits()) {
29182937 if (invert) {
29192938 return self.builder.buildNot(operand, "");
29202939 } else {
......@@ -2946,7 +2965,7 @@ pub const FuncGen = struct {
29462965 const err_set_ty = try self.dg.llvmType(Type.initTag(.anyerror));
29472966 const zero = err_set_ty.constNull();
29482967
2949 if (!payload_ty.hasCodeGenBits()) {
2968 if (!payload_ty.hasRuntimeBits()) {
29502969 const loaded = if (operand_is_ptr) self.builder.buildLoad(operand, "") else operand;
29512970 return self.builder.buildICmp(op, loaded, zero, "");
29522971 }
......@@ -2969,7 +2988,7 @@ pub const FuncGen = struct {
29692988 const optional_ty = self.air.typeOf(ty_op.operand).childType();
29702989 var buf: Type.Payload.ElemType = undefined;
29712990 const payload_ty = optional_ty.optionalChild(&buf);
2972 if (!payload_ty.hasCodeGenBits()) {
2991 if (!payload_ty.hasRuntimeBits()) {
29732992 // We have a pointer to a zero-bit value and we need to return
29742993 // a pointer to a zero-bit value.
29752994 return operand;
......@@ -2993,7 +3012,7 @@ pub const FuncGen = struct {
29933012 var buf: Type.Payload.ElemType = undefined;
29943013 const payload_ty = optional_ty.optionalChild(&buf);
29953014 const non_null_bit = self.context.intType(1).constAllOnes();
2996 if (!payload_ty.hasCodeGenBits()) {
3015 if (!payload_ty.hasRuntimeBits()) {
29973016 // We have a pointer to a i1. We need to set it to 1 and then return the same pointer.
29983017 _ = self.builder.buildStore(non_null_bit, operand);
29993018 return operand;
......@@ -3028,7 +3047,7 @@ pub const FuncGen = struct {
30283047 const operand = try self.resolveInst(ty_op.operand);
30293048 const optional_ty = self.air.typeOf(ty_op.operand);
30303049 const payload_ty = self.air.typeOfIndex(inst);
3031 if (!payload_ty.hasCodeGenBits()) return null;
3050 if (!payload_ty.hasRuntimeBits()) return null;
30323051
30333052 if (optional_ty.isPtrLikeOptional()) {
30343053 // Payload value is the same as the optional value.
......@@ -3049,7 +3068,7 @@ pub const FuncGen = struct {
30493068 const operand = try self.resolveInst(ty_op.operand);
30503069 const err_union_ty = self.air.typeOf(ty_op.operand);
30513070 const payload_ty = err_union_ty.errorUnionPayload();
3052 if (!payload_ty.hasCodeGenBits()) return null;
3071 if (!payload_ty.hasRuntimeBits()) return null;
30533072 if (operand_is_ptr or isByRef(payload_ty)) {
30543073 return self.builder.buildStructGEP(operand, 1, "");
30553074 }
......@@ -3069,7 +3088,7 @@ pub const FuncGen = struct {
30693088 const operand_ty = self.air.typeOf(ty_op.operand);
30703089
30713090 const payload_ty = operand_ty.errorUnionPayload();
3072 if (!payload_ty.hasCodeGenBits()) {
3091 if (!payload_ty.hasRuntimeBits()) {
30733092 if (!operand_is_ptr) return operand;
30743093 return self.builder.buildLoad(operand, "");
30753094 }
......@@ -3088,7 +3107,7 @@ pub const FuncGen = struct {
30883107 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
30893108 const payload_ty = self.air.typeOf(ty_op.operand);
30903109 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;
30923111 const operand = try self.resolveInst(ty_op.operand);
30933112 const optional_ty = self.air.typeOfIndex(inst);
30943113 if (optional_ty.isPtrLikeOptional()) return operand;
......@@ -3116,7 +3135,7 @@ pub const FuncGen = struct {
31163135 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
31173136 const payload_ty = self.air.typeOf(ty_op.operand);
31183137 const operand = try self.resolveInst(ty_op.operand);
3119 if (!payload_ty.hasCodeGenBits()) {
3138 if (!payload_ty.hasRuntimeBits()) {
31203139 return operand;
31213140 }
31223141 const inst_ty = self.air.typeOfIndex(inst);
......@@ -3147,7 +3166,7 @@ pub const FuncGen = struct {
31473166 const err_un_ty = self.air.typeOfIndex(inst);
31483167 const payload_ty = err_un_ty.errorUnionPayload();
31493168 const operand = try self.resolveInst(ty_op.operand);
3150 if (!payload_ty.hasCodeGenBits()) {
3169 if (!payload_ty.hasRuntimeBits()) {
31513170 return operand;
31523171 }
31533172 const err_un_llvm_ty = try self.dg.llvmType(err_un_ty);
......@@ -3836,7 +3855,7 @@ pub const FuncGen = struct {
38363855 if (self.liveness.isUnused(inst)) return null;
38373856 const ptr_ty = self.air.typeOfIndex(inst);
38383857 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
38413860 const pointee_llvm_ty = try self.dg.llvmType(pointee_type);
38423861 const alloca_inst = self.buildAlloca(pointee_llvm_ty);
......@@ -3850,7 +3869,7 @@ pub const FuncGen = struct {
38503869 if (self.liveness.isUnused(inst)) return null;
38513870 const ptr_ty = self.air.typeOfIndex(inst);
38523871 const ret_ty = ptr_ty.childType();
3853 if (!ret_ty.hasCodeGenBits()) return null;
3872 if (!ret_ty.isFnOrHasRuntimeBits()) return null;
38543873 if (self.ret_ptr) |ret_ptr| return ret_ptr;
38553874 const ret_llvm_ty = try self.dg.llvmType(ret_ty);
38563875 const target = self.dg.module.getTarget();
......@@ -4074,7 +4093,7 @@ pub const FuncGen = struct {
40744093 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
40754094 const ptr_ty = self.air.typeOf(bin_op.lhs);
40764095 const operand_ty = ptr_ty.childType();
4077 if (!operand_ty.hasCodeGenBits()) return null;
4096 if (!operand_ty.isFnOrHasRuntimeBits()) return null;
40784097 var ptr = try self.resolveInst(bin_op.lhs);
40794098 var element = try self.resolveInst(bin_op.rhs);
40804099 const opt_abi_ty = self.dg.getAtomicAbiType(operand_ty, false);
......@@ -4674,7 +4693,7 @@ pub const FuncGen = struct {
46744693 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
46754694 const field = &union_obj.fields.values()[field_index];
46764695 const result_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));
4677 if (!field.ty.hasCodeGenBits()) {
4696 if (!field.ty.hasRuntimeBits()) {
46784697 return null;
46794698 }
46804699 const target = self.dg.module.getTarget();
......@@ -4702,7 +4721,7 @@ pub const FuncGen = struct {
47024721
47034722 fn load(self: *FuncGen, ptr: *const llvm.Value, ptr_ty: Type) !?*const llvm.Value {
47044723 const info = ptr_ty.ptrInfo().data;
4705 if (!info.pointee_type.hasCodeGenBits()) return null;
4724 if (!info.pointee_type.hasRuntimeBits()) return null;
47064725
47074726 const target = self.dg.module.getTarget();
47084727 const ptr_alignment = ptr_ty.ptrAlignment(target);
......@@ -4757,7 +4776,7 @@ pub const FuncGen = struct {
47574776 ) void {
47584777 const info = ptr_ty.ptrInfo().data;
47594778 const elem_ty = info.pointee_type;
4760 if (!elem_ty.hasCodeGenBits()) {
4779 if (!elem_ty.isFnOrHasRuntimeBits()) {
47614780 return;
47624781 }
47634782 const target = self.dg.module.getTarget();
......@@ -5087,7 +5106,7 @@ fn llvmFieldIndex(
50875106 if (struct_obj.layout != .Packed) {
50885107 var llvm_field_index: c_uint = 0;
50895108 for (struct_obj.fields.values()) |field, i| {
5090 if (!field.ty.hasCodeGenBits())
5109 if (!field.ty.hasRuntimeBits())
50915110 continue;
50925111 if (field_index > i) {
50935112 llvm_field_index += 1;
......@@ -5114,7 +5133,7 @@ fn llvmFieldIndex(
51145133 var running_bits: u16 = 0;
51155134 var llvm_field_index: c_uint = 0;
51165135 for (struct_obj.fields.values()) |field, i| {
5117 if (!field.ty.hasCodeGenBits())
5136 if (!field.ty.hasRuntimeBits())
51185137 continue;
51195138
51205139 const field_align = field.packedAlignment();
......@@ -5227,9 +5246,9 @@ fn isByRef(ty: Type) bool {
52275246 .AnyFrame,
52285247 => return false,
52295248
5230 .Array, .Frame => return ty.hasCodeGenBits(),
5249 .Array, .Frame => return ty.hasRuntimeBits(),
52315250 .Struct => {
5232 if (!ty.hasCodeGenBits()) return false;
5251 if (!ty.hasRuntimeBits()) return false;
52335252 if (ty.castTag(.tuple)) |tuple| {
52345253 var count: usize = 0;
52355254 for (tuple.data.values) |field_val, i| {
......@@ -5247,7 +5266,7 @@ fn isByRef(ty: Type) bool {
52475266 }
52485267 return true;
52495268 },
5250 .Union => return ty.hasCodeGenBits(),
5269 .Union => return ty.hasRuntimeBits(),
52515270 .ErrorUnion => return isByRef(ty.errorUnionPayload()),
52525271 .Optional => {
52535272 var buf: Type.Payload.ElemType = undefined;
src/codegen/spirv.zig+3-3
......@@ -852,7 +852,7 @@ pub const DeclGen = struct {
852852 try self.beginSPIRVBlock(label_id);
853853
854854 // If this block didn't produce a value, simply return here.
855 if (!ty.hasCodeGenBits())
855 if (!ty.hasRuntimeBits())
856856 return null;
857857
858858 // Combine the result from the blocks using the Phi instruction.
......@@ -879,7 +879,7 @@ pub const DeclGen = struct {
879879 const block = self.blocks.get(br.block_inst).?;
880880 const operand_ty = self.air.typeOf(br.operand);
881881
882 if (operand_ty.hasCodeGenBits()) {
882 if (operand_ty.hasRuntimeBits()) {
883883 const operand_id = try self.resolve(br.operand);
884884 // current_block_label_id should not be undefined here, lest there is a br or br_void in the function's body.
885885 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 {
958958 fn airRet(self: *DeclGen, inst: Air.Inst.Index) !void {
959959 const operand = self.air.instructions.items(.data)[inst].un_op;
960960 const operand_ty = self.air.typeOf(operand);
961 if (operand_ty.hasCodeGenBits()) {
961 if (operand_ty.hasRuntimeBits()) {
962962 const operand_id = try self.resolve(operand);
963963 try writeInstruction(&self.code, .OpReturnValue, &[_]Word{operand_id});
964964 } else {
src/link/Elf.zig+1-1
......@@ -2476,7 +2476,7 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven
24762476 try dbg_info_buffer.ensureUnusedCapacity(25 + decl_name_with_null.len);
24772477
24782478 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();
24802480 if (fn_ret_has_bits) {
24812481 dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram);
24822482 } else {
src/link/MachO/DebugSymbols.zig+1-1
......@@ -920,7 +920,7 @@ pub fn initDeclDebugBuffers(
920920 try dbg_info_buffer.ensureUnusedCapacity(27 + decl_name_with_null.len);
921921
922922 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();
924924 if (fn_ret_has_bits) {
925925 dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram);
926926 } else {
src/link/Wasm.zig+1-1
......@@ -259,7 +259,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
259259 if (build_options.have_llvm) {
260260 if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(module, decl);
261261 }
262 if (!decl.ty.hasCodeGenBits()) return;
262 if (!decl.ty.hasRuntimeBits()) return;
263263 assert(decl.link.wasm.sym_index != 0); // Must call allocateDeclIndexes()
264264
265265 decl.link.wasm.clear();
src/print_zir.zig+2-1
......@@ -1157,7 +1157,8 @@ const Writer = struct {
11571157 break :blk decls_len;
11581158 } 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);
11611162 try stream.print("{s}, {s}, ", .{
11621163 @tagName(small.name_strategy), @tagName(small.layout),
11631164 });
src/target.zig+9
......@@ -637,3 +637,12 @@ pub fn llvmMachineAbi(target: std.Target) ?[:0]const u8 {
637637 else => return null,
638638 }
639639}
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;
55const Target = std.Target;
66const Module = @import("Module.zig");
77const log = std.log.scoped(.Type);
8const target_util = @import("target.zig");
89
910const file_struct = @This();
1011
......@@ -577,21 +578,36 @@ pub const Type = extern union {
577578 }
578579 },
579580 .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))
581585 return false;
582 if (a.fnCallingConvention() != b.fnCallingConvention())
586
587 if (a_info.cc != b_info.cc)
583588 return false;
584 const a_param_len = a.fnParamLen();
585 const b_param_len = b.fnParamLen();
586 if (a_param_len != b_param_len)
589
590 if (a_info.param_types.len != b_info.param_types.len)
587591 return false;
588 var i: usize = 0;
589 while (i < a_param_len) : (i += 1) {
590 if (!a.fnParamType(i).eql(b.fnParamType(i)))
592
593 for (a_info.param_types) |a_param_ty, 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])
591599 return false;
592600 }
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)
594606 return false;
607
608 if (a_info.is_generic != b_info.is_generic)
609 return false;
610
595611 return true;
596612 },
597613 .Optional => {
......@@ -686,6 +702,7 @@ pub const Type = extern union {
686702 return false;
687703 },
688704 .Float => return a.tag() == b.tag(),
705
689706 .BoundFn,
690707 .Frame,
691708 => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }),
......@@ -937,6 +954,7 @@ pub const Type = extern union {
937954 .return_type = try payload.return_type.copy(allocator),
938955 .param_types = param_types,
939956 .cc = payload.cc,
957 .alignment = payload.alignment,
940958 .is_var_args = payload.is_var_args,
941959 .is_generic = payload.is_generic,
942960 .comptime_params = comptime_params.ptr,
......@@ -1114,9 +1132,15 @@ pub const Type = extern union {
11141132 }
11151133 try writer.writeAll("...");
11161134 }
1117 try writer.writeAll(") callconv(.");
1118 try writer.writeAll(@tagName(payload.cc));
11191135 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 }
11201144 ty = payload.return_type;
11211145 continue;
11221146 },
......@@ -1423,170 +1447,6 @@ pub const Type = extern union {
14231447 }
14241448 }
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
15901450 pub fn toValue(self: Type, allocator: Allocator) Allocator.Error!Value {
15911451 switch (self.tag()) {
15921452 .u1 => return Value.initTag(.u1_type),
......@@ -1652,8 +1512,12 @@ pub const Type = extern union {
16521512 }
16531513 }
16541514
1655 pub fn hasCodeGenBits(self: Type) bool {
1656 return switch (self.tag()) {
1515 /// true if and only if the type takes up space in memory at runtime.
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()) {
16571521 .u1,
16581522 .u8,
16591523 .i8,
......@@ -1682,13 +1546,9 @@ pub const Type = extern union {
16821546 .f128,
16831547 .bool,
16841548 .anyerror,
1685 .single_const_pointer_to_comptime_int,
16861549 .const_slice_u8,
16871550 .const_slice_u8_sentinel_0,
16881551 .array_u8_sentinel_0,
1689 .optional,
1690 .optional_single_mut_pointer,
1691 .optional_single_const_pointer,
16921552 .anyerror_void_error_union,
16931553 .error_set,
16941554 .error_set_single,
......@@ -1708,9 +1568,40 @@ pub const Type = extern union {
17081568 .export_options,
17091569 .extern_options,
17101570 .@"anyframe",
1711 .anyframe_T,
17121571 .anyopaque,
17131572 .@"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,
17141605 .single_const_pointer,
17151606 .single_mut_pointer,
17161607 .many_const_pointer,
......@@ -1720,102 +1611,84 @@ pub const Type = extern union {
17201611 .const_slice,
17211612 .mut_slice,
17221613 .pointer,
1723 => true,
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,
1614 => !ty.comptimeOnly(),
17321615
17331616 .@"struct" => {
1734 const struct_obj = self.castTag(.@"struct").?.data;
1735 if (struct_obj.known_has_bits) {
1736 return true;
1617 const struct_obj = ty.castTag(.@"struct").?.data;
1618 switch (struct_obj.requires_comptime) {
1619 .wip => unreachable,
1620 .yes => return false,
1621 .no => if (struct_obj.known_non_opv) return true,
1622 .unknown => {},
17371623 }
17381624 assert(struct_obj.haveFieldTypes());
17391625 for (struct_obj.fields.values()) |value| {
1740 if (value.ty.hasCodeGenBits())
1626 if (value.ty.hasRuntimeBits())
17411627 return true;
17421628 } else {
17431629 return false;
17441630 }
17451631 },
1632
17461633 .enum_full => {
1747 const enum_full = self.castTag(.enum_full).?.data;
1634 const enum_full = ty.castTag(.enum_full).?.data;
17481635 return enum_full.fields.count() >= 2;
17491636 },
17501637 .enum_simple => {
1751 const enum_simple = self.castTag(.enum_simple).?.data;
1638 const enum_simple = ty.castTag(.enum_simple).?.data;
17521639 return enum_simple.fields.count() >= 2;
17531640 },
17541641 .enum_numbered, .enum_nonexhaustive => {
17551642 var buffer: Payload.Bits = undefined;
1756 const int_tag_ty = self.intTagType(&buffer);
1757 return int_tag_ty.hasCodeGenBits();
1643 const int_tag_ty = ty.intTagType(&buffer);
1644 return int_tag_ty.hasRuntimeBits();
17581645 },
1646
17591647 .@"union" => {
1760 const union_obj = self.castTag(.@"union").?.data;
1648 const union_obj = ty.castTag(.@"union").?.data;
17611649 assert(union_obj.haveFieldTypes());
17621650 for (union_obj.fields.values()) |value| {
1763 if (value.ty.hasCodeGenBits())
1651 if (value.ty.hasRuntimeBits())
17641652 return true;
17651653 } else {
17661654 return false;
17671655 }
17681656 },
17691657 .union_tagged => {
1770 const union_obj = self.castTag(.union_tagged).?.data;
1771 if (union_obj.tag_ty.hasCodeGenBits()) {
1658 const union_obj = ty.castTag(.union_tagged).?.data;
1659 if (union_obj.tag_ty.hasRuntimeBits()) {
17721660 return true;
17731661 }
17741662 assert(union_obj.haveFieldTypes());
17751663 for (union_obj.fields.values()) |value| {
1776 if (value.ty.hasCodeGenBits())
1664 if (value.ty.hasRuntimeBits())
17771665 return true;
17781666 } else {
17791667 return false;
17801668 }
17811669 },
17821670
1783 .array, .vector => self.elemType().hasCodeGenBits() and self.arrayLen() != 0,
1784 .array_u8 => self.arrayLen() != 0,
1785
1786 .array_sentinel => self.childType().hasCodeGenBits(),
1671 .array, .vector => ty.arrayLen() != 0 and ty.elemType().hasRuntimeBits(),
1672 .array_u8 => ty.arrayLen() != 0,
1673 .array_sentinel => ty.childType().hasRuntimeBits(),
17871674
1788 .int_signed, .int_unsigned => self.cast(Payload.Bits).?.data != 0,
1675 .int_signed, .int_unsigned => ty.cast(Payload.Bits).?.data != 0,
17891676
17901677 .error_union => {
1791 const payload = self.castTag(.error_union).?.data;
1792 return payload.error_set.hasCodeGenBits() or payload.payload.hasCodeGenBits();
1678 const payload = ty.castTag(.error_union).?.data;
1679 return payload.error_set.hasRuntimeBits() or payload.payload.hasRuntimeBits();
17931680 },
17941681
17951682 .tuple => {
1796 const tuple = self.castTag(.tuple).?.data;
1797 for (tuple.types) |ty, i| {
1683 const tuple = ty.castTag(.tuple).?.data;
1684 for (tuple.types) |field_ty, i| {
17981685 const val = tuple.values[i];
17991686 if (val.tag() != .unreachable_value) continue; // comptime field
1800 if (ty.hasCodeGenBits()) return true;
1687 if (field_ty.hasRuntimeBits()) return true;
18011688 }
18021689 return false;
18031690 },
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
18191692 .inferred_alloc_const => unreachable,
18201693 .inferred_alloc_mut => unreachable,
18211694 .var_args_param => unreachable,
......@@ -1823,6 +1696,24 @@ pub const Type = extern union {
18231696 };
18241697 }
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
18261717 pub fn isNoReturn(self: Type) bool {
18271718 const definitely_correct_result =
18281719 self.tag_if_small_enough != .bound_fn and
......@@ -1918,12 +1809,13 @@ pub const Type = extern union {
19181809 .fn_void_no_args, // represents machine code; not a pointer
19191810 .fn_naked_noreturn_no_args, // represents machine code; not a pointer
19201811 .fn_ccc_void_no_args, // represents machine code; not a pointer
1921 .function, // represents machine code; not a pointer
1922 => return switch (target.cpu.arch) {
1923 .arm, .armeb => 4,
1924 .aarch64, .aarch64_32, .aarch64_be => 4,
1925 .riscv64 => 2,
1926 else => 1,
1812 => return target_util.defaultFunctionAlignment(target),
1813
1814 // represents machine code; not a pointer
1815 .function => {
1816 const alignment = self.castTag(.function).?.data.alignment;
1817 if (alignment != 0) return alignment;
1818 return target_util.defaultFunctionAlignment(target);
19271819 },
19281820
19291821 .i16, .u16 => return 2,
......@@ -1996,7 +1888,7 @@ pub const Type = extern union {
19961888 .optional => {
19971889 var buf: Payload.ElemType = undefined;
19981890 const child_type = self.optionalChild(&buf);
1999 if (!child_type.hasCodeGenBits()) return 1;
1891 if (!child_type.hasRuntimeBits()) return 1;
20001892
20011893 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())
20021894 return @divExact(target.cpu.arch.ptrBitWidth(), 8);
......@@ -2006,9 +1898,9 @@ pub const Type = extern union {
20061898
20071899 .error_union => {
20081900 const data = self.castTag(.error_union).?.data;
2009 if (!data.error_set.hasCodeGenBits()) {
1901 if (!data.error_set.hasRuntimeBits()) {
20101902 return data.payload.abiAlignment(target);
2011 } else if (!data.payload.hasCodeGenBits()) {
1903 } else if (!data.payload.hasRuntimeBits()) {
20121904 return data.error_set.abiAlignment(target);
20131905 }
20141906 return @maximum(
......@@ -2028,7 +1920,7 @@ pub const Type = extern union {
20281920 if (!is_packed) {
20291921 var big_align: u32 = 0;
20301922 for (fields.values()) |field| {
2031 if (!field.ty.hasCodeGenBits()) continue;
1923 if (!field.ty.hasRuntimeBits()) continue;
20321924
20331925 const field_align = field.normalAlignment(target);
20341926 big_align = @maximum(big_align, field_align);
......@@ -2042,7 +1934,7 @@ pub const Type = extern union {
20421934 var running_bits: u16 = 0;
20431935
20441936 for (fields.values()) |field| {
2045 if (!field.ty.hasCodeGenBits()) continue;
1937 if (!field.ty.hasRuntimeBits()) continue;
20461938
20471939 const field_align = field.packedAlignment();
20481940 if (field_align == 0) {
......@@ -2080,7 +1972,7 @@ pub const Type = extern union {
20801972 for (tuple.types) |field_ty, i| {
20811973 const val = tuple.values[i];
20821974 if (val.tag() != .unreachable_value) continue; // comptime field
2083 if (!field_ty.hasCodeGenBits()) continue;
1975 if (!field_ty.hasRuntimeBits()) continue;
20841976
20851977 const field_align = field_ty.abiAlignment(target);
20861978 big_align = @maximum(big_align, field_align);
......@@ -2123,7 +2015,7 @@ pub const Type = extern union {
21232015 }
21242016
21252017 /// 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.
21272019 pub fn abiSize(self: Type, target: Target) u64 {
21282020 return switch (self.tag()) {
21292021 .fn_noreturn_no_args => unreachable, // represents machine code; not a pointer
......@@ -2210,24 +2102,8 @@ pub const Type = extern union {
22102102 .usize,
22112103 .@"anyframe",
22122104 .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
22242105 .optional_single_const_pointer,
22252106 .optional_single_mut_pointer,
2226 => {
2227 if (!self.elemType().hasCodeGenBits()) return 1;
2228 return @divExact(target.cpu.arch.ptrBitWidth(), 8);
2229 },
2230
22312107 .single_const_pointer,
22322108 .single_mut_pointer,
22332109 .many_const_pointer,
......@@ -2239,6 +2115,12 @@ pub const Type = extern union {
22392115 .manyptr_const_u8_sentinel_0,
22402116 => 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
22422124 .pointer => switch (self.castTag(.pointer).?.data.size) {
22432125 .Slice => @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2,
22442126 else => @divExact(target.cpu.arch.ptrBitWidth(), 8),
......@@ -2276,7 +2158,7 @@ pub const Type = extern union {
22762158 .optional => {
22772159 var buf: Payload.ElemType = undefined;
22782160 const child_type = self.optionalChild(&buf);
2279 if (!child_type.hasCodeGenBits()) return 1;
2161 if (!child_type.hasRuntimeBits()) return 1;
22802162
22812163 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr() and !child_type.isSlice())
22822164 return @divExact(target.cpu.arch.ptrBitWidth(), 8);
......@@ -2290,11 +2172,11 @@ pub const Type = extern union {
22902172
22912173 .error_union => {
22922174 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()) {
22942176 return 0;
2295 } else if (!data.error_set.hasCodeGenBits()) {
2177 } else if (!data.error_set.hasRuntimeBits()) {
22962178 return data.payload.abiSize(target);
2297 } else if (!data.payload.hasCodeGenBits()) {
2179 } else if (!data.payload.hasRuntimeBits()) {
22982180 return data.error_set.abiSize(target);
22992181 }
23002182 const code_align = abiAlignment(data.error_set, target);
......@@ -2414,11 +2296,7 @@ pub const Type = extern union {
24142296 .optional_single_const_pointer,
24152297 .optional_single_mut_pointer,
24162298 => {
2417 if (ty.elemType().hasCodeGenBits()) {
2418 return target.cpu.arch.ptrBitWidth();
2419 } else {
2420 return 1;
2421 }
2299 return target.cpu.arch.ptrBitWidth();
24222300 },
24232301
24242302 .single_const_pointer,
......@@ -2428,11 +2306,7 @@ pub const Type = extern union {
24282306 .c_const_pointer,
24292307 .c_mut_pointer,
24302308 => {
2431 if (ty.elemType().hasCodeGenBits()) {
2432 return target.cpu.arch.ptrBitWidth();
2433 } else {
2434 return 0;
2435 }
2309 return target.cpu.arch.ptrBitWidth();
24362310 },
24372311
24382312 .pointer => switch (ty.castTag(.pointer).?.data.size) {
......@@ -2468,7 +2342,7 @@ pub const Type = extern union {
24682342 .optional => {
24692343 var buf: Payload.ElemType = undefined;
24702344 const child_type = ty.optionalChild(&buf);
2471 if (!child_type.hasCodeGenBits()) return 8;
2345 if (!child_type.hasRuntimeBits()) return 8;
24722346
24732347 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr() and !child_type.isSlice())
24742348 return target.cpu.arch.ptrBitWidth();
......@@ -2482,11 +2356,11 @@ pub const Type = extern union {
24822356
24832357 .error_union => {
24842358 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()) {
24862360 return 0;
2487 } else if (!payload.error_set.hasCodeGenBits()) {
2361 } else if (!payload.error_set.hasRuntimeBits()) {
24882362 return payload.payload.bitSize(target);
2489 } else if (!payload.payload.hasCodeGenBits()) {
2363 } else if (!payload.payload.hasRuntimeBits()) {
24902364 return payload.error_set.bitSize(target);
24912365 }
24922366 @panic("TODO bitSize error union");
......@@ -2728,7 +2602,7 @@ pub const Type = extern union {
27282602 var buf: Payload.ElemType = undefined;
27292603 const child_type = self.optionalChild(&buf);
27302604 // optionals of zero sized pointers behave like bools
2731 if (!child_type.hasCodeGenBits()) return false;
2605 if (!child_type.hasRuntimeBits()) return false;
27322606 if (child_type.zigTypeTag() != .Pointer) return false;
27332607
27342608 const info = child_type.ptrInfo().data;
......@@ -2765,7 +2639,7 @@ pub const Type = extern union {
27652639 var buf: Payload.ElemType = undefined;
27662640 const child_type = self.optionalChild(&buf);
27672641 // optionals of zero sized types behave like bools, not pointers
2768 if (!child_type.hasCodeGenBits()) return false;
2642 if (!child_type.hasRuntimeBits()) return false;
27692643 if (child_type.zigTypeTag() != .Pointer) return false;
27702644
27712645 const info = child_type.ptrInfo().data;
......@@ -3424,6 +3298,7 @@ pub const Type = extern union {
34243298 .comptime_params = undefined,
34253299 .return_type = initTag(.noreturn),
34263300 .cc = .Unspecified,
3301 .alignment = 0,
34273302 .is_var_args = false,
34283303 .is_generic = false,
34293304 },
......@@ -3432,6 +3307,7 @@ pub const Type = extern union {
34323307 .comptime_params = undefined,
34333308 .return_type = initTag(.void),
34343309 .cc = .Unspecified,
3310 .alignment = 0,
34353311 .is_var_args = false,
34363312 .is_generic = false,
34373313 },
......@@ -3440,6 +3316,7 @@ pub const Type = extern union {
34403316 .comptime_params = undefined,
34413317 .return_type = initTag(.noreturn),
34423318 .cc = .Naked,
3319 .alignment = 0,
34433320 .is_var_args = false,
34443321 .is_generic = false,
34453322 },
......@@ -3448,6 +3325,7 @@ pub const Type = extern union {
34483325 .comptime_params = undefined,
34493326 .return_type = initTag(.void),
34503327 .cc = .C,
3328 .alignment = 0,
34513329 .is_var_args = false,
34523330 .is_generic = false,
34533331 },
......@@ -3629,7 +3507,7 @@ pub const Type = extern union {
36293507 },
36303508 .enum_nonexhaustive => {
36313509 const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty;
3632 if (!tag_ty.hasCodeGenBits()) {
3510 if (!tag_ty.hasRuntimeBits()) {
36333511 return Value.zero;
36343512 } else {
36353513 return null;
......@@ -3672,6 +3550,167 @@ pub const Type = extern union {
36723550 };
36733551 }
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
36753714 pub fn isIndexable(ty: Type) bool {
36763715 return switch (ty.zigTypeTag()) {
36773716 .Array, .Vector => true,
......@@ -3949,7 +3988,7 @@ pub const Type = extern union {
39493988
39503989 const field = it.struct_obj.fields.values()[it.field];
39513990 defer it.field += 1;
3952 if (!field.ty.hasCodeGenBits()) {
3991 if (!field.ty.hasRuntimeBits()) {
39533992 return PackedFieldOffset{
39543993 .field = it.field,
39553994 .offset = it.offset,
......@@ -4018,7 +4057,7 @@ pub const Type = extern union {
40184057
40194058 const field = it.struct_obj.fields.values()[it.field];
40204059 defer it.field += 1;
4021 if (!field.ty.hasCodeGenBits())
4060 if (!field.ty.hasRuntimeBits())
40224061 return FieldOffset{ .field = it.field, .offset = it.offset };
40234062
40244063 const field_align = field.normalAlignment(it.target);
......@@ -4572,6 +4611,8 @@ pub const Type = extern union {
45724611 param_types: []Type,
45734612 comptime_params: [*]bool,
45744613 return_type: Type,
4614 /// If zero use default target function code alignment.
4615 alignment: u32,
45754616 cc: std.builtin.CallingConvention,
45764617 is_var_args: bool,
45774618 is_generic: bool,
src/value.zig+72-7
......@@ -1225,7 +1225,7 @@ pub const Value = extern union {
12251225
12261226 /// Asserts the value is an integer and not undefined.
12271227 /// 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 {
12291229 switch (self.tag()) {
12301230 .zero,
12311231 .bool_false,
......@@ -1244,6 +1244,15 @@ pub const Value = extern union {
12441244 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().bitCountTwosComp(),
12451245 .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
12471256 else => {
12481257 var buffer: BigIntSpace = undefined;
12491258 return self.toBigInt(&buffer).bitCountTwosComp();
......@@ -1333,6 +1342,20 @@ pub const Value = extern union {
13331342 return true;
13341343 },
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
13361359 else => unreachable,
13371360 }
13381361 }
......@@ -1397,6 +1420,11 @@ pub const Value = extern union {
13971420
13981421 .one,
13991422 .bool_true,
1423 .decl_ref,
1424 .decl_ref_mut,
1425 .extern_fn,
1426 .function,
1427 .variable,
14001428 => .gt,
14011429
14021430 .int_u64 => std.math.order(lhs.castTag(.int_u64).?.data, 0),
......@@ -1417,10 +1445,18 @@ pub const Value = extern union {
14171445 pub fn order(lhs: Value, rhs: Value) std.math.Order {
14181446 const lhs_tag = lhs.tag();
14191447 const rhs_tag = rhs.tag();
1420 const lhs_is_zero = lhs_tag == .zero;
1421 const rhs_is_zero = rhs_tag == .zero;
1422 if (lhs_is_zero) return rhs.orderAgainstZero().invert();
1423 if (rhs_is_zero) return lhs.orderAgainstZero();
1448 const lhs_against_zero = lhs.orderAgainstZero();
1449 const rhs_against_zero = rhs.orderAgainstZero();
1450 switch (lhs_against_zero) {
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
14251461 const lhs_float = lhs.isFloat();
14261462 const rhs_float = rhs.isFloat();
......@@ -1451,6 +1487,27 @@ pub const Value = extern union {
14511487 /// Asserts the value is comparable. Does not take a type parameter because it supports
14521488 /// comparisons between heterogeneous types.
14531489 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 }
14541511 return order(lhs, rhs).compare(op);
14551512 }
14561513
......@@ -1520,6 +1577,11 @@ pub const Value = extern union {
15201577 }
15211578 return true;
15221579 },
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 },
15231585 else => {},
15241586 }
15251587 } else if (a_tag == .null_value or b_tag == .null_value) {
......@@ -1573,6 +1635,7 @@ pub const Value = extern union {
15731635 pub fn hash(val: Value, ty: Type, hasher: *std.hash.Wyhash) void {
15741636 const zig_ty_tag = ty.zigTypeTag();
15751637 std.hash.autoHash(hasher, zig_ty_tag);
1638 if (val.isUndef()) return;
15761639
15771640 switch (zig_ty_tag) {
15781641 .BoundFn => unreachable, // TODO remove this from the language
......@@ -1694,7 +1757,8 @@ pub const Value = extern union {
16941757 union_obj.val.hash(active_field_ty, hasher);
16951758 },
16961759 .Fn => {
1697 @panic("TODO implement hashing function values");
1760 const func = val.castTag(.function).?.data;
1761 return std.hash.autoHash(hasher, func.owner_decl);
16981762 },
16991763 .Frame => {
17001764 @panic("TODO implement hashing frame values");
......@@ -1703,7 +1767,8 @@ pub const Value = extern union {
17031767 @panic("TODO implement hashing anyframe values");
17041768 },
17051769 .EnumLiteral => {
1706 @panic("TODO implement hashing enum literal values");
1770 const bytes = val.castTag(.enum_literal).?.data;
1771 hasher.update(bytes);
17071772 },
17081773 }
17091774 }
test/behavior.zig+9-12
......@@ -2,22 +2,23 @@ const builtin = @import("builtin");
22
33test {
44 // 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");
510 _ = @import("behavior/bugs/1111.zig");
611 _ = @import("behavior/bugs/2346.zig");
7 _ = @import("behavior/slice_sentinel_comptime.zig");
8 _ = @import("behavior/bugs/679.zig");
912 _ = @import("behavior/bugs/6850.zig");
13 _ = @import("behavior/cast.zig");
14 _ = @import("behavior/comptime_memory.zig");
1015 _ = @import("behavior/fn_in_struct_in_comptime.zig");
1116 _ = @import("behavior/hasdecl.zig");
1217 _ = @import("behavior/hasfield.zig");
1318 _ = @import("behavior/prefetch.zig");
1419 _ = @import("behavior/pub_enum.zig");
20 _ = @import("behavior/slice_sentinel_comptime.zig");
1521 _ = @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
2223 if (builtin.zig_backend != .stage2_arm and builtin.zig_backend != .stage2_x86_64) {
2324 // Tests that pass for stage1, llvm backend, C backend, wasm backend.
......@@ -113,11 +114,7 @@ test {
113114 _ = @import("behavior/switch.zig");
114115 _ = @import("behavior/widening.zig");
115116
116 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 {
117 if (builtin.zig_backend == .stage1) {
121118 // Tests that only pass for the stage1 backend.
122119 _ = @import("behavior/align_stage1.zig");
123120 if (builtin.os.tag != .wasi) {
test/behavior/align.zig+25-2
......@@ -165,8 +165,9 @@ fn give() anyerror!u128 {
165165}
166166
167167test "page aligned array on stack" {
168 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm or
169 builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
168 if (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
171172 // Large alignment value to make it hard to accidentally pass.
172173 var array align(0x1000) = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
......@@ -181,3 +182,25 @@ test "page aligned array on stack" {
181182 try expect(number1 == 42);
182183 try expect(number2 == 43);
183184}
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;
33const builtin = @import("builtin");
44const 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
236test "implicitly decreasing fn alignment" {
247 // function alignment is a compile error on wasm32/wasm64
258 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 {
259259}
260260
261261test "call function pointer in struct" {
262 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
263
262264 try expect(mem.eql(u8, f3(true), "a"));
263265 try expect(mem.eql(u8, f3(false), "b"));
264266}
......@@ -276,7 +278,7 @@ fn f3(x: bool) []const u8 {
276278}
277279
278280const FnPtrWrapper = struct {
279 fn_ptr: fn () []const u8,
281 fn_ptr: *const fn () []const u8,
280282};
281283
282284test "const ptr from var variable" {
test/behavior/basic_llvm.zig+3-1
......@@ -205,9 +205,11 @@ test "multiline string literal is null terminated" {
205205}
206206
207207test "self reference through fn ptr field" {
208 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
209
208210 const S = struct {
209211 const A = struct {
210 f: fn (A) u8,
212 f: *const fn (A) u8,
211213 };
212214
213215 fn foo(a: A) u8 {
test/behavior/bugs/1500.zig+1-1
......@@ -2,7 +2,7 @@ const A = struct {
22 b: B,
33};
44
5const B = fn (A) void;
5const B = *const fn (A) void;
66
77test "allow these dependencies" {
88 var a: A = undefined;
test/behavior/bugs/3112.zig+4-1
......@@ -1,9 +1,10 @@
1const builtin = @import("builtin");
12const std = @import("std");
23const expect = std.testing.expect;
34
45const State = struct {
56 const Self = @This();
6 enter: fn (previous: ?Self) void,
7 enter: *const fn (previous: ?Self) void,
78};
89
910fn prev(p: ?State) void {
......@@ -11,6 +12,8 @@ fn prev(p: ?State) void {
1112}
1213
1314test "zig test crash" {
15 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
16
1417 var global: State = undefined;
1518 global.enter = prev;
1619 global.enter(null);
test/behavior/cast_llvm.zig+9-3
......@@ -47,12 +47,14 @@ fn incrementVoidPtrArray(array: ?*anyopaque, len: usize) void {
4747}
4848
4949test "compile time int to ptr of function" {
50 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
5051 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) return error.SkipZigTest; // TODO
52
5153 try foobar(FUNCTION_CONSTANT);
5254}
5355
5456pub 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
5759fn foobar(func: PFN_void) !void {
5860 try std.testing.expect(@ptrToInt(func) == maxInt(usize));
......@@ -153,8 +155,12 @@ test "implicit cast *[0]T to E![]const u8" {
153155}
154156
155157var global_array: [4]u8 = undefined;
156test "cast from array reference to fn" {
157 const f = @ptrCast(fn () callconv(.C) void, &global_array);
158test "cast from array reference to fn: comptime fn ptr" {
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);
158164 try expect(@ptrToInt(f) == @ptrToInt(&global_array));
159165}
160166
test/behavior/comptime_memory.zig+98-1
......@@ -1,8 +1,15 @@
1const endian = @import("builtin").cpu.arch.endian();
1const builtin = @import("builtin");
2const endian = builtin.cpu.arch.endian();
23const testing = @import("std").testing;
34const ptr_size = @sizeOf(usize);
45
56test "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
613 comptime {
714 var x: u32 = 0;
815 const y = @ptrCast(*i32, &x);
......@@ -12,6 +19,12 @@ test "type pun signed and unsigned as single pointer" {
1219}
1320
1421test "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
1528 comptime {
1629 var x: u32 = 0;
1730 const y = @ptrCast([*]i32, &x);
......@@ -21,6 +34,12 @@ test "type pun signed and unsigned as many pointer" {
2134}
2235
2336test "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
2443 comptime {
2544 var x: u32 = 0;
2645 const y = @ptrCast(*[1]i32, &x);
......@@ -30,6 +49,12 @@ test "type pun signed and unsigned as array pointer" {
3049}
3150
3251test "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
3358 comptime {
3459 var x: u32 = 0;
3560 var y = @ptrCast([*]i32, &x);
......@@ -40,6 +65,12 @@ test "type pun signed and unsigned as offset many pointer" {
4065}
4166
4267test "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
4374 comptime {
4475 var x: u32 = 0;
4576 const y = @ptrCast([*]i32, &x) - 10;
......@@ -50,6 +81,12 @@ test "type pun signed and unsigned as array pointer" {
5081}
5182
5283test "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
5390 comptime {
5491 const StructOfU32 = extern struct { x: u32 };
5592 var inst: StructOfU32 = .{ .x = 0 };
......@@ -64,6 +101,12 @@ fn bigToNativeEndian(comptime T: type, v: T) T {
64101 return if (endian == .Big) v else @byteSwap(T, v);
65102}
66103test "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
67110 comptime {
68111 const StructOfBytes = extern struct { x: [4]u8 };
69112 var inst: StructOfBytes = .{ .x = [4]u8{ 0, 0, 0, 0 } };
......@@ -155,6 +198,12 @@ fn doTypePunBitsTest(as_bits: *Bits) !void {
155198}
156199
157200test "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
158207 comptime {
159208 var v: u32 = undefined;
160209 try doTypePunBitsTest(@ptrCast(*Bits, &v));
......@@ -167,6 +216,12 @@ const imports = struct {
167216
168217// Make sure lazy values work on their own, before getting into more complex tests
169218test "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
170225 comptime {
171226 const lazy_address = @ptrToInt(&imports.global_u32);
172227 try testing.expectEqual(@ptrToInt(&imports.global_u32), lazy_address);
......@@ -175,6 +230,12 @@ test "basic pointer preservation" {
175230}
176231
177232test "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
178239 const ct_value = comptime blk: {
179240 const lazy = &imports.global_u32;
180241 var result: *u32 = undefined;
......@@ -193,6 +254,12 @@ test "byte copy preserves linker value" {
193254}
194255
195256test "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
196263 const ct_value = comptime blk: {
197264 const lazy = &imports.global_u32;
198265 var result: *u32 = undefined;
......@@ -212,6 +279,12 @@ test "unordered byte copy preserves linker value" {
212279}
213280
214281test "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
215288 const lazy_address = @ptrToInt(&imports.global_u32);
216289 const shuffled1_rt = shuffle(lazy_address, Bits, ShuffledBits);
217290 const unshuffled1_rt = shuffle(shuffled1_rt, ShuffledBits, Bits);
......@@ -225,6 +298,12 @@ test "shuffle chunks of linker value" {
225298}
226299
227300test "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
228307 comptime {
229308 var arr: [2]usize = undefined;
230309 arr[0] = @ptrToInt(&imports.global_u32);
......@@ -251,6 +330,12 @@ test "dance on linker values" {
251330}
252331
253332test "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
254339 comptime {
255340 const VirtualStruct = struct { x: u32 };
256341 var arr: [4]VirtualStruct = .{
......@@ -273,6 +358,12 @@ test "offset array ptr by element size" {
273358}
274359
275360test "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
276367 comptime {
277368 const VirtualStruct = struct { x: u32, y: u32, z: u32, w: u32 };
278369 var inst = VirtualStruct{ .x = 0, .y = 1, .z = 2, .w = 3 };
......@@ -293,6 +384,12 @@ test "offset instance by field size" {
293384}
294385
295386test "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
296393 comptime {
297394 const VirtualStruct = struct { x: u32 };
298395 var arr: [4]VirtualStruct = .{
test/behavior/error.zig+1
......@@ -1,3 +1,4 @@
1const builtin = @import("builtin");
12const std = @import("std");
23const expect = std.testing.expect;
34const expectError = std.testing.expectError;
test/behavior/fn.zig+9-3
......@@ -57,7 +57,7 @@ test "assign inline fn to const variable" {
5757
5858inline fn inlineFn() void {}
5959
60fn outer(y: u32) fn (u32) u32 {
60fn outer(y: u32) *const fn (u32) u32 {
6161 const Y = @TypeOf(y);
6262 const st = struct {
6363 fn get(z: u32) u32 {
......@@ -68,6 +68,8 @@ fn outer(y: u32) fn (u32) u32 {
6868}
6969
7070test "return inner function which references comptime variable of outer function" {
71 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
72
7173 var func = outer(10);
7274 try expect(func(3) == 7);
7375}
......@@ -92,6 +94,8 @@ test "discard the result of a function that returns a struct" {
9294}
9395
9496test "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
9599 const S = struct {
96100 field: u32,
97101
......@@ -113,7 +117,7 @@ test "inline function call that calls optional function pointer, return pointer
113117 return bar2.?();
114118 }
115119
116 var bar2: ?fn () u32 = null;
120 var bar2: ?*const fn () u32 = null;
117121
118122 fn actualFn() u32 {
119123 return 1234;
......@@ -135,8 +139,10 @@ fn fnWithUnreachable() noreturn {
135139}
136140
137141test "extern struct with stdcallcc fn pointer" {
142 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
143
138144 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
141147 fn foo() callconv(if (builtin.target.cpu.arch == .i386) .Stdcall else .C) i32 {
142148 return 1234;
test/behavior/inttoptr.zig+7-5
......@@ -1,14 +1,16 @@
11const 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;
45 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) return error.SkipZigTest; // TODO
5 randomAddressToFunction();
6 comptime randomAddressToFunction();
6
7 addressToFunction();
8 comptime addressToFunction();
79}
810
9fn randomAddressToFunction() void {
11fn addressToFunction() void {
1012 var addr: usize = 0xdeadbeef;
11 _ = @intToPtr(fn () void, addr);
13 _ = @intToPtr(*const fn () void, addr);
1214}
1315
1416test "mutate through ptr initialized with constant intToPtr value" {
test/behavior/member_func.zig+8-2
......@@ -1,8 +1,10 @@
1const expect = @import("std").testing.expect;
1const builtin = @import("builtin");
2const std = @import("std");
3const expect = std.testing.expect;
24
35const HasFuncs = struct {
46 state: u32,
5 func_field: fn (u32) u32,
7 func_field: *const fn (u32) u32,
68
79 fn inc(self: *HasFuncs) void {
810 self.state += 1;
......@@ -25,6 +27,8 @@ const HasFuncs = struct {
2527};
2628
2729test "standard field calls" {
30 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
31
2832 try expect(HasFuncs.one(0) == 1);
2933 try expect(HasFuncs.two(0) == 2);
3034
......@@ -64,6 +68,8 @@ test "standard field calls" {
6468}
6569
6670test "@field field calls" {
71 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
72
6773 try expect(@field(HasFuncs, "one")(0) == 1);
6874 try expect(@field(HasFuncs, "two")(0) == 2);
6975
test/behavior/slice.zig+13
......@@ -1,3 +1,4 @@
1const builtin = @import("builtin");
12const std = @import("std");
23const expect = std.testing.expect;
34const expectEqualSlices = std.testing.expectEqualSlices;
......@@ -166,3 +167,15 @@ test "slicing zero length array" {
166167 try expect(mem.eql(u8, s1, ""));
167168 try expect(mem.eql(u32, s2, &[_]u32{}));
168169}
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 @@
1const builtin = @import("builtin");
12const std = @import("std");
23const expect = std.testing.expect;
34const expectEqual = std.testing.expectEqual;
......@@ -166,8 +167,10 @@ test "union with specified enum tag" {
166167}
167168
168169test "packed union generates correctly aligned LLVM type" {
170 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
171
169172 const U = packed union {
170 f1: fn () error{TestUnexpectedResult}!void,
173 f1: *const fn () error{TestUnexpectedResult}!void,
171174 f2: u32,
172175 };
173176 var foo = [_]U{
test/stage2/arm.zig+1-1
......@@ -751,7 +751,7 @@ pub fn addCases(ctx: *TestContext) !void {
751751 {
752752 var case = ctx.exe("function pointers", linux_arm);
753753 case.addCompareOutput(
754 \\const PrintFn = fn () void;
754 \\const PrintFn = *const fn () void;
755755 \\
756756 \\pub fn main() void {
757757 \\ var printFn: PrintFn = stopSayingThat;