authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-21 00:49:58-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-24 21:47:53-07:00
logb34f994c0ba2d87fce2a3409d6bcfa7a5ebe78ff
tree436e0ad81e8baddbdcbe5d7148338bcac11a23df
parent0866fa9d1d46f3c66a4adcaf1d863e762f874c6c

stage2: type system treats fn ptr and body separately

This commit updates stage2 to enforce the property that the syntax `fn()void` is a function *body* not a *pointer*. To get a pointer, the syntax `*const fn()void` is required. ZIR puts function alignment into the func instruction rather than the decl because this way it makes it into function types. LLVM backend respects function alignments. Struct and Union have methods `fieldSrcLoc` to help look up source locations of their fields. These trigger full loading, tokenization, and parsing of source files, so should only be called once it is confirmed that an error message needs to be printed. There are some nice new error hints for explaining why a type is required to be comptime, particularly for structs that contain function body types. `Type.requiresComptime` is now moved into Sema because it can fail and might need to trigger field type resolution. Comptime pointer loading takes into account types that do not have a well-defined memory layout and does not try to compute a byte offset for them. `fn()void` syntax no longer secretly makes a pointer. You get a function body type, which requires comptime. However a pointer to a function body can be runtime known (obviously). Compile errors that report "expected pointer, found ..." are factored out into convenience functions `checkPtrOperand` and `checkPtrType` and have a note about function pointers. Implemented `Value.hash` for functions, enum literals, and undefined values. stage1 is not updated to this (yet?), so some workarounds and disabled tests are needed to keep everything working. Should we update stage1 to these new type semantics? Yes probably because I don't want to add too much conditional compilation logic in the std lib for the different backends.

24 files changed, 856 insertions(+), 354 deletions(-)

lib/std/builtin.zig+7-1
...@@ -730,10 +730,16 @@ pub const CompilerBackend = enum(u64) {...@@ -730,10 +730,16 @@ pub const CompilerBackend = enum(u64) {
730/// therefore must be kept in sync with the compiler implementation.730/// therefore must be kept in sync with the compiler implementation.
731pub const TestFn = struct {731pub const TestFn = struct {
732 name: []const u8,732 name: []const u8,
733 func: fn () anyerror!void,733 func: testFnProto,
734 async_frame_size: ?usize,734 async_frame_size: ?usize,
735};735};
736736
737/// stage1 is *wrong*. It is not yet updated to support the new function type semantics.
738const testFnProto = switch (builtin.zig_backend) {
739 .stage1 => fn () anyerror!void, // wrong!
740 else => *const fn () anyerror!void,
741};
742
737/// This function type is used by the Zig language code generation and743/// This function type is used by the Zig language code generation and
738/// therefore must be kept in sync with the compiler implementation.744/// therefore must be kept in sync with the compiler implementation.
739pub const PanicFn = fn ([]const u8, ?*StackTrace) noreturn;745pub const PanicFn = fn ([]const u8, ?*StackTrace) noreturn;
src/AstGen.zig+4-6
...@@ -3240,7 +3240,8 @@ fn fnDecl(...@@ -3240,7 +3240,8 @@ fn fnDecl(
3240 const doc_comment_index = try astgen.docCommentAsString(fn_proto.firstToken());3240 const doc_comment_index = try astgen.docCommentAsString(fn_proto.firstToken());
32413241
3242 const has_section_or_addrspace = fn_proto.ast.section_expr != 0 or fn_proto.ast.addrspace_expr != 0;3242 const has_section_or_addrspace = fn_proto.ast.section_expr != 0 or fn_proto.ast.addrspace_expr != 0;
3243 wip_members.nextDecl(is_pub, is_export, fn_proto.ast.align_expr != 0, has_section_or_addrspace);3243 // Alignment is passed in the func instruction in this case.
3244 wip_members.nextDecl(is_pub, is_export, false, has_section_or_addrspace);
32443245
3245 var params_scope = &fn_gz.base;3246 var params_scope = &fn_gz.base;
3246 const is_var_args = is_var_args: {3247 const is_var_args = is_var_args: {
...@@ -3380,7 +3381,7 @@ fn fnDecl(...@@ -3380,7 +3381,7 @@ fn fnDecl(
3380 .param_block = block_inst,3381 .param_block = block_inst,
3381 .body_gz = null,3382 .body_gz = null,
3382 .cc = cc,3383 .cc = cc,
3383 .align_inst = .none, // passed in the per-decl data3384 .align_inst = align_inst,
3384 .lib_name = lib_name,3385 .lib_name = lib_name,
3385 .is_var_args = is_var_args,3386 .is_var_args = is_var_args,
3386 .is_inferred_error = false,3387 .is_inferred_error = false,
...@@ -3423,7 +3424,7 @@ fn fnDecl(...@@ -3423,7 +3424,7 @@ fn fnDecl(
3423 .ret_br = ret_br,3424 .ret_br = ret_br,
3424 .body_gz = &fn_gz,3425 .body_gz = &fn_gz,
3425 .cc = cc,3426 .cc = cc,
3426 .align_inst = .none, // passed in the per-decl data3427 .align_inst = align_inst,
3427 .lib_name = lib_name,3428 .lib_name = lib_name,
3428 .is_var_args = is_var_args,3429 .is_var_args = is_var_args,
3429 .is_inferred_error = is_inferred_error,3430 .is_inferred_error = is_inferred_error,
...@@ -3449,9 +3450,6 @@ fn fnDecl(...@@ -3449,9 +3450,6 @@ fn fnDecl(
3449 wip_members.appendToDecl(fn_name_str_index);3450 wip_members.appendToDecl(fn_name_str_index);
3450 wip_members.appendToDecl(block_inst);3451 wip_members.appendToDecl(block_inst);
3451 wip_members.appendToDecl(doc_comment_index);3452 wip_members.appendToDecl(doc_comment_index);
3452 if (align_inst != .none) {
3453 wip_members.appendToDecl(@enumToInt(align_inst));
3454 }
3455 if (has_section_or_addrspace) {3453 if (has_section_or_addrspace) {
3456 wip_members.appendToDecl(@enumToInt(section_inst));3454 wip_members.appendToDecl(@enumToInt(section_inst));
3457 wip_members.appendToDecl(@enumToInt(addrspace_inst));3455 wip_members.appendToDecl(@enumToInt(addrspace_inst));
src/Module.zig+117-2
...@@ -898,6 +898,45 @@ pub const Struct = struct {...@@ -898,6 +898,45 @@ pub const Struct = struct {
898 };898 };
899 }899 }
900900
901 pub fn fieldSrcLoc(s: Struct, gpa: Allocator, query: FieldSrcQuery) SrcLoc {
902 @setCold(true);
903 const tree = s.owner_decl.getFileScope().getTree(gpa) catch |err| {
904 // In this case we emit a warning + a less precise source location.
905 log.warn("unable to load {s}: {s}", .{
906 s.owner_decl.getFileScope().sub_file_path, @errorName(err),
907 });
908 return s.srcLoc();
909 };
910 const node = s.owner_decl.relativeToNodeIndex(s.node_offset);
911 const node_tags = tree.nodes.items(.tag);
912 const file = s.owner_decl.getFileScope();
913 switch (node_tags[node]) {
914 .container_decl,
915 .container_decl_trailing,
916 => return queryFieldSrc(tree.*, query, file, tree.containerDecl(node)),
917 .container_decl_two, .container_decl_two_trailing => {
918 var buffer: [2]Ast.Node.Index = undefined;
919 return queryFieldSrc(tree.*, query, file, tree.containerDeclTwo(&buffer, node));
920 },
921 .container_decl_arg,
922 .container_decl_arg_trailing,
923 => return queryFieldSrc(tree.*, query, file, tree.containerDeclArg(node)),
924
925 .tagged_union,
926 .tagged_union_trailing,
927 => return queryFieldSrc(tree.*, query, file, tree.taggedUnion(node)),
928 .tagged_union_two, .tagged_union_two_trailing => {
929 var buffer: [2]Ast.Node.Index = undefined;
930 return queryFieldSrc(tree.*, query, file, tree.taggedUnionTwo(&buffer, node));
931 },
932 .tagged_union_enum_tag,
933 .tagged_union_enum_tag_trailing,
934 => return queryFieldSrc(tree.*, query, file, tree.taggedUnionEnumTag(node)),
935
936 else => unreachable,
937 }
938 }
939
901 pub fn haveFieldTypes(s: Struct) bool {940 pub fn haveFieldTypes(s: Struct) bool {
902 return switch (s.status) {941 return switch (s.status) {
903 .none,942 .none,
...@@ -1063,6 +1102,33 @@ pub const Union = struct {...@@ -1063,6 +1102,33 @@ pub const Union = struct {
1063 };1102 };
1064 }1103 }
10651104
1105 pub fn fieldSrcLoc(u: Union, gpa: Allocator, query: FieldSrcQuery) SrcLoc {
1106 @setCold(true);
1107 const tree = u.owner_decl.getFileScope().getTree(gpa) catch |err| {
1108 // In this case we emit a warning + a less precise source location.
1109 log.warn("unable to load {s}: {s}", .{
1110 u.owner_decl.getFileScope().sub_file_path, @errorName(err),
1111 });
1112 return u.srcLoc();
1113 };
1114 const node = u.owner_decl.relativeToNodeIndex(u.node_offset);
1115 const node_tags = tree.nodes.items(.tag);
1116 const file = u.owner_decl.getFileScope();
1117 switch (node_tags[node]) {
1118 .container_decl,
1119 .container_decl_trailing,
1120 => return queryFieldSrc(tree.*, query, file, tree.containerDecl(node)),
1121 .container_decl_two, .container_decl_two_trailing => {
1122 var buffer: [2]Ast.Node.Index = undefined;
1123 return queryFieldSrc(tree.*, query, file, tree.containerDeclTwo(&buffer, node));
1124 },
1125 .container_decl_arg,
1126 .container_decl_arg_trailing,
1127 => return queryFieldSrc(tree.*, query, file, tree.containerDeclArg(node)),
1128 else => unreachable,
1129 }
1130 }
1131
1066 pub fn haveFieldTypes(u: Union) bool {1132 pub fn haveFieldTypes(u: Union) bool {
1067 return switch (u.status) {1133 return switch (u.status) {
1068 .none,1134 .none,
...@@ -4662,8 +4728,8 @@ pub fn createAnonymousDeclFromDeclNamed(...@@ -4662,8 +4728,8 @@ pub fn createAnonymousDeclFromDeclNamed(
4662 new_decl.src_line = src_decl.src_line;4728 new_decl.src_line = src_decl.src_line;
4663 new_decl.ty = typed_value.ty;4729 new_decl.ty = typed_value.ty;
4664 new_decl.val = typed_value.val;4730 new_decl.val = typed_value.val;
4665 new_decl.align_val = Value.initTag(.null_value);4731 new_decl.align_val = Value.@"null";
4666 new_decl.linksection_val = Value.initTag(.null_value);4732 new_decl.linksection_val = Value.@"null";
4667 new_decl.has_tv = true;4733 new_decl.has_tv = true;
4668 new_decl.analysis = .complete;4734 new_decl.analysis = .complete;
4669 new_decl.generation = mod.generation;4735 new_decl.generation = mod.generation;
...@@ -4905,6 +4971,55 @@ pub const PeerTypeCandidateSrc = union(enum) {...@@ -4905,6 +4971,55 @@ pub const PeerTypeCandidateSrc = union(enum) {
4905 }4971 }
4906};4972};
49074973
4974const FieldSrcQuery = struct {
4975 index: usize,
4976 range: enum { name, type, value, alignment },
4977};
4978
4979fn queryFieldSrc(
4980 tree: Ast,
4981 query: FieldSrcQuery,
4982 file_scope: *File,
4983 container_decl: Ast.full.ContainerDecl,
4984) SrcLoc {
4985 const node_tags = tree.nodes.items(.tag);
4986 var field_index: usize = 0;
4987 for (container_decl.ast.members) |member_node| {
4988 const field = switch (node_tags[member_node]) {
4989 .container_field_init => tree.containerFieldInit(member_node),
4990 .container_field_align => tree.containerFieldAlign(member_node),
4991 .container_field => tree.containerField(member_node),
4992 else => continue,
4993 };
4994 if (field_index == query.index) {
4995 return switch (query.range) {
4996 .name => .{
4997 .file_scope = file_scope,
4998 .parent_decl_node = 0,
4999 .lazy = .{ .token_abs = field.ast.name_token },
5000 },
5001 .type => .{
5002 .file_scope = file_scope,
5003 .parent_decl_node = 0,
5004 .lazy = .{ .node_abs = field.ast.type_expr },
5005 },
5006 .value => .{
5007 .file_scope = file_scope,
5008 .parent_decl_node = 0,
5009 .lazy = .{ .node_abs = field.ast.value_expr },
5010 },
5011 .alignment => .{
5012 .file_scope = file_scope,
5013 .parent_decl_node = 0,
5014 .lazy = .{ .node_abs = field.ast.align_expr },
5015 },
5016 };
5017 }
5018 field_index += 1;
5019 }
5020 unreachable;
5021}
5022
4908/// Called from `performAllTheWork`, after all AstGen workers have finished,5023/// Called from `performAllTheWork`, after all AstGen workers have finished,
4909/// and before the main semantic analysis loop begins.5024/// and before the main semantic analysis loop begins.
4910pub fn processOutdatedAndDeletedDecls(mod: *Module) !void {5025pub fn processOutdatedAndDeletedDecls(mod: *Module) !void {
src/Sema.zig+473-103
...@@ -4147,7 +4147,7 @@ fn analyzeCall(...@@ -4147,7 +4147,7 @@ fn analyzeCall(
4147 const gpa = sema.gpa;4147 const gpa = sema.gpa;
41484148
4149 const is_comptime_call = block.is_comptime or modifier == .compile_time or4149 const is_comptime_call = block.is_comptime or modifier == .compile_time or
4150 func_ty_info.return_type.requiresComptime();4150 try sema.typeRequiresComptime(block, func_src, func_ty_info.return_type);
4151 const is_inline_call = is_comptime_call or modifier == .always_inline or4151 const is_inline_call = is_comptime_call or modifier == .always_inline or
4152 func_ty_info.cc == .Inline;4152 func_ty_info.cc == .Inline;
4153 const result: Air.Inst.Ref = if (is_inline_call) res: {4153 const result: Air.Inst.Ref = if (is_inline_call) res: {
...@@ -4576,7 +4576,7 @@ fn analyzeCall(...@@ -4576,7 +4576,7 @@ fn analyzeCall(
4576 }4576 }
4577 } else if (is_anytype) {4577 } else if (is_anytype) {
4578 const arg_ty = sema.typeOf(arg);4578 const arg_ty = sema.typeOf(arg);
4579 if (arg_ty.requiresComptime()) {4579 if (try sema.typeRequiresComptime(block, arg_src, arg_ty)) {
4580 const arg_val = try sema.resolveConstValue(block, arg_src, arg);4580 const arg_val = try sema.resolveConstValue(block, arg_src, arg);
4581 const child_arg = try child_sema.addConstant(arg_ty, arg_val);4581 const child_arg = try child_sema.addConstant(arg_ty, arg_val);
4582 child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);4582 child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
...@@ -5430,7 +5430,6 @@ fn funcCommon(...@@ -5430,7 +5430,6 @@ fn funcCommon(
5430 src_locs: Zir.Inst.Func.SrcLocs,5430 src_locs: Zir.Inst.Func.SrcLocs,
5431 opt_lib_name: ?[]const u8,5431 opt_lib_name: ?[]const u8,
5432) CompileError!Air.Inst.Ref {5432) CompileError!Air.Inst.Ref {
5433 const src: LazySrcLoc = .{ .node_offset = src_node_offset };
5434 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };5433 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
54355434
5436 // The return type body might be a type expression that depends on generic parameters.5435 // The return type body might be a type expression that depends on generic parameters.
...@@ -5481,11 +5480,22 @@ fn funcCommon(...@@ -5481,11 +5480,22 @@ fn funcCommon(
5481 errdefer if (maybe_inferred_error_set_node) |node| sema.gpa.destroy(node);5480 errdefer if (maybe_inferred_error_set_node) |node| sema.gpa.destroy(node);
5482 // Note: no need to errdefer since this will still be in its default state at the end of the function.5481 // Note: no need to errdefer since this will still be in its default state at the end of the function.
54835482
5483 const target = mod.getTarget();
5484
5484 const fn_ty: Type = fn_ty: {5485 const fn_ty: Type = fn_ty: {
5486 const alignment: u32 = if (align_val.tag() == .null_value) 0 else a: {
5487 const alignment = @intCast(u32, align_val.toUnsignedInt());
5488 if (alignment == target_util.defaultFunctionAlignment(target)) {
5489 break :a 0;
5490 } else {
5491 break :a alignment;
5492 }
5493 };
5494
5485 // Hot path for some common function types.5495 // Hot path for some common function types.
5486 // TODO can we eliminate some of these Type tag values? seems unnecessarily complicated.5496 // TODO can we eliminate some of these Type tag values? seems unnecessarily complicated.
5487 if (!is_generic and block.params.items.len == 0 and !var_args and5497 if (!is_generic and block.params.items.len == 0 and !var_args and
5488 align_val.tag() == .null_value and !inferred_error_set)5498 alignment == 0 and !inferred_error_set)
5489 {5499 {
5490 if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {5500 if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {
5491 break :fn_ty Type.initTag(.fn_noreturn_no_args);5501 break :fn_ty Type.initTag(.fn_noreturn_no_args);
...@@ -5507,16 +5517,15 @@ fn funcCommon(...@@ -5507,16 +5517,15 @@ fn funcCommon(
5507 const param_types = try sema.arena.alloc(Type, block.params.items.len);5517 const param_types = try sema.arena.alloc(Type, block.params.items.len);
5508 const comptime_params = try sema.arena.alloc(bool, block.params.items.len);5518 const comptime_params = try sema.arena.alloc(bool, block.params.items.len);
5509 for (block.params.items) |param, i| {5519 for (block.params.items) |param, i| {
5520 const param_src: LazySrcLoc = .{ .node_offset = src_node_offset }; // TODO better src
5510 param_types[i] = param.ty;5521 param_types[i] = param.ty;
5511 comptime_params[i] = param.is_comptime or param.ty.requiresComptime();5522 comptime_params[i] = param.is_comptime or
5523 try sema.typeRequiresComptime(block, param_src, param.ty);
5512 is_generic = is_generic or comptime_params[i] or param.ty.tag() == .generic_poison;5524 is_generic = is_generic or comptime_params[i] or param.ty.tag() == .generic_poison;
5513 }5525 }
55145526
5515 if (align_val.tag() != .null_value) {5527 is_generic = is_generic or
5516 return sema.fail(block, src, "TODO implement support for function prototypes to have alignment specified", .{});5528 try sema.typeRequiresComptime(block, ret_ty_src, bare_return_type);
5517 }
5518
5519 is_generic = is_generic or bare_return_type.requiresComptime();
55205529
5521 const return_type = if (!inferred_error_set or bare_return_type.tag() == .generic_poison)5530 const return_type = if (!inferred_error_set or bare_return_type.tag() == .generic_poison)
5522 bare_return_type5531 bare_return_type
...@@ -5537,6 +5546,7 @@ fn funcCommon(...@@ -5537,6 +5546,7 @@ fn funcCommon(
5537 .comptime_params = comptime_params.ptr,5546 .comptime_params = comptime_params.ptr,
5538 .return_type = return_type,5547 .return_type = return_type,
5539 .cc = cc,5548 .cc = cc,
5549 .alignment = alignment,
5540 .is_var_args = var_args,5550 .is_var_args = var_args,
5541 .is_generic = is_generic,5551 .is_generic = is_generic,
5542 });5552 });
...@@ -5550,7 +5560,6 @@ fn funcCommon(...@@ -5550,7 +5560,6 @@ fn funcCommon(
5550 lib_name, @errorName(err),5560 lib_name, @errorName(err),
5551 });5561 });
5552 };5562 };
5553 const target = mod.getTarget();
5554 if (target_util.is_libc_lib_name(target, lib_name)) {5563 if (target_util.is_libc_lib_name(target, lib_name)) {
5555 if (!mod.comp.bin_file.options.link_libc) {5564 if (!mod.comp.bin_file.options.link_libc) {
5556 return sema.fail(5565 return sema.fail(
...@@ -5591,12 +5600,7 @@ fn funcCommon(...@@ -5591,12 +5600,7 @@ fn funcCommon(
5591 }5600 }
55925601
5593 if (body_inst == 0) {5602 if (body_inst == 0) {
5594 const fn_ptr_ty = try Type.ptr(sema.arena, .{5603 return sema.addType(fn_ty);
5595 .pointee_type = fn_ty,
5596 .@"addrspace" = .generic,
5597 .mutable = false,
5598 });
5599 return sema.addType(fn_ptr_ty);
5600 }5604 }
56015605
5602 const is_inline = fn_ty.fnCallingConvention() == .Inline;5606 const is_inline = fn_ty.fnCallingConvention() == .Inline;
...@@ -5632,7 +5636,7 @@ fn zirParam(...@@ -5632,7 +5636,7 @@ fn zirParam(
5632 sema: *Sema,5636 sema: *Sema,
5633 block: *Block,5637 block: *Block,
5634 inst: Zir.Inst.Index,5638 inst: Zir.Inst.Index,
5635 is_comptime: bool,5639 comptime_syntax: bool,
5636) CompileError!void {5640) CompileError!void {
5637 const inst_data = sema.code.instructions.items(.data)[inst].pl_tok;5641 const inst_data = sema.code.instructions.items(.data)[inst].pl_tok;
5638 const src = inst_data.src();5642 const src = inst_data.src();
...@@ -5669,7 +5673,7 @@ fn zirParam(...@@ -5669,7 +5673,7 @@ fn zirParam(
5669 // insert an anytype parameter.5673 // insert an anytype parameter.
5670 try block.params.append(sema.gpa, .{5674 try block.params.append(sema.gpa, .{
5671 .ty = Type.initTag(.generic_poison),5675 .ty = Type.initTag(.generic_poison),
5672 .is_comptime = is_comptime,5676 .is_comptime = comptime_syntax,
5673 });5677 });
5674 try sema.inst_map.putNoClobber(sema.gpa, inst, .generic_poison);5678 try sema.inst_map.putNoClobber(sema.gpa, inst, .generic_poison);
5675 return;5679 return;
...@@ -5677,8 +5681,10 @@ fn zirParam(...@@ -5677,8 +5681,10 @@ fn zirParam(
5677 else => |e| return e,5681 else => |e| return e,
5678 }5682 }
5679 };5683 };
5684 const is_comptime = comptime_syntax or
5685 try sema.typeRequiresComptime(block, src, param_ty);
5680 if (sema.inst_map.get(inst)) |arg| {5686 if (sema.inst_map.get(inst)) |arg| {
5681 if (is_comptime or param_ty.requiresComptime()) {5687 if (is_comptime) {
5682 // We have a comptime value for this parameter so it should be elided from the5688 // We have a comptime value for this parameter so it should be elided from the
5683 // function type of the function instruction in this block.5689 // function type of the function instruction in this block.
5684 const coerced_arg = try sema.coerce(block, param_ty, arg, src);5690 const coerced_arg = try sema.coerce(block, param_ty, arg, src);
...@@ -5692,7 +5698,7 @@ fn zirParam(...@@ -5692,7 +5698,7 @@ fn zirParam(
56925698
5693 try block.params.append(sema.gpa, .{5699 try block.params.append(sema.gpa, .{
5694 .ty = param_ty,5700 .ty = param_ty,
5695 .is_comptime = is_comptime or param_ty.requiresComptime(),5701 .is_comptime = is_comptime,
5696 });5702 });
5697 const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison));5703 const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison));
5698 try sema.inst_map.putNoClobber(sema.gpa, inst, result);5704 try sema.inst_map.putNoClobber(sema.gpa, inst, result);
...@@ -5702,9 +5708,10 @@ fn zirParamAnytype(...@@ -5702,9 +5708,10 @@ fn zirParamAnytype(
5702 sema: *Sema,5708 sema: *Sema,
5703 block: *Block,5709 block: *Block,
5704 inst: Zir.Inst.Index,5710 inst: Zir.Inst.Index,
5705 is_comptime: bool,5711 comptime_syntax: bool,
5706) CompileError!void {5712) CompileError!void {
5707 const inst_data = sema.code.instructions.items(.data)[inst].str_tok;5713 const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
5714 const src = inst_data.src();
5708 const param_name = inst_data.get(sema.code);5715 const param_name = inst_data.get(sema.code);
57095716
5710 // TODO check if param_name shadows a Decl. This only needs to be done if5717 // TODO check if param_name shadows a Decl. This only needs to be done if
...@@ -5713,7 +5720,7 @@ fn zirParamAnytype(...@@ -5713,7 +5720,7 @@ fn zirParamAnytype(
57135720
5714 if (sema.inst_map.get(inst)) |air_ref| {5721 if (sema.inst_map.get(inst)) |air_ref| {
5715 const param_ty = sema.typeOf(air_ref);5722 const param_ty = sema.typeOf(air_ref);
5716 if (is_comptime or param_ty.requiresComptime()) {5723 if (comptime_syntax or try sema.typeRequiresComptime(block, src, param_ty)) {
5717 // We have a comptime value for this parameter so it should be elided from the5724 // We have a comptime value for this parameter so it should be elided from the
5718 // function type of the function instruction in this block.5725 // function type of the function instruction in this block.
5719 return;5726 return;
...@@ -5730,7 +5737,7 @@ fn zirParamAnytype(...@@ -5730,7 +5737,7 @@ fn zirParamAnytype(
57305737
5731 try block.params.append(sema.gpa, .{5738 try block.params.append(sema.gpa, .{
5732 .ty = Type.initTag(.generic_poison),5739 .ty = Type.initTag(.generic_poison),
5733 .is_comptime = is_comptime,5740 .is_comptime = comptime_syntax,
5734 });5741 });
5735 try sema.inst_map.put(sema.gpa, inst, .generic_poison);5742 try sema.inst_map.put(sema.gpa, inst, .generic_poison);
5736}5743}
...@@ -11118,8 +11125,7 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -11118,8 +11125,7 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1111811125
11119 const type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };11126 const type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
11120 const type_res = try sema.resolveType(block, src, extra.lhs);11127 const type_res = try sema.resolveType(block, src, extra.lhs);
11121 if (type_res.zigTypeTag() != .Pointer)11128 try sema.checkPtrType(block, type_src, type_res);
11122 return sema.fail(block, type_src, "expected pointer, found '{}'", .{type_res});
11123 const ptr_align = type_res.ptrAlignment(sema.mod.getTarget());11129 const ptr_align = type_res.ptrAlignment(sema.mod.getTarget());
1112411130
11125 if (try sema.resolveDefinedValue(block, operand_src, operand_coerced)) |val| {11131 if (try sema.resolveDefinedValue(block, operand_src, operand_coerced)) |val| {
...@@ -11176,16 +11182,8 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -11176,16 +11182,8 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
11176 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);11182 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
11177 const operand = sema.resolveInst(extra.rhs);11183 const operand = sema.resolveInst(extra.rhs);
11178 const operand_ty = sema.typeOf(operand);11184 const operand_ty = sema.typeOf(operand);
11179 if (operand_ty.zigTypeTag() != .Pointer) {11185 try sema.checkPtrType(block, dest_ty_src, dest_ty);
11180 return sema.fail(block, operand_src, "expected pointer, found {s} type '{}'", .{11186 try sema.checkPtrOperand(block, operand_src, operand_ty);
11181 @tagName(operand_ty.zigTypeTag()), operand_ty,
11182 });
11183 }
11184 if (dest_ty.zigTypeTag() != .Pointer) {
11185 return sema.fail(block, dest_ty_src, "expected pointer, found {s} type '{}'", .{
11186 @tagName(dest_ty.zigTypeTag()), dest_ty,
11187 });
11188 }
11189 return sema.coerceCompatiblePtrs(block, dest_ty, operand, operand_src);11187 return sema.coerceCompatiblePtrs(block, dest_ty, operand, operand_src);
11190}11188}
1119111189
...@@ -11264,7 +11262,7 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -11264,7 +11262,7 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1126411262
11265 // TODO in addition to pointers, this instruction is supposed to work for11263 // TODO in addition to pointers, this instruction is supposed to work for
11266 // pointer-like optionals and slices.11264 // pointer-like optionals and slices.
11267 try sema.checkPtrType(block, ptr_src, ptr_ty);11265 try sema.checkPtrOperand(block, ptr_src, ptr_ty);
1126811266
11269 // TODO compile error if the result pointer is comptime known and would have an11267 // TODO compile error if the result pointer is comptime known and would have an
11270 // alignment that disagrees with the Decl's alignment.11268 // alignment that disagrees with the Decl's alignment.
...@@ -11462,6 +11460,34 @@ fn checkIntType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileEr...@@ -11462,6 +11460,34 @@ fn checkIntType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileEr
11462 }11460 }
11463}11461}
1146411462
11463fn checkPtrOperand(
11464 sema: *Sema,
11465 block: *Block,
11466 ty_src: LazySrcLoc,
11467 ty: Type,
11468) CompileError!void {
11469 switch (ty.zigTypeTag()) {
11470 .Pointer => {},
11471 .Fn => {
11472 const msg = msg: {
11473 const msg = try sema.errMsg(
11474 block,
11475 ty_src,
11476 "expected pointer, found {}",
11477 .{ty},
11478 );
11479 errdefer msg.destroy(sema.gpa);
11480
11481 try sema.errNote(block, ty_src, msg, "use '&' to obtain a function pointer", .{});
11482
11483 break :msg msg;
11484 };
11485 return sema.failWithOwnedErrorMsg(msg);
11486 },
11487 else => return sema.fail(block, ty_src, "expected pointer, found '{}'", .{ty}),
11488 }
11489}
11490
11465fn checkPtrType(11491fn checkPtrType(
11466 sema: *Sema,11492 sema: *Sema,
11467 block: *Block,11493 block: *Block,
...@@ -11470,6 +11496,22 @@ fn checkPtrType(...@@ -11470,6 +11496,22 @@ fn checkPtrType(
11470) CompileError!void {11496) CompileError!void {
11471 switch (ty.zigTypeTag()) {11497 switch (ty.zigTypeTag()) {
11472 .Pointer => {},11498 .Pointer => {},
11499 .Fn => {
11500 const msg = msg: {
11501 const msg = try sema.errMsg(
11502 block,
11503 ty_src,
11504 "expected pointer type, found '{}'",
11505 .{ty},
11506 );
11507 errdefer msg.destroy(sema.gpa);
11508
11509 try sema.errNote(block, ty_src, msg, "use '*const ' to make a function pointer type", .{});
11510
11511 break :msg msg;
11512 };
11513 return sema.failWithOwnedErrorMsg(msg);
11514 },
11473 else => return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty}),11515 else => return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty}),
11474 }11516 }
11475}11517}
...@@ -12139,20 +12181,14 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void...@@ -12139,20 +12181,14 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
12139 const dest_ptr = sema.resolveInst(extra.dest);12181 const dest_ptr = sema.resolveInst(extra.dest);
12140 const dest_ptr_ty = sema.typeOf(dest_ptr);12182 const dest_ptr_ty = sema.typeOf(dest_ptr);
1214112183
12142 if (dest_ptr_ty.zigTypeTag() != .Pointer) {12184 try sema.checkPtrOperand(block, dest_src, dest_ptr_ty);
12143 return sema.fail(block, dest_src, "expected pointer, found '{}'", .{dest_ptr_ty});
12144 }
12145 if (dest_ptr_ty.isConstPtr()) {12185 if (dest_ptr_ty.isConstPtr()) {
12146 return sema.fail(block, dest_src, "cannot store through const pointer '{}'", .{dest_ptr_ty});12186 return sema.fail(block, dest_src, "cannot store through const pointer '{}'", .{dest_ptr_ty});
12147 }12187 }
1214812188
12149 const uncasted_src_ptr = sema.resolveInst(extra.source);12189 const uncasted_src_ptr = sema.resolveInst(extra.source);
12150 const uncasted_src_ptr_ty = sema.typeOf(uncasted_src_ptr);12190 const uncasted_src_ptr_ty = sema.typeOf(uncasted_src_ptr);
12151 if (uncasted_src_ptr_ty.zigTypeTag() != .Pointer) {12191 try sema.checkPtrOperand(block, src_src, uncasted_src_ptr_ty);
12152 return sema.fail(block, src_src, "expected pointer, found '{}'", .{
12153 uncasted_src_ptr_ty,
12154 });
12155 }
12156 const src_ptr_info = uncasted_src_ptr_ty.ptrInfo().data;12192 const src_ptr_info = uncasted_src_ptr_ty.ptrInfo().data;
12157 const wanted_src_ptr_ty = try Type.ptr(sema.arena, .{12193 const wanted_src_ptr_ty = try Type.ptr(sema.arena, .{
12158 .pointee_type = dest_ptr_ty.elemType2(),12194 .pointee_type = dest_ptr_ty.elemType2(),
...@@ -12203,9 +12239,7 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void...@@ -12203,9 +12239,7 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
12203 const len_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };12239 const len_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
12204 const dest_ptr = sema.resolveInst(extra.dest);12240 const dest_ptr = sema.resolveInst(extra.dest);
12205 const dest_ptr_ty = sema.typeOf(dest_ptr);12241 const dest_ptr_ty = sema.typeOf(dest_ptr);
12206 if (dest_ptr_ty.zigTypeTag() != .Pointer) {12242 try sema.checkPtrOperand(block, dest_src, dest_ptr_ty);
12207 return sema.fail(block, dest_src, "expected pointer, found '{}'", .{dest_ptr_ty});
12208 }
12209 if (dest_ptr_ty.isConstPtr()) {12243 if (dest_ptr_ty.isConstPtr()) {
12210 return sema.fail(block, dest_src, "cannot store through const pointer '{}'", .{dest_ptr_ty});12244 return sema.fail(block, dest_src, "cannot store through const pointer '{}'", .{dest_ptr_ty});
12211 }12245 }
...@@ -12487,7 +12521,7 @@ fn zirPrefetch(...@@ -12487,7 +12521,7 @@ fn zirPrefetch(
12487 const opts_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };12521 const opts_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
12488 const options_ty = try sema.getBuiltinType(block, opts_src, "PrefetchOptions");12522 const options_ty = try sema.getBuiltinType(block, opts_src, "PrefetchOptions");
12489 const ptr = sema.resolveInst(extra.lhs);12523 const ptr = sema.resolveInst(extra.lhs);
12490 try sema.checkPtrType(block, ptr_src, sema.typeOf(ptr));12524 try sema.checkPtrOperand(block, ptr_src, sema.typeOf(ptr));
12491 const options = try sema.coerce(block, options_ty, sema.resolveInst(extra.rhs), opts_src);12525 const options = try sema.coerce(block, options_ty, sema.resolveInst(extra.rhs), opts_src);
1249212526
12493 const rw = try sema.fieldVal(block, opts_src, options, "rw", opts_src);12527 const rw = try sema.fieldVal(block, opts_src, options, "rw", opts_src);
...@@ -12568,12 +12602,15 @@ fn validateVarType(...@@ -12568,12 +12602,15 @@ fn validateVarType(
12568 .Type,12602 .Type,
12569 .Undefined,12603 .Undefined,
12570 .Null,12604 .Null,
12605 .Fn,
12571 => break,12606 => break,
1257212607
12573 .Pointer => {12608 .Pointer => {
12574 const elem_ty = ty.childType();12609 const elem_ty = ty.childType();
12575 if (elem_ty.zigTypeTag() == .Opaque) return;12610 switch (elem_ty.zigTypeTag()) {
12576 ty = elem_ty;12611 .Opaque, .Fn => return,
12612 else => ty = elem_ty,
12613 }
12577 },12614 },
12578 .Opaque => if (is_extern) return else break,12615 .Opaque => if (is_extern) return else break,
1257912616
...@@ -12586,9 +12623,9 @@ fn validateVarType(...@@ -12586,9 +12623,9 @@ fn validateVarType(
1258612623
12587 .ErrorUnion => ty = ty.errorUnionPayload(),12624 .ErrorUnion => ty = ty.errorUnionPayload(),
1258812625
12589 .Fn, .Struct, .Union => {12626 .Struct, .Union => {
12590 const resolved_ty = try sema.resolveTypeFields(block, src, ty);12627 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
12591 if (resolved_ty.requiresComptime()) {12628 if (try sema.typeRequiresComptime(block, src, resolved_ty)) {
12592 break;12629 break;
12593 } else {12630 } else {
12594 return;12631 return;
...@@ -12596,7 +12633,99 @@ fn validateVarType(...@@ -12596,7 +12633,99 @@ fn validateVarType(
12596 },12633 },
12597 } else unreachable; // TODO should not need else unreachable12634 } else unreachable; // TODO should not need else unreachable
1259812635
12599 return sema.fail(block, src, "variable of type '{}' must be const or comptime", .{var_ty});12636 const msg = msg: {
12637 const msg = try sema.errMsg(block, src, "variable of type '{}' must be const or comptime", .{var_ty});
12638 errdefer msg.destroy(sema.gpa);
12639
12640 try sema.explainWhyTypeIsComptime(block, src, msg, src.toSrcLoc(block.src_decl), var_ty);
12641
12642 break :msg msg;
12643 };
12644 return sema.failWithOwnedErrorMsg(msg);
12645}
12646
12647fn explainWhyTypeIsComptime(
12648 sema: *Sema,
12649 block: *Block,
12650 src: LazySrcLoc,
12651 msg: *Module.ErrorMsg,
12652 src_loc: Module.SrcLoc,
12653 ty: Type,
12654) CompileError!void {
12655 const mod = sema.mod;
12656 switch (ty.zigTypeTag()) {
12657 .Bool,
12658 .Int,
12659 .Float,
12660 .ErrorSet,
12661 .Enum,
12662 .Frame,
12663 .AnyFrame,
12664 .Void,
12665 => return,
12666
12667 .Fn => {
12668 try mod.errNoteNonLazy(src_loc, msg, "use '*const {}' for a function pointer type", .{
12669 ty,
12670 });
12671 },
12672
12673 .Type => {
12674 try mod.errNoteNonLazy(src_loc, msg, "types are not available at runtime", .{});
12675 },
12676
12677 .BoundFn,
12678 .ComptimeFloat,
12679 .ComptimeInt,
12680 .EnumLiteral,
12681 .NoReturn,
12682 .Undefined,
12683 .Null,
12684 .Opaque,
12685 .Optional,
12686 => return,
12687
12688 .Pointer, .Array, .Vector => {
12689 try sema.explainWhyTypeIsComptime(block, src, msg, src_loc, ty.elemType());
12690 },
12691
12692 .ErrorUnion => {
12693 try sema.explainWhyTypeIsComptime(block, src, msg, src_loc, ty.errorUnionPayload());
12694 },
12695
12696 .Struct => {
12697 if (ty.castTag(.@"struct")) |payload| {
12698 const struct_obj = payload.data;
12699 for (struct_obj.fields.values()) |field, i| {
12700 const field_src_loc = struct_obj.fieldSrcLoc(sema.gpa, .{
12701 .index = i,
12702 .range = .type,
12703 });
12704 if (try sema.typeRequiresComptime(block, src, field.ty)) {
12705 try mod.errNoteNonLazy(field_src_loc, msg, "struct requires comptime because of this field", .{});
12706 try sema.explainWhyTypeIsComptime(block, src, msg, field_src_loc, field.ty);
12707 }
12708 }
12709 }
12710 // TODO tuples
12711 },
12712
12713 .Union => {
12714 if (ty.cast(Type.Payload.Union)) |payload| {
12715 const union_obj = payload.data;
12716 for (union_obj.fields.values()) |field, i| {
12717 const field_src_loc = union_obj.fieldSrcLoc(sema.gpa, .{
12718 .index = i,
12719 .range = .type,
12720 });
12721 if (try sema.typeRequiresComptime(block, src, field.ty)) {
12722 try mod.errNoteNonLazy(field_src_loc, msg, "union requires comptime because of this field", .{});
12723 try sema.explainWhyTypeIsComptime(block, src, msg, field_src_loc, field.ty);
12724 }
12725 }
12726 }
12727 },
12728 }
12600}12729}
1260112730
12602pub const PanicId = enum {12731pub const PanicId = enum {
...@@ -13883,6 +14012,10 @@ fn coerce(...@@ -13883,6 +14012,10 @@ fn coerce(
13883 {14012 {
13884 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);14013 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
13885 }14014 }
14015
14016 // This will give an extra hint on top of what the bottom of this func would provide.
14017 try sema.checkPtrOperand(block, dest_ty_src, inst_ty);
14018 unreachable;
13886 },14019 },
13887 .Int, .ComptimeInt => switch (inst_ty.zigTypeTag()) {14020 .Int, .ComptimeInt => switch (inst_ty.zigTypeTag()) {
13888 .Float, .ComptimeFloat => float: {14021 .Float, .ComptimeFloat => float: {
...@@ -14683,7 +14816,8 @@ const ComptimePtrLoadKit = struct {...@@ -14683,7 +14816,8 @@ const ComptimePtrLoadKit = struct {
14683 /// The Type of the parent Value.14816 /// The Type of the parent Value.
14684 ty: Type,14817 ty: Type,
14685 /// The starting byte offset of `val` from `root_val`.14818 /// The starting byte offset of `val` from `root_val`.
14686 byte_offset: usize,14819 /// If the type does not have a well-defined memory layout, this is null.
14820 byte_offset: ?usize,
14687 /// Whether the `root_val` could be mutated by further14821 /// Whether the `root_val` could be mutated by further
14688 /// semantic analysis and a copy must be performed.14822 /// semantic analysis and a copy must be performed.
14689 is_mutable: bool,14823 is_mutable: bool,
...@@ -14738,12 +14872,24 @@ fn beginComptimePtrLoad(...@@ -14738,12 +14872,24 @@ fn beginComptimePtrLoad(
14738 });14872 });
14739 }14873 }
14740 const elem_ty = parent.ty.childType();14874 const elem_ty = parent.ty.childType();
14741 const elem_size = elem_ty.abiSize(target);14875 const byte_offset: ?usize = bo: {
14876 if (try sema.typeRequiresComptime(block, src, elem_ty)) {
14877 break :bo null;
14878 } else {
14879 if (parent.byte_offset) |off| {
14880 try sema.resolveTypeLayout(block, src, elem_ty);
14881 const elem_size = elem_ty.abiSize(target);
14882 break :bo try sema.usizeCast(block, src, off + elem_size * elem_ptr.index);
14883 } else {
14884 break :bo null;
14885 }
14886 }
14887 };
14742 return ComptimePtrLoadKit{14888 return ComptimePtrLoadKit{
14743 .root_val = parent.root_val,14889 .root_val = parent.root_val,
14744 .val = try parent.val.elemValue(sema.arena, elem_ptr.index),14890 .val = try parent.val.elemValue(sema.arena, elem_ptr.index),
14745 .ty = elem_ty,14891 .ty = elem_ty,
14746 .byte_offset = try sema.usizeCast(block, src, parent.byte_offset + elem_size * elem_ptr.index),14892 .byte_offset = byte_offset,
14747 .is_mutable = parent.is_mutable,14893 .is_mutable = parent.is_mutable,
14748 };14894 };
14749 },14895 },
...@@ -14768,13 +14914,24 @@ fn beginComptimePtrLoad(...@@ -14768,13 +14914,24 @@ fn beginComptimePtrLoad(
14768 const field_ptr = ptr_val.castTag(.field_ptr).?.data;14914 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
14769 const parent = try beginComptimePtrLoad(sema, block, src, field_ptr.container_ptr);14915 const parent = try beginComptimePtrLoad(sema, block, src, field_ptr.container_ptr);
14770 const field_index = @intCast(u32, field_ptr.field_index);14916 const field_index = @intCast(u32, field_ptr.field_index);
14771 try sema.resolveTypeLayout(block, src, parent.ty);14917 const byte_offset: ?usize = bo: {
14772 const field_offset = parent.ty.structFieldOffset(field_index, target);14918 if (try sema.typeRequiresComptime(block, src, parent.ty)) {
14919 break :bo null;
14920 } else {
14921 if (parent.byte_offset) |off| {
14922 try sema.resolveTypeLayout(block, src, parent.ty);
14923 const field_offset = parent.ty.structFieldOffset(field_index, target);
14924 break :bo try sema.usizeCast(block, src, off + field_offset);
14925 } else {
14926 break :bo null;
14927 }
14928 }
14929 };
14773 return ComptimePtrLoadKit{14930 return ComptimePtrLoadKit{
14774 .root_val = parent.root_val,14931 .root_val = parent.root_val,
14775 .val = try parent.val.fieldValue(sema.arena, field_index),14932 .val = try parent.val.fieldValue(sema.arena, field_index),
14776 .ty = parent.ty.structFieldType(field_index),14933 .ty = parent.ty.structFieldType(field_index),
14777 .byte_offset = try sema.usizeCast(block, src, parent.byte_offset + field_offset),14934 .byte_offset = byte_offset,
14778 .is_mutable = parent.is_mutable,14935 .is_mutable = parent.is_mutable,
14779 };14936 };
14780 },14937 },
...@@ -14785,7 +14942,7 @@ fn beginComptimePtrLoad(...@@ -14785,7 +14942,7 @@ fn beginComptimePtrLoad(
14785 .root_val = parent.root_val,14942 .root_val = parent.root_val,
14786 .val = parent.val.castTag(.eu_payload).?.data,14943 .val = parent.val.castTag(.eu_payload).?.data,
14787 .ty = parent.ty.errorUnionPayload(),14944 .ty = parent.ty.errorUnionPayload(),
14788 .byte_offset = undefined,14945 .byte_offset = null,
14789 .is_mutable = parent.is_mutable,14946 .is_mutable = parent.is_mutable,
14790 };14947 };
14791 },14948 },
...@@ -14796,7 +14953,7 @@ fn beginComptimePtrLoad(...@@ -14796,7 +14953,7 @@ fn beginComptimePtrLoad(
14796 .root_val = parent.root_val,14953 .root_val = parent.root_val,
14797 .val = parent.val.castTag(.opt_payload).?.data,14954 .val = parent.val.castTag(.opt_payload).?.data,
14798 .ty = try parent.ty.optionalChildAlloc(sema.arena),14955 .ty = try parent.ty.optionalChildAlloc(sema.arena),
14799 .byte_offset = undefined,14956 .byte_offset = null,
14800 .is_mutable = parent.is_mutable,14957 .is_mutable = parent.is_mutable,
14801 };14958 };
14802 },14959 },
...@@ -16090,28 +16247,12 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp...@@ -16090,28 +16247,12 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp
16090 switch (ty.tag()) {16247 switch (ty.tag()) {
16091 .@"struct" => {16248 .@"struct" => {
16092 const struct_obj = ty.castTag(.@"struct").?.data;16249 const struct_obj = ty.castTag(.@"struct").?.data;
16093 switch (struct_obj.status) {16250 try sema.resolveTypeFieldsStruct(block, src, ty, struct_obj);
16094 .none => {},16251 return ty;
16095 .field_types_wip => {16252 },
16096 return sema.fail(block, src, "struct {} depends on itself", .{ty});16253 .@"union", .union_tagged => {
16097 },16254 const union_obj = ty.cast(Type.Payload.Union).?.data;
16098 .have_field_types,16255 try sema.resolveTypeFieldsUnion(block, src, ty, union_obj);
16099 .have_layout,
16100 .layout_wip,
16101 .fully_resolved_wip,
16102 .fully_resolved,
16103 => return ty,
16104 }
16105
16106 struct_obj.status = .field_types_wip;
16107 try semaStructFields(sema.mod, struct_obj);
16108
16109 if (struct_obj.fields.count() == 0) {
16110 struct_obj.status = .have_layout;
16111 } else {
16112 struct_obj.status = .have_field_types;
16113 }
16114
16115 return ty;16256 return ty;
16116 },16257 },
16117 .type_info => return sema.resolveBuiltinTypeFields(block, src, "TypeInfo"),16258 .type_info => return sema.resolveBuiltinTypeFields(block, src, "TypeInfo"),
...@@ -16126,29 +16267,63 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp...@@ -16126,29 +16267,63 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp
16126 .call_options => return sema.resolveBuiltinTypeFields(block, src, "CallOptions"),16267 .call_options => return sema.resolveBuiltinTypeFields(block, src, "CallOptions"),
16127 .prefetch_options => return sema.resolveBuiltinTypeFields(block, src, "PrefetchOptions"),16268 .prefetch_options => return sema.resolveBuiltinTypeFields(block, src, "PrefetchOptions"),
1612816269
16129 .@"union", .union_tagged => {16270 else => return ty,
16130 const union_obj = ty.cast(Type.Payload.Union).?.data;16271 }
16131 switch (union_obj.status) {16272}
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 }
1614316273
16144 union_obj.status = .field_types_wip;16274fn resolveTypeFieldsStruct(
16145 try semaUnionFields(sema.mod, union_obj);16275 sema: *Sema,
16146 union_obj.status = .have_field_types;16276 block: *Block,
16277 src: LazySrcLoc,
16278 ty: Type,
16279 struct_obj: *Module.Struct,
16280) CompileError!void {
16281 switch (struct_obj.status) {
16282 .none => {},
16283 .field_types_wip => {
16284 return sema.fail(block, src, "struct {} depends on itself", .{ty});
16285 },
16286 .have_field_types,
16287 .have_layout,
16288 .layout_wip,
16289 .fully_resolved_wip,
16290 .fully_resolved,
16291 => return,
16292 }
1614716293
16148 return ty;16294 struct_obj.status = .field_types_wip;
16295 try semaStructFields(sema.mod, struct_obj);
16296
16297 if (struct_obj.fields.count() == 0) {
16298 struct_obj.status = .have_layout;
16299 } else {
16300 struct_obj.status = .have_field_types;
16301 }
16302}
16303
16304fn resolveTypeFieldsUnion(
16305 sema: *Sema,
16306 block: *Block,
16307 src: LazySrcLoc,
16308 ty: Type,
16309 union_obj: *Module.Union,
16310) CompileError!void {
16311 switch (union_obj.status) {
16312 .none => {},
16313 .field_types_wip => {
16314 return sema.fail(block, src, "union {} depends on itself", .{ty});
16149 },16315 },
16150 else => return ty,16316 .have_field_types,
16317 .have_layout,
16318 .layout_wip,
16319 .fully_resolved_wip,
16320 .fully_resolved,
16321 => return,
16151 }16322 }
16323
16324 union_obj.status = .field_types_wip;
16325 try semaUnionFields(sema.mod, union_obj);
16326 union_obj.status = .have_field_types;
16152}16327}
1615316328
16154fn resolveBuiltinTypeFields(16329fn resolveBuiltinTypeFields(
...@@ -17295,3 +17470,198 @@ fn typePtrOrOptionalPtrTy(...@@ -17295,3 +17470,198 @@ fn typePtrOrOptionalPtrTy(
17295 else => return null,17470 else => return null,
17296 }17471 }
17297}17472}
17473
17474/// Anything that reports hasCodeGenBits() false returns false here as well.
17475/// `generic_poison` will return false.
17476/// This function returns false negatives when structs and unions are having their
17477/// field types resolved.
17478fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
17479 return switch (ty.tag()) {
17480 .u1,
17481 .u8,
17482 .i8,
17483 .u16,
17484 .i16,
17485 .u32,
17486 .i32,
17487 .u64,
17488 .i64,
17489 .u128,
17490 .i128,
17491 .usize,
17492 .isize,
17493 .c_short,
17494 .c_ushort,
17495 .c_int,
17496 .c_uint,
17497 .c_long,
17498 .c_ulong,
17499 .c_longlong,
17500 .c_ulonglong,
17501 .c_longdouble,
17502 .f16,
17503 .f32,
17504 .f64,
17505 .f128,
17506 .anyopaque,
17507 .bool,
17508 .void,
17509 .anyerror,
17510 .noreturn,
17511 .@"anyframe",
17512 .@"null",
17513 .@"undefined",
17514 .atomic_order,
17515 .atomic_rmw_op,
17516 .calling_convention,
17517 .address_space,
17518 .float_mode,
17519 .reduce_op,
17520 .call_options,
17521 .prefetch_options,
17522 .export_options,
17523 .extern_options,
17524 .manyptr_u8,
17525 .manyptr_const_u8,
17526 .manyptr_const_u8_sentinel_0,
17527 .const_slice_u8,
17528 .const_slice_u8_sentinel_0,
17529 .anyerror_void_error_union,
17530 .empty_struct_literal,
17531 .empty_struct,
17532 .error_set,
17533 .error_set_single,
17534 .error_set_inferred,
17535 .error_set_merged,
17536 .@"opaque",
17537 .generic_poison,
17538 .array_u8,
17539 .array_u8_sentinel_0,
17540 .int_signed,
17541 .int_unsigned,
17542 .enum_simple,
17543 => false,
17544
17545 .single_const_pointer_to_comptime_int,
17546 .type,
17547 .comptime_int,
17548 .comptime_float,
17549 .enum_literal,
17550 .type_info,
17551 // These are function bodies, not function pointers.
17552 .fn_noreturn_no_args,
17553 .fn_void_no_args,
17554 .fn_naked_noreturn_no_args,
17555 .fn_ccc_void_no_args,
17556 .function,
17557 => true,
17558
17559 .var_args_param => unreachable,
17560 .inferred_alloc_mut => unreachable,
17561 .inferred_alloc_const => unreachable,
17562 .bound_fn => unreachable,
17563
17564 .array,
17565 .array_sentinel,
17566 .vector,
17567 => return sema.typeRequiresComptime(block, src, ty.childType()),
17568
17569 .pointer,
17570 .single_const_pointer,
17571 .single_mut_pointer,
17572 .many_const_pointer,
17573 .many_mut_pointer,
17574 .c_const_pointer,
17575 .c_mut_pointer,
17576 .const_slice,
17577 .mut_slice,
17578 => {
17579 const child_ty = ty.childType();
17580 if (child_ty.zigTypeTag() == .Fn) {
17581 return false;
17582 } else {
17583 return sema.typeRequiresComptime(block, src, child_ty);
17584 }
17585 },
17586
17587 .optional,
17588 .optional_single_mut_pointer,
17589 .optional_single_const_pointer,
17590 => {
17591 var buf: Type.Payload.ElemType = undefined;
17592 return sema.typeRequiresComptime(block, src, ty.optionalChild(&buf));
17593 },
17594
17595 .tuple => {
17596 const tuple = ty.castTag(.tuple).?.data;
17597 for (tuple.types) |field_ty| {
17598 if (try sema.typeRequiresComptime(block, src, field_ty)) {
17599 return true;
17600 }
17601 }
17602 return false;
17603 },
17604
17605 .@"struct" => {
17606 const struct_obj = ty.castTag(.@"struct").?.data;
17607 switch (struct_obj.requires_comptime) {
17608 .no, .wip => return false,
17609 .yes => return true,
17610 .unknown => {
17611 if (struct_obj.status == .field_types_wip)
17612 return false;
17613
17614 try sema.resolveTypeFieldsStruct(block, src, ty, struct_obj);
17615
17616 struct_obj.requires_comptime = .wip;
17617 for (struct_obj.fields.values()) |field| {
17618 if (try sema.typeRequiresComptime(block, src, field.ty)) {
17619 struct_obj.requires_comptime = .yes;
17620 return true;
17621 }
17622 }
17623 struct_obj.requires_comptime = .no;
17624 return false;
17625 },
17626 }
17627 },
17628
17629 .@"union", .union_tagged => {
17630 const union_obj = ty.cast(Type.Payload.Union).?.data;
17631 switch (union_obj.requires_comptime) {
17632 .no, .wip => return false,
17633 .yes => return true,
17634 .unknown => {
17635 if (union_obj.status == .field_types_wip)
17636 return false;
17637
17638 try sema.resolveTypeFieldsUnion(block, src, ty, union_obj);
17639
17640 union_obj.requires_comptime = .wip;
17641 for (union_obj.fields.values()) |field| {
17642 if (try sema.typeRequiresComptime(block, src, field.ty)) {
17643 union_obj.requires_comptime = .yes;
17644 return true;
17645 }
17646 }
17647 union_obj.requires_comptime = .no;
17648 return false;
17649 },
17650 }
17651 },
17652
17653 .error_union => return sema.typeRequiresComptime(block, src, ty.errorUnionPayload()),
17654 .anyframe_T => {
17655 const child_ty = ty.castTag(.anyframe_T).?.data;
17656 return sema.typeRequiresComptime(block, src, child_ty);
17657 },
17658 .enum_numbered => {
17659 const tag_ty = ty.castTag(.enum_numbered).?.data.tag_ty;
17660 return sema.typeRequiresComptime(block, src, tag_ty);
17661 },
17662 .enum_full, .enum_nonexhaustive => {
17663 const tag_ty = ty.cast(Type.Payload.EnumFull).?.data.tag_ty;
17664 return sema.typeRequiresComptime(block, src, tag_ty);
17665 },
17666 };
17667}
src/codegen/llvm.zig+4
...@@ -725,6 +725,10 @@ pub const DeclGen = struct {...@@ -725,6 +725,10 @@ pub const DeclGen = struct {
725 llvm_fn.setFunctionCallConv(toLlvmCallConv(fn_info.cc, target));725 llvm_fn.setFunctionCallConv(toLlvmCallConv(fn_info.cc, target));
726 }726 }
727727
728 if (fn_info.alignment != 0) {
729 llvm_fn.setAlignment(fn_info.alignment);
730 }
731
728 // Function attributes that are independent of analysis results of the function body.732 // Function attributes that are independent of analysis results of the function body.
729 dg.addCommonFnAttributes(llvm_fn);733 dg.addCommonFnAttributes(llvm_fn);
730734
src/target.zig+9
...@@ -637,3 +637,12 @@ pub fn llvmMachineAbi(target: std.Target) ?[:0]const u8 {...@@ -637,3 +637,12 @@ pub fn llvmMachineAbi(target: std.Target) ?[:0]const u8 {
637 else => return null,637 else => return null,
638 }638 }
639}639}
640
641pub fn defaultFunctionAlignment(target: std.Target) u32 {
642 return switch (target.cpu.arch) {
643 .arm, .armeb => 4,
644 .aarch64, .aarch64_32, .aarch64_be => 4,
645 .riscv64 => 2,
646 else => 1,
647 };
648}
src/type.zig+48-181
...@@ -5,6 +5,7 @@ const Allocator = std.mem.Allocator;...@@ -5,6 +5,7 @@ const Allocator = std.mem.Allocator;
5const Target = std.Target;5const Target = std.Target;
6const Module = @import("Module.zig");6const Module = @import("Module.zig");
7const log = std.log.scoped(.Type);7const log = std.log.scoped(.Type);
8const target_util = @import("target.zig");
89
9const file_struct = @This();10const file_struct = @This();
1011
...@@ -577,21 +578,36 @@ pub const Type = extern union {...@@ -577,21 +578,36 @@ pub const Type = extern union {
577 }578 }
578 },579 },
579 .Fn => {580 .Fn => {
580 if (!a.fnReturnType().eql(b.fnReturnType()))581 const a_info = a.fnInfo();
582 const b_info = b.fnInfo();
583
584 if (!eql(a_info.return_type, b_info.return_type))
581 return false;585 return false;
582 if (a.fnCallingConvention() != b.fnCallingConvention())586
587 if (a_info.cc != b_info.cc)
583 return false;588 return false;
584 const a_param_len = a.fnParamLen();589
585 const b_param_len = b.fnParamLen();590 if (a_info.param_types.len != b_info.param_types.len)
586 if (a_param_len != b_param_len)
587 return false;591 return false;
588 var i: usize = 0;592
589 while (i < a_param_len) : (i += 1) {593 for (a_info.param_types) |a_param_ty, i| {
590 if (!a.fnParamType(i).eql(b.fnParamType(i)))594 const b_param_ty = b_info.param_types[i];
595 if (!eql(a_param_ty, b_param_ty))
596 return false;
597
598 if (a_info.comptime_params[i] != b_info.comptime_params[i])
591 return false;599 return false;
592 }600 }
593 if (a.fnIsVarArgs() != b.fnIsVarArgs())601
602 if (a_info.alignment != b_info.alignment)
603 return false;
604
605 if (a_info.is_var_args != b_info.is_var_args)
594 return false;606 return false;
607
608 if (a_info.is_generic != b_info.is_generic)
609 return false;
610
595 return true;611 return true;
596 },612 },
597 .Optional => {613 .Optional => {
...@@ -686,6 +702,7 @@ pub const Type = extern union {...@@ -686,6 +702,7 @@ pub const Type = extern union {
686 return false;702 return false;
687 },703 },
688 .Float => return a.tag() == b.tag(),704 .Float => return a.tag() == b.tag(),
705
689 .BoundFn,706 .BoundFn,
690 .Frame,707 .Frame,
691 => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }),708 => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }),
...@@ -937,6 +954,7 @@ pub const Type = extern union {...@@ -937,6 +954,7 @@ pub const Type = extern union {
937 .return_type = try payload.return_type.copy(allocator),954 .return_type = try payload.return_type.copy(allocator),
938 .param_types = param_types,955 .param_types = param_types,
939 .cc = payload.cc,956 .cc = payload.cc,
957 .alignment = payload.alignment,
940 .is_var_args = payload.is_var_args,958 .is_var_args = payload.is_var_args,
941 .is_generic = payload.is_generic,959 .is_generic = payload.is_generic,
942 .comptime_params = comptime_params.ptr,960 .comptime_params = comptime_params.ptr,
...@@ -1114,9 +1132,15 @@ pub const Type = extern union {...@@ -1114,9 +1132,15 @@ pub const Type = extern union {
1114 }1132 }
1115 try writer.writeAll("...");1133 try writer.writeAll("...");
1116 }1134 }
1117 try writer.writeAll(") callconv(.");
1118 try writer.writeAll(@tagName(payload.cc));
1119 try writer.writeAll(") ");1135 try writer.writeAll(") ");
1136 if (payload.cc != .Unspecified) {
1137 try writer.writeAll("callconv(.");
1138 try writer.writeAll(@tagName(payload.cc));
1139 try writer.writeAll(") ");
1140 }
1141 if (payload.alignment != 0) {
1142 try writer.print("align({d}) ", .{payload.alignment});
1143 }
1120 ty = payload.return_type;1144 ty = payload.return_type;
1121 continue;1145 continue;
1122 },1146 },
...@@ -1423,170 +1447,6 @@ pub const Type = extern union {...@@ -1423,170 +1447,6 @@ pub const Type = extern union {
1423 }1447 }
1424 }1448 }
14251449
1426 /// Anything that reports hasCodeGenBits() false returns false here as well.
1427 /// `generic_poison` will return false.
1428 pub fn requiresComptime(ty: Type) bool {
1429 return switch (ty.tag()) {
1430 .u1,
1431 .u8,
1432 .i8,
1433 .u16,
1434 .i16,
1435 .u32,
1436 .i32,
1437 .u64,
1438 .i64,
1439 .u128,
1440 .i128,
1441 .usize,
1442 .isize,
1443 .c_short,
1444 .c_ushort,
1445 .c_int,
1446 .c_uint,
1447 .c_long,
1448 .c_ulong,
1449 .c_longlong,
1450 .c_ulonglong,
1451 .c_longdouble,
1452 .f16,
1453 .f32,
1454 .f64,
1455 .f128,
1456 .anyopaque,
1457 .bool,
1458 .void,
1459 .anyerror,
1460 .noreturn,
1461 .@"anyframe",
1462 .@"null",
1463 .@"undefined",
1464 .atomic_order,
1465 .atomic_rmw_op,
1466 .calling_convention,
1467 .address_space,
1468 .float_mode,
1469 .reduce_op,
1470 .call_options,
1471 .prefetch_options,
1472 .export_options,
1473 .extern_options,
1474 .manyptr_u8,
1475 .manyptr_const_u8,
1476 .manyptr_const_u8_sentinel_0,
1477 .fn_noreturn_no_args,
1478 .fn_void_no_args,
1479 .fn_naked_noreturn_no_args,
1480 .fn_ccc_void_no_args,
1481 .const_slice_u8,
1482 .const_slice_u8_sentinel_0,
1483 .anyerror_void_error_union,
1484 .empty_struct_literal,
1485 .function,
1486 .empty_struct,
1487 .error_set,
1488 .error_set_single,
1489 .error_set_inferred,
1490 .error_set_merged,
1491 .@"opaque",
1492 .generic_poison,
1493 .array_u8,
1494 .array_u8_sentinel_0,
1495 .int_signed,
1496 .int_unsigned,
1497 .enum_simple,
1498 => false,
1499
1500 .single_const_pointer_to_comptime_int,
1501 .type,
1502 .comptime_int,
1503 .comptime_float,
1504 .enum_literal,
1505 .type_info,
1506 => true,
1507
1508 .var_args_param => unreachable,
1509 .inferred_alloc_mut => unreachable,
1510 .inferred_alloc_const => unreachable,
1511 .bound_fn => unreachable,
1512
1513 .array,
1514 .array_sentinel,
1515 .vector,
1516 .pointer,
1517 .single_const_pointer,
1518 .single_mut_pointer,
1519 .many_const_pointer,
1520 .many_mut_pointer,
1521 .c_const_pointer,
1522 .c_mut_pointer,
1523 .const_slice,
1524 .mut_slice,
1525 => return requiresComptime(childType(ty)),
1526
1527 .optional,
1528 .optional_single_mut_pointer,
1529 .optional_single_const_pointer,
1530 => {
1531 var buf: Payload.ElemType = undefined;
1532 return requiresComptime(optionalChild(ty, &buf));
1533 },
1534
1535 .tuple => {
1536 const tuple = ty.castTag(.tuple).?.data;
1537 for (tuple.types) |field_ty| {
1538 if (requiresComptime(field_ty)) {
1539 return true;
1540 }
1541 }
1542 return false;
1543 },
1544
1545 .@"struct" => {
1546 const struct_obj = ty.castTag(.@"struct").?.data;
1547 switch (struct_obj.requires_comptime) {
1548 .no, .wip => return false,
1549 .yes => return true,
1550 .unknown => {
1551 struct_obj.requires_comptime = .wip;
1552 for (struct_obj.fields.values()) |field| {
1553 if (requiresComptime(field.ty)) {
1554 struct_obj.requires_comptime = .yes;
1555 return true;
1556 }
1557 }
1558 struct_obj.requires_comptime = .no;
1559 return false;
1560 },
1561 }
1562 },
1563
1564 .@"union", .union_tagged => {
1565 const union_obj = ty.cast(Payload.Union).?.data;
1566 switch (union_obj.requires_comptime) {
1567 .no, .wip => return false,
1568 .yes => return true,
1569 .unknown => {
1570 union_obj.requires_comptime = .wip;
1571 for (union_obj.fields.values()) |field| {
1572 if (requiresComptime(field.ty)) {
1573 union_obj.requires_comptime = .yes;
1574 return true;
1575 }
1576 }
1577 union_obj.requires_comptime = .no;
1578 return false;
1579 },
1580 }
1581 },
1582
1583 .error_union => return requiresComptime(errorUnionPayload(ty)),
1584 .anyframe_T => return ty.castTag(.anyframe_T).?.data.requiresComptime(),
1585 .enum_numbered => return ty.castTag(.enum_numbered).?.data.tag_ty.requiresComptime(),
1586 .enum_full, .enum_nonexhaustive => return ty.cast(Payload.EnumFull).?.data.tag_ty.requiresComptime(),
1587 };
1588 }
1589
1590 pub fn toValue(self: Type, allocator: Allocator) Allocator.Error!Value {1450 pub fn toValue(self: Type, allocator: Allocator) Allocator.Error!Value {
1591 switch (self.tag()) {1451 switch (self.tag()) {
1592 .u1 => return Value.initTag(.u1_type),1452 .u1 => return Value.initTag(.u1_type),
...@@ -1918,12 +1778,13 @@ pub const Type = extern union {...@@ -1918,12 +1778,13 @@ pub const Type = extern union {
1918 .fn_void_no_args, // represents machine code; not a pointer1778 .fn_void_no_args, // represents machine code; not a pointer
1919 .fn_naked_noreturn_no_args, // represents machine code; not a pointer1779 .fn_naked_noreturn_no_args, // represents machine code; not a pointer
1920 .fn_ccc_void_no_args, // represents machine code; not a pointer1780 .fn_ccc_void_no_args, // represents machine code; not a pointer
1921 .function, // represents machine code; not a pointer1781 => return target_util.defaultFunctionAlignment(target),
1922 => return switch (target.cpu.arch) {1782
1923 .arm, .armeb => 4,1783 // represents machine code; not a pointer
1924 .aarch64, .aarch64_32, .aarch64_be => 4,1784 .function => {
1925 .riscv64 => 2,1785 const alignment = self.castTag(.function).?.data.alignment;
1926 else => 1,1786 if (alignment != 0) return alignment;
1787 return target_util.defaultFunctionAlignment(target);
1927 },1788 },
19281789
1929 .i16, .u16 => return 2,1790 .i16, .u16 => return 2,
...@@ -3424,6 +3285,7 @@ pub const Type = extern union {...@@ -3424,6 +3285,7 @@ pub const Type = extern union {
3424 .comptime_params = undefined,3285 .comptime_params = undefined,
3425 .return_type = initTag(.noreturn),3286 .return_type = initTag(.noreturn),
3426 .cc = .Unspecified,3287 .cc = .Unspecified,
3288 .alignment = 0,
3427 .is_var_args = false,3289 .is_var_args = false,
3428 .is_generic = false,3290 .is_generic = false,
3429 },3291 },
...@@ -3432,6 +3294,7 @@ pub const Type = extern union {...@@ -3432,6 +3294,7 @@ pub const Type = extern union {
3432 .comptime_params = undefined,3294 .comptime_params = undefined,
3433 .return_type = initTag(.void),3295 .return_type = initTag(.void),
3434 .cc = .Unspecified,3296 .cc = .Unspecified,
3297 .alignment = 0,
3435 .is_var_args = false,3298 .is_var_args = false,
3436 .is_generic = false,3299 .is_generic = false,
3437 },3300 },
...@@ -3440,6 +3303,7 @@ pub const Type = extern union {...@@ -3440,6 +3303,7 @@ pub const Type = extern union {
3440 .comptime_params = undefined,3303 .comptime_params = undefined,
3441 .return_type = initTag(.noreturn),3304 .return_type = initTag(.noreturn),
3442 .cc = .Naked,3305 .cc = .Naked,
3306 .alignment = 0,
3443 .is_var_args = false,3307 .is_var_args = false,
3444 .is_generic = false,3308 .is_generic = false,
3445 },3309 },
...@@ -3448,6 +3312,7 @@ pub const Type = extern union {...@@ -3448,6 +3312,7 @@ pub const Type = extern union {
3448 .comptime_params = undefined,3312 .comptime_params = undefined,
3449 .return_type = initTag(.void),3313 .return_type = initTag(.void),
3450 .cc = .C,3314 .cc = .C,
3315 .alignment = 0,
3451 .is_var_args = false,3316 .is_var_args = false,
3452 .is_generic = false,3317 .is_generic = false,
3453 },3318 },
...@@ -4572,6 +4437,8 @@ pub const Type = extern union {...@@ -4572,6 +4437,8 @@ pub const Type = extern union {
4572 param_types: []Type,4437 param_types: []Type,
4573 comptime_params: [*]bool,4438 comptime_params: [*]bool,
4574 return_type: Type,4439 return_type: Type,
4440 /// If zero use default target function code alignment.
4441 alignment: u32,
4575 cc: std.builtin.CallingConvention,4442 cc: std.builtin.CallingConvention,
4576 is_var_args: bool,4443 is_var_args: bool,
4577 is_generic: bool,4444 is_generic: bool,
src/value.zig+10-2
...@@ -1520,6 +1520,11 @@ pub const Value = extern union {...@@ -1520,6 +1520,11 @@ pub const Value = extern union {
1520 }1520 }
1521 return true;1521 return true;
1522 },1522 },
1523 .function => {
1524 const a_payload = a.castTag(.function).?.data;
1525 const b_payload = b.castTag(.function).?.data;
1526 return a_payload == b_payload;
1527 },
1523 else => {},1528 else => {},
1524 }1529 }
1525 } else if (a_tag == .null_value or b_tag == .null_value) {1530 } else if (a_tag == .null_value or b_tag == .null_value) {
...@@ -1573,6 +1578,7 @@ pub const Value = extern union {...@@ -1573,6 +1578,7 @@ pub const Value = extern union {
1573 pub fn hash(val: Value, ty: Type, hasher: *std.hash.Wyhash) void {1578 pub fn hash(val: Value, ty: Type, hasher: *std.hash.Wyhash) void {
1574 const zig_ty_tag = ty.zigTypeTag();1579 const zig_ty_tag = ty.zigTypeTag();
1575 std.hash.autoHash(hasher, zig_ty_tag);1580 std.hash.autoHash(hasher, zig_ty_tag);
1581 if (val.isUndef()) return;
15761582
1577 switch (zig_ty_tag) {1583 switch (zig_ty_tag) {
1578 .BoundFn => unreachable, // TODO remove this from the language1584 .BoundFn => unreachable, // TODO remove this from the language
...@@ -1694,7 +1700,8 @@ pub const Value = extern union {...@@ -1694,7 +1700,8 @@ pub const Value = extern union {
1694 union_obj.val.hash(active_field_ty, hasher);1700 union_obj.val.hash(active_field_ty, hasher);
1695 },1701 },
1696 .Fn => {1702 .Fn => {
1697 @panic("TODO implement hashing function values");1703 const func = val.castTag(.function).?.data;
1704 return std.hash.autoHash(hasher, func.owner_decl);
1698 },1705 },
1699 .Frame => {1706 .Frame => {
1700 @panic("TODO implement hashing frame values");1707 @panic("TODO implement hashing frame values");
...@@ -1703,7 +1710,8 @@ pub const Value = extern union {...@@ -1703,7 +1710,8 @@ pub const Value = extern union {
1703 @panic("TODO implement hashing anyframe values");1710 @panic("TODO implement hashing anyframe values");
1704 },1711 },
1705 .EnumLiteral => {1712 .EnumLiteral => {
1706 @panic("TODO implement hashing enum literal values");1713 const bytes = val.castTag(.enum_literal).?.data;
1714 hasher.update(bytes);
1707 },1715 },
1708 }1716 }
1709 }1717 }
test/behavior.zig+9-12
...@@ -2,22 +2,23 @@ const builtin = @import("builtin");...@@ -2,22 +2,23 @@ const builtin = @import("builtin");
22
3test {3test {
4 // Tests that pass for stage1, llvm backend, C backend, wasm backend, arm backend and x86_64 backend.4 // Tests that pass for stage1, llvm backend, C backend, wasm backend, arm backend and x86_64 backend.
5 _ = @import("behavior/align.zig");
6 _ = @import("behavior/array.zig");
7 _ = @import("behavior/bool.zig");
8 _ = @import("behavior/bugs/655.zig");
9 _ = @import("behavior/bugs/679.zig");
5 _ = @import("behavior/bugs/1111.zig");10 _ = @import("behavior/bugs/1111.zig");
6 _ = @import("behavior/bugs/2346.zig");11 _ = @import("behavior/bugs/2346.zig");
7 _ = @import("behavior/slice_sentinel_comptime.zig");
8 _ = @import("behavior/bugs/679.zig");
9 _ = @import("behavior/bugs/6850.zig");12 _ = @import("behavior/bugs/6850.zig");
13 _ = @import("behavior/cast.zig");
14 _ = @import("behavior/comptime_memory.zig");
10 _ = @import("behavior/fn_in_struct_in_comptime.zig");15 _ = @import("behavior/fn_in_struct_in_comptime.zig");
11 _ = @import("behavior/hasdecl.zig");16 _ = @import("behavior/hasdecl.zig");
12 _ = @import("behavior/hasfield.zig");17 _ = @import("behavior/hasfield.zig");
13 _ = @import("behavior/prefetch.zig");18 _ = @import("behavior/prefetch.zig");
14 _ = @import("behavior/pub_enum.zig");19 _ = @import("behavior/pub_enum.zig");
20 _ = @import("behavior/slice_sentinel_comptime.zig");
15 _ = @import("behavior/type.zig");21 _ = @import("behavior/type.zig");
16 _ = @import("behavior/bugs/655.zig");
17 _ = @import("behavior/bool.zig");
18 _ = @import("behavior/align.zig");
19 _ = @import("behavior/array.zig");
20 _ = @import("behavior/cast.zig");
2122
22 if (builtin.zig_backend != .stage2_arm and builtin.zig_backend != .stage2_x86_64) {23 if (builtin.zig_backend != .stage2_arm and builtin.zig_backend != .stage2_x86_64) {
23 // Tests that pass for stage1, llvm backend, C backend, wasm backend.24 // Tests that pass for stage1, llvm backend, C backend, wasm backend.
...@@ -113,11 +114,7 @@ test {...@@ -113,11 +114,7 @@ test {
113 _ = @import("behavior/switch.zig");114 _ = @import("behavior/switch.zig");
114 _ = @import("behavior/widening.zig");115 _ = @import("behavior/widening.zig");
115116
116 if (builtin.zig_backend != .stage1) {117 if (builtin.zig_backend == .stage1) {
117 // When all comptime_memory.zig tests pass, #9646 can be closed.
118 // _ = @import("behavior/comptime_memory.zig");
119 _ = @import("behavior/slice_stage2.zig");
120 } else {
121 // Tests that only pass for the stage1 backend.118 // Tests that only pass for the stage1 backend.
122 _ = @import("behavior/align_stage1.zig");119 _ = @import("behavior/align_stage1.zig");
123 if (builtin.os.tag != .wasi) {120 if (builtin.os.tag != .wasi) {
test/behavior/align.zig+20
...@@ -181,3 +181,23 @@ test "page aligned array on stack" {...@@ -181,3 +181,23 @@ test "page aligned array on stack" {
181 try expect(number1 == 42);181 try expect(number1 == 42);
182 try expect(number2 == 43);182 try expect(number2 == 43);
183}183}
184
185fn derp() align(@sizeOf(usize) * 2) i32 {
186 return 1234;
187}
188fn noop1() align(1) void {}
189fn noop4() align(4) void {}
190
191test "function alignment" {
192 // function alignment is a compile error on wasm32/wasm64
193 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
194
195 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
196 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
197
198 try expect(derp() == 1234);
199 try expect(@TypeOf(noop1) == fn () align(1) void);
200 try expect(@TypeOf(noop4) == fn () align(4) void);
201 noop1();
202 noop4();
203}
test/behavior/align_stage1.zig-17
...@@ -3,23 +3,6 @@ const expect = std.testing.expect;...@@ -3,23 +3,6 @@ const expect = std.testing.expect;
3const builtin = @import("builtin");3const builtin = @import("builtin");
4const native_arch = builtin.target.cpu.arch;4const native_arch = builtin.target.cpu.arch;
55
6fn derp() align(@sizeOf(usize) * 2) i32 {
7 return 1234;
8}
9fn noop1() align(1) void {}
10fn noop4() align(4) void {}
11
12test "function alignment" {
13 // function alignment is a compile error on wasm32/wasm64
14 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
15
16 try expect(derp() == 1234);
17 try expect(@TypeOf(noop1) == fn () align(1) void);
18 try expect(@TypeOf(noop4) == fn () align(4) void);
19 noop1();
20 noop4();
21}
22
23test "implicitly decreasing fn alignment" {6test "implicitly decreasing fn alignment" {
24 // function alignment is a compile error on wasm32/wasm647 // function alignment is a compile error on wasm32/wasm64
25 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;8 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
test/behavior/basic.zig+3-1
...@@ -259,6 +259,8 @@ fn fB() []const u8 {...@@ -259,6 +259,8 @@ fn fB() []const u8 {
259}259}
260260
261test "call function pointer in struct" {261test "call function pointer in struct" {
262 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
263
262 try expect(mem.eql(u8, f3(true), "a"));264 try expect(mem.eql(u8, f3(true), "a"));
263 try expect(mem.eql(u8, f3(false), "b"));265 try expect(mem.eql(u8, f3(false), "b"));
264}266}
...@@ -276,7 +278,7 @@ fn f3(x: bool) []const u8 {...@@ -276,7 +278,7 @@ fn f3(x: bool) []const u8 {
276}278}
277279
278const FnPtrWrapper = struct {280const FnPtrWrapper = struct {
279 fn_ptr: fn () []const u8,281 fn_ptr: *const fn () []const u8,
280};282};
281283
282test "const ptr from var variable" {284test "const ptr from var variable" {
test/behavior/basic_llvm.zig+3-1
...@@ -205,9 +205,11 @@ test "multiline string literal is null terminated" {...@@ -205,9 +205,11 @@ test "multiline string literal is null terminated" {
205}205}
206206
207test "self reference through fn ptr field" {207test "self reference through fn ptr field" {
208 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
209
208 const S = struct {210 const S = struct {
209 const A = struct {211 const A = struct {
210 f: fn (A) u8,212 f: *const fn (A) u8,
211 };213 };
212214
213 fn foo(a: A) u8 {215 fn foo(a: A) u8 {
test/behavior/bugs/1500.zig+1-1
...@@ -2,7 +2,7 @@ const A = struct {...@@ -2,7 +2,7 @@ const A = struct {
2 b: B,2 b: B,
3};3};
44
5const B = fn (A) void;5const B = *const fn (A) void;
66
7test "allow these dependencies" {7test "allow these dependencies" {
8 var a: A = undefined;8 var a: A = undefined;
test/behavior/bugs/3112.zig+4-1
...@@ -1,9 +1,10 @@...@@ -1,9 +1,10 @@
1const builtin = @import("builtin");
1const std = @import("std");2const std = @import("std");
2const expect = std.testing.expect;3const expect = std.testing.expect;
34
4const State = struct {5const State = struct {
5 const Self = @This();6 const Self = @This();
6 enter: fn (previous: ?Self) void,7 enter: *const fn (previous: ?Self) void,
7};8};
89
9fn prev(p: ?State) void {10fn prev(p: ?State) void {
...@@ -11,6 +12,8 @@ fn prev(p: ?State) void {...@@ -11,6 +12,8 @@ fn prev(p: ?State) void {
11}12}
1213
13test "zig test crash" {14test "zig test crash" {
15 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
16
14 var global: State = undefined;17 var global: State = undefined;
15 global.enter = prev;18 global.enter = prev;
16 global.enter(null);19 global.enter(null);
test/behavior/cast_llvm.zig+4-2
...@@ -47,12 +47,14 @@ fn incrementVoidPtrArray(array: ?*anyopaque, len: usize) void {...@@ -47,12 +47,14 @@ fn incrementVoidPtrArray(array: ?*anyopaque, len: usize) void {
47}47}
4848
49test "compile time int to ptr of function" {49test "compile time int to ptr of function" {
50 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
50 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) return error.SkipZigTest; // TODO51 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) return error.SkipZigTest; // TODO
52
51 try foobar(FUNCTION_CONSTANT);53 try foobar(FUNCTION_CONSTANT);
52}54}
5355
54pub const FUNCTION_CONSTANT = @intToPtr(PFN_void, maxInt(usize));56pub const FUNCTION_CONSTANT = @intToPtr(PFN_void, maxInt(usize));
55pub const PFN_void = fn (*anyopaque) callconv(.C) void;57pub const PFN_void = *const fn (*anyopaque) callconv(.C) void;
5658
57fn foobar(func: PFN_void) !void {59fn foobar(func: PFN_void) !void {
58 try std.testing.expect(@ptrToInt(func) == maxInt(usize));60 try std.testing.expect(@ptrToInt(func) == maxInt(usize));
...@@ -154,7 +156,7 @@ test "implicit cast *[0]T to E![]const u8" {...@@ -154,7 +156,7 @@ test "implicit cast *[0]T to E![]const u8" {
154156
155var global_array: [4]u8 = undefined;157var global_array: [4]u8 = undefined;
156test "cast from array reference to fn" {158test "cast from array reference to fn" {
157 const f = @ptrCast(fn () callconv(.C) void, &global_array);159 const f = @ptrCast(*const fn () callconv(.C) void, &global_array);
158 try expect(@ptrToInt(f) == @ptrToInt(&global_array));160 try expect(@ptrToInt(f) == @ptrToInt(&global_array));
159}161}
160162
test/behavior/comptime_memory.zig+98-1
...@@ -1,8 +1,15 @@...@@ -1,8 +1,15 @@
1const endian = @import("builtin").cpu.arch.endian();1const builtin = @import("builtin");
2const endian = builtin.cpu.arch.endian();
2const testing = @import("std").testing;3const testing = @import("std").testing;
3const ptr_size = @sizeOf(usize);4const ptr_size = @sizeOf(usize);
45
5test "type pun signed and unsigned as single pointer" {6test "type pun signed and unsigned as single pointer" {
7 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
8 if (builtin.zig_backend != .stage1) {
9 // TODO https://github.com/ziglang/zig/issues/9646
10 return error.SkipZigTest;
11 }
12
6 comptime {13 comptime {
7 var x: u32 = 0;14 var x: u32 = 0;
8 const y = @ptrCast(*i32, &x);15 const y = @ptrCast(*i32, &x);
...@@ -12,6 +19,12 @@ test "type pun signed and unsigned as single pointer" {...@@ -12,6 +19,12 @@ test "type pun signed and unsigned as single pointer" {
12}19}
1320
14test "type pun signed and unsigned as many pointer" {21test "type pun signed and unsigned as many pointer" {
22 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
23 if (builtin.zig_backend != .stage1) {
24 // TODO https://github.com/ziglang/zig/issues/9646
25 return error.SkipZigTest;
26 }
27
15 comptime {28 comptime {
16 var x: u32 = 0;29 var x: u32 = 0;
17 const y = @ptrCast([*]i32, &x);30 const y = @ptrCast([*]i32, &x);
...@@ -21,6 +34,12 @@ test "type pun signed and unsigned as many pointer" {...@@ -21,6 +34,12 @@ test "type pun signed and unsigned as many pointer" {
21}34}
2235
23test "type pun signed and unsigned as array pointer" {36test "type pun signed and unsigned as array pointer" {
37 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
38 if (builtin.zig_backend != .stage1) {
39 // TODO https://github.com/ziglang/zig/issues/9646
40 return error.SkipZigTest;
41 }
42
24 comptime {43 comptime {
25 var x: u32 = 0;44 var x: u32 = 0;
26 const y = @ptrCast(*[1]i32, &x);45 const y = @ptrCast(*[1]i32, &x);
...@@ -30,6 +49,12 @@ test "type pun signed and unsigned as array pointer" {...@@ -30,6 +49,12 @@ test "type pun signed and unsigned as array pointer" {
30}49}
3150
32test "type pun signed and unsigned as offset many pointer" {51test "type pun signed and unsigned as offset many pointer" {
52 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
53 if (builtin.zig_backend != .stage1) {
54 // TODO https://github.com/ziglang/zig/issues/9646
55 return error.SkipZigTest;
56 }
57
33 comptime {58 comptime {
34 var x: u32 = 0;59 var x: u32 = 0;
35 var y = @ptrCast([*]i32, &x);60 var y = @ptrCast([*]i32, &x);
...@@ -40,6 +65,12 @@ test "type pun signed and unsigned as offset many pointer" {...@@ -40,6 +65,12 @@ test "type pun signed and unsigned as offset many pointer" {
40}65}
4166
42test "type pun signed and unsigned as array pointer" {67test "type pun signed and unsigned as array pointer" {
68 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
69 if (builtin.zig_backend != .stage1) {
70 // TODO https://github.com/ziglang/zig/issues/9646
71 return error.SkipZigTest;
72 }
73
43 comptime {74 comptime {
44 var x: u32 = 0;75 var x: u32 = 0;
45 const y = @ptrCast([*]i32, &x) - 10;76 const y = @ptrCast([*]i32, &x) - 10;
...@@ -50,6 +81,12 @@ test "type pun signed and unsigned as array pointer" {...@@ -50,6 +81,12 @@ test "type pun signed and unsigned as array pointer" {
50}81}
5182
52test "type pun value and struct" {83test "type pun value and struct" {
84 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
85 if (builtin.zig_backend != .stage1) {
86 // TODO https://github.com/ziglang/zig/issues/9646
87 return error.SkipZigTest;
88 }
89
53 comptime {90 comptime {
54 const StructOfU32 = extern struct { x: u32 };91 const StructOfU32 = extern struct { x: u32 };
55 var inst: StructOfU32 = .{ .x = 0 };92 var inst: StructOfU32 = .{ .x = 0 };
...@@ -64,6 +101,12 @@ fn bigToNativeEndian(comptime T: type, v: T) T {...@@ -64,6 +101,12 @@ fn bigToNativeEndian(comptime T: type, v: T) T {
64 return if (endian == .Big) v else @byteSwap(T, v);101 return if (endian == .Big) v else @byteSwap(T, v);
65}102}
66test "type pun endianness" {103test "type pun endianness" {
104 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
105 if (builtin.zig_backend != .stage1) {
106 // TODO https://github.com/ziglang/zig/issues/9646
107 return error.SkipZigTest;
108 }
109
67 comptime {110 comptime {
68 const StructOfBytes = extern struct { x: [4]u8 };111 const StructOfBytes = extern struct { x: [4]u8 };
69 var inst: StructOfBytes = .{ .x = [4]u8{ 0, 0, 0, 0 } };112 var inst: StructOfBytes = .{ .x = [4]u8{ 0, 0, 0, 0 } };
...@@ -155,6 +198,12 @@ fn doTypePunBitsTest(as_bits: *Bits) !void {...@@ -155,6 +198,12 @@ fn doTypePunBitsTest(as_bits: *Bits) !void {
155}198}
156199
157test "type pun bits" {200test "type pun bits" {
201 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
202 if (builtin.zig_backend != .stage1) {
203 // TODO https://github.com/ziglang/zig/issues/9646
204 return error.SkipZigTest;
205 }
206
158 comptime {207 comptime {
159 var v: u32 = undefined;208 var v: u32 = undefined;
160 try doTypePunBitsTest(@ptrCast(*Bits, &v));209 try doTypePunBitsTest(@ptrCast(*Bits, &v));
...@@ -167,6 +216,12 @@ const imports = struct {...@@ -167,6 +216,12 @@ const imports = struct {
167216
168// Make sure lazy values work on their own, before getting into more complex tests217// Make sure lazy values work on their own, before getting into more complex tests
169test "basic pointer preservation" {218test "basic pointer preservation" {
219 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
220 if (builtin.zig_backend != .stage1) {
221 // TODO https://github.com/ziglang/zig/issues/9646
222 return error.SkipZigTest;
223 }
224
170 comptime {225 comptime {
171 const lazy_address = @ptrToInt(&imports.global_u32);226 const lazy_address = @ptrToInt(&imports.global_u32);
172 try testing.expectEqual(@ptrToInt(&imports.global_u32), lazy_address);227 try testing.expectEqual(@ptrToInt(&imports.global_u32), lazy_address);
...@@ -175,6 +230,12 @@ test "basic pointer preservation" {...@@ -175,6 +230,12 @@ test "basic pointer preservation" {
175}230}
176231
177test "byte copy preserves linker value" {232test "byte copy preserves linker value" {
233 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
234 if (builtin.zig_backend != .stage1) {
235 // TODO https://github.com/ziglang/zig/issues/9646
236 return error.SkipZigTest;
237 }
238
178 const ct_value = comptime blk: {239 const ct_value = comptime blk: {
179 const lazy = &imports.global_u32;240 const lazy = &imports.global_u32;
180 var result: *u32 = undefined;241 var result: *u32 = undefined;
...@@ -193,6 +254,12 @@ test "byte copy preserves linker value" {...@@ -193,6 +254,12 @@ test "byte copy preserves linker value" {
193}254}
194255
195test "unordered byte copy preserves linker value" {256test "unordered byte copy preserves linker value" {
257 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
258 if (builtin.zig_backend != .stage1) {
259 // TODO https://github.com/ziglang/zig/issues/9646
260 return error.SkipZigTest;
261 }
262
196 const ct_value = comptime blk: {263 const ct_value = comptime blk: {
197 const lazy = &imports.global_u32;264 const lazy = &imports.global_u32;
198 var result: *u32 = undefined;265 var result: *u32 = undefined;
...@@ -212,6 +279,12 @@ test "unordered byte copy preserves linker value" {...@@ -212,6 +279,12 @@ test "unordered byte copy preserves linker value" {
212}279}
213280
214test "shuffle chunks of linker value" {281test "shuffle chunks of linker value" {
282 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
283 if (builtin.zig_backend != .stage1) {
284 // TODO https://github.com/ziglang/zig/issues/9646
285 return error.SkipZigTest;
286 }
287
215 const lazy_address = @ptrToInt(&imports.global_u32);288 const lazy_address = @ptrToInt(&imports.global_u32);
216 const shuffled1_rt = shuffle(lazy_address, Bits, ShuffledBits);289 const shuffled1_rt = shuffle(lazy_address, Bits, ShuffledBits);
217 const unshuffled1_rt = shuffle(shuffled1_rt, ShuffledBits, Bits);290 const unshuffled1_rt = shuffle(shuffled1_rt, ShuffledBits, Bits);
...@@ -225,6 +298,12 @@ test "shuffle chunks of linker value" {...@@ -225,6 +298,12 @@ test "shuffle chunks of linker value" {
225}298}
226299
227test "dance on linker values" {300test "dance on linker values" {
301 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
302 if (builtin.zig_backend != .stage1) {
303 // TODO https://github.com/ziglang/zig/issues/9646
304 return error.SkipZigTest;
305 }
306
228 comptime {307 comptime {
229 var arr: [2]usize = undefined;308 var arr: [2]usize = undefined;
230 arr[0] = @ptrToInt(&imports.global_u32);309 arr[0] = @ptrToInt(&imports.global_u32);
...@@ -251,6 +330,12 @@ test "dance on linker values" {...@@ -251,6 +330,12 @@ test "dance on linker values" {
251}330}
252331
253test "offset array ptr by element size" {332test "offset array ptr by element size" {
333 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
334 if (builtin.zig_backend != .stage1) {
335 // TODO https://github.com/ziglang/zig/issues/9646
336 return error.SkipZigTest;
337 }
338
254 comptime {339 comptime {
255 const VirtualStruct = struct { x: u32 };340 const VirtualStruct = struct { x: u32 };
256 var arr: [4]VirtualStruct = .{341 var arr: [4]VirtualStruct = .{
...@@ -273,6 +358,12 @@ test "offset array ptr by element size" {...@@ -273,6 +358,12 @@ test "offset array ptr by element size" {
273}358}
274359
275test "offset instance by field size" {360test "offset instance by field size" {
361 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
362 if (builtin.zig_backend != .stage1) {
363 // TODO https://github.com/ziglang/zig/issues/9646
364 return error.SkipZigTest;
365 }
366
276 comptime {367 comptime {
277 const VirtualStruct = struct { x: u32, y: u32, z: u32, w: u32 };368 const VirtualStruct = struct { x: u32, y: u32, z: u32, w: u32 };
278 var inst = VirtualStruct{ .x = 0, .y = 1, .z = 2, .w = 3 };369 var inst = VirtualStruct{ .x = 0, .y = 1, .z = 2, .w = 3 };
...@@ -293,6 +384,12 @@ test "offset instance by field size" {...@@ -293,6 +384,12 @@ test "offset instance by field size" {
293}384}
294385
295test "offset field ptr by enclosing array element size" {386test "offset field ptr by enclosing array element size" {
387 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
388 if (builtin.zig_backend != .stage1) {
389 // TODO https://github.com/ziglang/zig/issues/9646
390 return error.SkipZigTest;
391 }
392
296 comptime {393 comptime {
297 const VirtualStruct = struct { x: u32 };394 const VirtualStruct = struct { x: u32 };
298 var arr: [4]VirtualStruct = .{395 var arr: [4]VirtualStruct = .{
test/behavior/error.zig+1
...@@ -1,3 +1,4 @@...@@ -1,3 +1,4 @@
1const builtin = @import("builtin");
1const std = @import("std");2const std = @import("std");
2const expect = std.testing.expect;3const expect = std.testing.expect;
3const expectError = std.testing.expectError;4const expectError = std.testing.expectError;
test/behavior/fn.zig+9-3
...@@ -57,7 +57,7 @@ test "assign inline fn to const variable" {...@@ -57,7 +57,7 @@ test "assign inline fn to const variable" {
5757
58inline fn inlineFn() void {}58inline fn inlineFn() void {}
5959
60fn outer(y: u32) fn (u32) u32 {60fn outer(y: u32) *const fn (u32) u32 {
61 const Y = @TypeOf(y);61 const Y = @TypeOf(y);
62 const st = struct {62 const st = struct {
63 fn get(z: u32) u32 {63 fn get(z: u32) u32 {
...@@ -68,6 +68,8 @@ fn outer(y: u32) fn (u32) u32 {...@@ -68,6 +68,8 @@ fn outer(y: u32) fn (u32) u32 {
68}68}
6969
70test "return inner function which references comptime variable of outer function" {70test "return inner function which references comptime variable of outer function" {
71 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
72
71 var func = outer(10);73 var func = outer(10);
72 try expect(func(3) == 7);74 try expect(func(3) == 7);
73}75}
...@@ -92,6 +94,8 @@ test "discard the result of a function that returns a struct" {...@@ -92,6 +94,8 @@ test "discard the result of a function that returns a struct" {
92}94}
9395
94test "inline function call that calls optional function pointer, return pointer at callsite interacts correctly with callsite return type" {96test "inline function call that calls optional function pointer, return pointer at callsite interacts correctly with callsite return type" {
97 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
98
95 const S = struct {99 const S = struct {
96 field: u32,100 field: u32,
97101
...@@ -113,7 +117,7 @@ test "inline function call that calls optional function pointer, return pointer...@@ -113,7 +117,7 @@ test "inline function call that calls optional function pointer, return pointer
113 return bar2.?();117 return bar2.?();
114 }118 }
115119
116 var bar2: ?fn () u32 = null;120 var bar2: ?*const fn () u32 = null;
117121
118 fn actualFn() u32 {122 fn actualFn() u32 {
119 return 1234;123 return 1234;
...@@ -135,8 +139,10 @@ fn fnWithUnreachable() noreturn {...@@ -135,8 +139,10 @@ fn fnWithUnreachable() noreturn {
135}139}
136140
137test "extern struct with stdcallcc fn pointer" {141test "extern struct with stdcallcc fn pointer" {
142 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
143
138 const S = extern struct {144 const S = extern struct {
139 ptr: fn () callconv(if (builtin.target.cpu.arch == .i386) .Stdcall else .C) i32,145 ptr: *const fn () callconv(if (builtin.target.cpu.arch == .i386) .Stdcall else .C) i32,
140146
141 fn foo() callconv(if (builtin.target.cpu.arch == .i386) .Stdcall else .C) i32 {147 fn foo() callconv(if (builtin.target.cpu.arch == .i386) .Stdcall else .C) i32 {
142 return 1234;148 return 1234;
test/behavior/inttoptr.zig+7-5
...@@ -1,14 +1,16 @@...@@ -1,14 +1,16 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
22
3test "casting random address to function pointer" {3test "casting integer address to function pointer" {
4 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
4 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) return error.SkipZigTest; // TODO5 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) return error.SkipZigTest; // TODO
5 randomAddressToFunction();6
6 comptime randomAddressToFunction();7 addressToFunction();
8 comptime addressToFunction();
7}9}
810
9fn randomAddressToFunction() void {11fn addressToFunction() void {
10 var addr: usize = 0xdeadbeef;12 var addr: usize = 0xdeadbeef;
11 _ = @intToPtr(fn () void, addr);13 _ = @intToPtr(*const fn () void, addr);
12}14}
1315
14test "mutate through ptr initialized with constant intToPtr value" {16test "mutate through ptr initialized with constant intToPtr value" {
test/behavior/member_func.zig+8-2
...@@ -1,8 +1,10 @@...@@ -1,8 +1,10 @@
1const expect = @import("std").testing.expect;1const builtin = @import("builtin");
2const std = @import("std");
3const expect = std.testing.expect;
24
3const HasFuncs = struct {5const HasFuncs = struct {
4 state: u32,6 state: u32,
5 func_field: fn (u32) u32,7 func_field: *const fn (u32) u32,
68
7 fn inc(self: *HasFuncs) void {9 fn inc(self: *HasFuncs) void {
8 self.state += 1;10 self.state += 1;
...@@ -25,6 +27,8 @@ const HasFuncs = struct {...@@ -25,6 +27,8 @@ const HasFuncs = struct {
25};27};
2628
27test "standard field calls" {29test "standard field calls" {
30 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
31
28 try expect(HasFuncs.one(0) == 1);32 try expect(HasFuncs.one(0) == 1);
29 try expect(HasFuncs.two(0) == 2);33 try expect(HasFuncs.two(0) == 2);
3034
...@@ -64,6 +68,8 @@ test "standard field calls" {...@@ -64,6 +68,8 @@ test "standard field calls" {
64}68}
6569
66test "@field field calls" {70test "@field field calls" {
71 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
72
67 try expect(@field(HasFuncs, "one")(0) == 1);73 try expect(@field(HasFuncs, "one")(0) == 1);
68 try expect(@field(HasFuncs, "two")(0) == 2);74 try expect(@field(HasFuncs, "two")(0) == 2);
6975
test/behavior/slice.zig+13
...@@ -1,3 +1,4 @@...@@ -1,3 +1,4 @@
1const builtin = @import("builtin");
1const std = @import("std");2const std = @import("std");
2const expect = std.testing.expect;3const expect = std.testing.expect;
3const expectEqualSlices = std.testing.expectEqualSlices;4const expectEqualSlices = std.testing.expectEqualSlices;
...@@ -166,3 +167,15 @@ test "slicing zero length array" {...@@ -166,3 +167,15 @@ test "slicing zero length array" {
166 try expect(mem.eql(u8, s1, ""));167 try expect(mem.eql(u8, s1, ""));
167 try expect(mem.eql(u32, s2, &[_]u32{}));168 try expect(mem.eql(u32, s2, &[_]u32{}));
168}169}
170
171const x = @intToPtr([*]i32, 0x1000)[0..0x500];
172const y = x[0x100..];
173test "compile time slice of pointer to hard coded address" {
174 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
175
176 try expect(@ptrToInt(x) == 0x1000);
177 try expect(x.len == 0x500);
178
179 try expect(@ptrToInt(y) == 0x1400);
180 try expect(y.len == 0x400);
181}
test/behavior/slice_stage2.zig deleted-12
...@@ -1,12 +0,0 @@
1const std = @import("std");
2const expect = std.testing.expect;
3
4const x = @intToPtr([*]i32, 0x1000)[0..0x500];
5const y = x[0x100..];
6test "compile time slice of pointer to hard coded address" {
7 try expect(@ptrToInt(x) == 0x1000);
8 try expect(x.len == 0x500);
9
10 try expect(@ptrToInt(y) == 0x1400);
11 try expect(y.len == 0x400);
12}
test/behavior/union.zig+4-1
...@@ -1,3 +1,4 @@...@@ -1,3 +1,4 @@
1const builtin = @import("builtin");
1const std = @import("std");2const std = @import("std");
2const expect = std.testing.expect;3const expect = std.testing.expect;
3const expectEqual = std.testing.expectEqual;4const expectEqual = std.testing.expectEqual;
...@@ -166,8 +167,10 @@ test "union with specified enum tag" {...@@ -166,8 +167,10 @@ test "union with specified enum tag" {
166}167}
167168
168test "packed union generates correctly aligned LLVM type" {169test "packed union generates correctly aligned LLVM type" {
170 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
171
169 const U = packed union {172 const U = packed union {
170 f1: fn () error{TestUnexpectedResult}!void,173 f1: *const fn () error{TestUnexpectedResult}!void,
171 f2: u32,174 f2: u32,
172 };175 };
173 var foo = [_]U{176 var foo = [_]U{