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) {
730730/// therefore must be kept in sync with the compiler implementation.
731731pub const TestFn = struct {
732732 name: []const u8,
733 func: fn () anyerror!void,
733 func: testFnProto,
734734 async_frame_size: ?usize,
735735};
736736
737/// stage1 is *wrong*. It is not yet updated to support the new function type semantics.
738const testFnProto = switch (builtin.zig_backend) {
739 .stage1 => fn () anyerror!void, // wrong!
740 else => *const fn () anyerror!void,
741};
742
737743/// This function type is used by the Zig language code generation and
738744/// therefore must be kept in sync with the compiler implementation.
739745pub const PanicFn = fn ([]const u8, ?*StackTrace) noreturn;
src/AstGen.zig+4-6
......@@ -3240,7 +3240,8 @@ fn fnDecl(
32403240 const doc_comment_index = try astgen.docCommentAsString(fn_proto.firstToken());
32413241
32423242 const has_section_or_addrspace = fn_proto.ast.section_expr != 0 or fn_proto.ast.addrspace_expr != 0;
3243 wip_members.nextDecl(is_pub, is_export, fn_proto.ast.align_expr != 0, has_section_or_addrspace);
3243 // Alignment is passed in the func instruction in this case.
3244 wip_members.nextDecl(is_pub, is_export, false, has_section_or_addrspace);
32443245
32453246 var params_scope = &fn_gz.base;
32463247 const is_var_args = is_var_args: {
......@@ -3380,7 +3381,7 @@ fn fnDecl(
33803381 .param_block = block_inst,
33813382 .body_gz = null,
33823383 .cc = cc,
3383 .align_inst = .none, // passed in the per-decl data
3384 .align_inst = align_inst,
33843385 .lib_name = lib_name,
33853386 .is_var_args = is_var_args,
33863387 .is_inferred_error = false,
......@@ -3423,7 +3424,7 @@ fn fnDecl(
34233424 .ret_br = ret_br,
34243425 .body_gz = &fn_gz,
34253426 .cc = cc,
3426 .align_inst = .none, // passed in the per-decl data
3427 .align_inst = align_inst,
34273428 .lib_name = lib_name,
34283429 .is_var_args = is_var_args,
34293430 .is_inferred_error = is_inferred_error,
......@@ -3449,9 +3450,6 @@ fn fnDecl(
34493450 wip_members.appendToDecl(fn_name_str_index);
34503451 wip_members.appendToDecl(block_inst);
34513452 wip_members.appendToDecl(doc_comment_index);
3452 if (align_inst != .none) {
3453 wip_members.appendToDecl(@enumToInt(align_inst));
3454 }
34553453 if (has_section_or_addrspace) {
34563454 wip_members.appendToDecl(@enumToInt(section_inst));
34573455 wip_members.appendToDecl(@enumToInt(addrspace_inst));
src/Module.zig+117-2
......@@ -898,6 +898,45 @@ pub const Struct = struct {
898898 };
899899 }
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
901940 pub fn haveFieldTypes(s: Struct) bool {
902941 return switch (s.status) {
903942 .none,
......@@ -1063,6 +1102,33 @@ pub const Union = struct {
10631102 };
10641103 }
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
10661132 pub fn haveFieldTypes(u: Union) bool {
10671133 return switch (u.status) {
10681134 .none,
......@@ -4662,8 +4728,8 @@ pub fn createAnonymousDeclFromDeclNamed(
46624728 new_decl.src_line = src_decl.src_line;
46634729 new_decl.ty = typed_value.ty;
46644730 new_decl.val = typed_value.val;
4665 new_decl.align_val = Value.initTag(.null_value);
4666 new_decl.linksection_val = Value.initTag(.null_value);
4731 new_decl.align_val = Value.@"null";
4732 new_decl.linksection_val = Value.@"null";
46674733 new_decl.has_tv = true;
46684734 new_decl.analysis = .complete;
46694735 new_decl.generation = mod.generation;
......@@ -4905,6 +4971,55 @@ pub const PeerTypeCandidateSrc = union(enum) {
49054971 }
49064972};
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
49085023/// Called from `performAllTheWork`, after all AstGen workers have finished,
49095024/// and before the main semantic analysis loop begins.
49105025pub fn processOutdatedAndDeletedDecls(mod: *Module) !void {
src/Sema.zig+473-103
......@@ -4147,7 +4147,7 @@ fn analyzeCall(
41474147 const gpa = sema.gpa;
41484148
41494149 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);
41514151 const is_inline_call = is_comptime_call or modifier == .always_inline or
41524152 func_ty_info.cc == .Inline;
41534153 const result: Air.Inst.Ref = if (is_inline_call) res: {
......@@ -4576,7 +4576,7 @@ fn analyzeCall(
45764576 }
45774577 } else if (is_anytype) {
45784578 const arg_ty = sema.typeOf(arg);
4579 if (arg_ty.requiresComptime()) {
4579 if (try sema.typeRequiresComptime(block, arg_src, arg_ty)) {
45804580 const arg_val = try sema.resolveConstValue(block, arg_src, arg);
45814581 const child_arg = try child_sema.addConstant(arg_ty, arg_val);
45824582 child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
......@@ -5430,7 +5430,6 @@ fn funcCommon(
54305430 src_locs: Zir.Inst.Func.SrcLocs,
54315431 opt_lib_name: ?[]const u8,
54325432) CompileError!Air.Inst.Ref {
5433 const src: LazySrcLoc = .{ .node_offset = src_node_offset };
54345433 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
54355434
54365435 // The return type body might be a type expression that depends on generic parameters.
......@@ -5481,11 +5480,22 @@ fn funcCommon(
54815480 errdefer if (maybe_inferred_error_set_node) |node| sema.gpa.destroy(node);
54825481 // 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
54845485 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
54855495 // Hot path for some common function types.
54865496 // TODO can we eliminate some of these Type tag values? seems unnecessarily complicated.
54875497 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)
54895499 {
54905500 if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {
54915501 break :fn_ty Type.initTag(.fn_noreturn_no_args);
......@@ -5507,16 +5517,15 @@ fn funcCommon(
55075517 const param_types = try sema.arena.alloc(Type, block.params.items.len);
55085518 const comptime_params = try sema.arena.alloc(bool, block.params.items.len);
55095519 for (block.params.items) |param, i| {
5520 const param_src: LazySrcLoc = .{ .node_offset = src_node_offset }; // TODO better src
55105521 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);
55125524 is_generic = is_generic or comptime_params[i] or param.ty.tag() == .generic_poison;
55135525 }
55145526
5515 if (align_val.tag() != .null_value) {
5516 return sema.fail(block, src, "TODO implement support for function prototypes to have alignment specified", .{});
5517 }
5518
5519 is_generic = is_generic or bare_return_type.requiresComptime();
5527 is_generic = is_generic or
5528 try sema.typeRequiresComptime(block, ret_ty_src, bare_return_type);
55205529
55215530 const return_type = if (!inferred_error_set or bare_return_type.tag() == .generic_poison)
55225531 bare_return_type
......@@ -5537,6 +5546,7 @@ fn funcCommon(
55375546 .comptime_params = comptime_params.ptr,
55385547 .return_type = return_type,
55395548 .cc = cc,
5549 .alignment = alignment,
55405550 .is_var_args = var_args,
55415551 .is_generic = is_generic,
55425552 });
......@@ -5550,7 +5560,6 @@ fn funcCommon(
55505560 lib_name, @errorName(err),
55515561 });
55525562 };
5553 const target = mod.getTarget();
55545563 if (target_util.is_libc_lib_name(target, lib_name)) {
55555564 if (!mod.comp.bin_file.options.link_libc) {
55565565 return sema.fail(
......@@ -5591,12 +5600,7 @@ fn funcCommon(
55915600 }
55925601
55935602 if (body_inst == 0) {
5594 const fn_ptr_ty = try Type.ptr(sema.arena, .{
5595 .pointee_type = fn_ty,
5596 .@"addrspace" = .generic,
5597 .mutable = false,
5598 });
5599 return sema.addType(fn_ptr_ty);
5603 return sema.addType(fn_ty);
56005604 }
56015605
56025606 const is_inline = fn_ty.fnCallingConvention() == .Inline;
......@@ -5632,7 +5636,7 @@ fn zirParam(
56325636 sema: *Sema,
56335637 block: *Block,
56345638 inst: Zir.Inst.Index,
5635 is_comptime: bool,
5639 comptime_syntax: bool,
56365640) CompileError!void {
56375641 const inst_data = sema.code.instructions.items(.data)[inst].pl_tok;
56385642 const src = inst_data.src();
......@@ -5669,7 +5673,7 @@ fn zirParam(
56695673 // insert an anytype parameter.
56705674 try block.params.append(sema.gpa, .{
56715675 .ty = Type.initTag(.generic_poison),
5672 .is_comptime = is_comptime,
5676 .is_comptime = comptime_syntax,
56735677 });
56745678 try sema.inst_map.putNoClobber(sema.gpa, inst, .generic_poison);
56755679 return;
......@@ -5677,8 +5681,10 @@ fn zirParam(
56775681 else => |e| return e,
56785682 }
56795683 };
5684 const is_comptime = comptime_syntax or
5685 try sema.typeRequiresComptime(block, src, param_ty);
56805686 if (sema.inst_map.get(inst)) |arg| {
5681 if (is_comptime or param_ty.requiresComptime()) {
5687 if (is_comptime) {
56825688 // We have a comptime value for this parameter so it should be elided from the
56835689 // function type of the function instruction in this block.
56845690 const coerced_arg = try sema.coerce(block, param_ty, arg, src);
......@@ -5692,7 +5698,7 @@ fn zirParam(
56925698
56935699 try block.params.append(sema.gpa, .{
56945700 .ty = param_ty,
5695 .is_comptime = is_comptime or param_ty.requiresComptime(),
5701 .is_comptime = is_comptime,
56965702 });
56975703 const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison));
56985704 try sema.inst_map.putNoClobber(sema.gpa, inst, result);
......@@ -5702,9 +5708,10 @@ fn zirParamAnytype(
57025708 sema: *Sema,
57035709 block: *Block,
57045710 inst: Zir.Inst.Index,
5705 is_comptime: bool,
5711 comptime_syntax: bool,
57065712) CompileError!void {
57075713 const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
5714 const src = inst_data.src();
57085715 const param_name = inst_data.get(sema.code);
57095716
57105717 // TODO check if param_name shadows a Decl. This only needs to be done if
......@@ -5713,7 +5720,7 @@ fn zirParamAnytype(
57135720
57145721 if (sema.inst_map.get(inst)) |air_ref| {
57155722 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)) {
57175724 // We have a comptime value for this parameter so it should be elided from the
57185725 // function type of the function instruction in this block.
57195726 return;
......@@ -5730,7 +5737,7 @@ fn zirParamAnytype(
57305737
57315738 try block.params.append(sema.gpa, .{
57325739 .ty = Type.initTag(.generic_poison),
5733 .is_comptime = is_comptime,
5740 .is_comptime = comptime_syntax,
57345741 });
57355742 try sema.inst_map.put(sema.gpa, inst, .generic_poison);
57365743}
......@@ -11118,8 +11125,7 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1111811125
1111911126 const type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
1112011127 const type_res = try sema.resolveType(block, src, extra.lhs);
11121 if (type_res.zigTypeTag() != .Pointer)
11122 return sema.fail(block, type_src, "expected pointer, found '{}'", .{type_res});
11128 try sema.checkPtrType(block, type_src, type_res);
1112311129 const ptr_align = type_res.ptrAlignment(sema.mod.getTarget());
1112411130
1112511131 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
1117611182 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
1117711183 const operand = sema.resolveInst(extra.rhs);
1117811184 const operand_ty = sema.typeOf(operand);
11179 if (operand_ty.zigTypeTag() != .Pointer) {
11180 return sema.fail(block, operand_src, "expected pointer, found {s} type '{}'", .{
11181 @tagName(operand_ty.zigTypeTag()), operand_ty,
11182 });
11183 }
11184 if (dest_ty.zigTypeTag() != .Pointer) {
11185 return sema.fail(block, dest_ty_src, "expected pointer, found {s} type '{}'", .{
11186 @tagName(dest_ty.zigTypeTag()), dest_ty,
11187 });
11188 }
11185 try sema.checkPtrType(block, dest_ty_src, dest_ty);
11186 try sema.checkPtrOperand(block, operand_src, operand_ty);
1118911187 return sema.coerceCompatiblePtrs(block, dest_ty, operand, operand_src);
1119011188}
1119111189
......@@ -11264,7 +11262,7 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1126411262
1126511263 // TODO in addition to pointers, this instruction is supposed to work for
1126611264 // pointer-like optionals and slices.
11267 try sema.checkPtrType(block, ptr_src, ptr_ty);
11265 try sema.checkPtrOperand(block, ptr_src, ptr_ty);
1126811266
1126911267 // TODO compile error if the result pointer is comptime known and would have an
1127011268 // alignment that disagrees with the Decl's alignment.
......@@ -11462,6 +11460,34 @@ fn checkIntType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileEr
1146211460 }
1146311461}
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
1146511491fn checkPtrType(
1146611492 sema: *Sema,
1146711493 block: *Block,
......@@ -11470,6 +11496,22 @@ fn checkPtrType(
1147011496) CompileError!void {
1147111497 switch (ty.zigTypeTag()) {
1147211498 .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 },
1147311515 else => return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty}),
1147411516 }
1147511517}
......@@ -12139,20 +12181,14 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
1213912181 const dest_ptr = sema.resolveInst(extra.dest);
1214012182 const dest_ptr_ty = sema.typeOf(dest_ptr);
1214112183
12142 if (dest_ptr_ty.zigTypeTag() != .Pointer) {
12143 return sema.fail(block, dest_src, "expected pointer, found '{}'", .{dest_ptr_ty});
12144 }
12184 try sema.checkPtrOperand(block, dest_src, dest_ptr_ty);
1214512185 if (dest_ptr_ty.isConstPtr()) {
1214612186 return sema.fail(block, dest_src, "cannot store through const pointer '{}'", .{dest_ptr_ty});
1214712187 }
1214812188
1214912189 const uncasted_src_ptr = sema.resolveInst(extra.source);
1215012190 const uncasted_src_ptr_ty = sema.typeOf(uncasted_src_ptr);
12151 if (uncasted_src_ptr_ty.zigTypeTag() != .Pointer) {
12152 return sema.fail(block, src_src, "expected pointer, found '{}'", .{
12153 uncasted_src_ptr_ty,
12154 });
12155 }
12191 try sema.checkPtrOperand(block, src_src, uncasted_src_ptr_ty);
1215612192 const src_ptr_info = uncasted_src_ptr_ty.ptrInfo().data;
1215712193 const wanted_src_ptr_ty = try Type.ptr(sema.arena, .{
1215812194 .pointee_type = dest_ptr_ty.elemType2(),
......@@ -12203,9 +12239,7 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
1220312239 const len_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
1220412240 const dest_ptr = sema.resolveInst(extra.dest);
1220512241 const dest_ptr_ty = sema.typeOf(dest_ptr);
12206 if (dest_ptr_ty.zigTypeTag() != .Pointer) {
12207 return sema.fail(block, dest_src, "expected pointer, found '{}'", .{dest_ptr_ty});
12208 }
12242 try sema.checkPtrOperand(block, dest_src, dest_ptr_ty);
1220912243 if (dest_ptr_ty.isConstPtr()) {
1221012244 return sema.fail(block, dest_src, "cannot store through const pointer '{}'", .{dest_ptr_ty});
1221112245 }
......@@ -12487,7 +12521,7 @@ fn zirPrefetch(
1248712521 const opts_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
1248812522 const options_ty = try sema.getBuiltinType(block, opts_src, "PrefetchOptions");
1248912523 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));
1249112525 const options = try sema.coerce(block, options_ty, sema.resolveInst(extra.rhs), opts_src);
1249212526
1249312527 const rw = try sema.fieldVal(block, opts_src, options, "rw", opts_src);
......@@ -12568,12 +12602,15 @@ fn validateVarType(
1256812602 .Type,
1256912603 .Undefined,
1257012604 .Null,
12605 .Fn,
1257112606 => break,
1257212607
1257312608 .Pointer => {
1257412609 const elem_ty = ty.childType();
12575 if (elem_ty.zigTypeTag() == .Opaque) return;
12576 ty = elem_ty;
12610 switch (elem_ty.zigTypeTag()) {
12611 .Opaque, .Fn => return,
12612 else => ty = elem_ty,
12613 }
1257712614 },
1257812615 .Opaque => if (is_extern) return else break,
1257912616
......@@ -12586,9 +12623,9 @@ fn validateVarType(
1258612623
1258712624 .ErrorUnion => ty = ty.errorUnionPayload(),
1258812625
12589 .Fn, .Struct, .Union => {
12626 .Struct, .Union => {
1259012627 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
12591 if (resolved_ty.requiresComptime()) {
12628 if (try sema.typeRequiresComptime(block, src, resolved_ty)) {
1259212629 break;
1259312630 } else {
1259412631 return;
......@@ -12596,7 +12633,99 @@ fn validateVarType(
1259612633 },
1259712634 } 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 }
1260012729}
1260112730
1260212731pub const PanicId = enum {
......@@ -13883,6 +14012,10 @@ fn coerce(
1388314012 {
1388414013 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
1388514014 }
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;
1388614019 },
1388714020 .Int, .ComptimeInt => switch (inst_ty.zigTypeTag()) {
1388814021 .Float, .ComptimeFloat => float: {
......@@ -14683,7 +14816,8 @@ const ComptimePtrLoadKit = struct {
1468314816 /// The Type of the parent Value.
1468414817 ty: Type,
1468514818 /// 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,
1468714821 /// Whether the `root_val` could be mutated by further
1468814822 /// semantic analysis and a copy must be performed.
1468914823 is_mutable: bool,
......@@ -14738,12 +14872,24 @@ fn beginComptimePtrLoad(
1473814872 });
1473914873 }
1474014874 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 };
1474214888 return ComptimePtrLoadKit{
1474314889 .root_val = parent.root_val,
1474414890 .val = try parent.val.elemValue(sema.arena, elem_ptr.index),
1474514891 .ty = elem_ty,
14746 .byte_offset = try sema.usizeCast(block, src, parent.byte_offset + elem_size * elem_ptr.index),
14892 .byte_offset = byte_offset,
1474714893 .is_mutable = parent.is_mutable,
1474814894 };
1474914895 },
......@@ -14768,13 +14914,24 @@ fn beginComptimePtrLoad(
1476814914 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
1476914915 const parent = try beginComptimePtrLoad(sema, block, src, field_ptr.container_ptr);
1477014916 const field_index = @intCast(u32, field_ptr.field_index);
14771 try sema.resolveTypeLayout(block, src, parent.ty);
14772 const field_offset = parent.ty.structFieldOffset(field_index, target);
14917 const byte_offset: ?usize = bo: {
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 };
1477314930 return ComptimePtrLoadKit{
1477414931 .root_val = parent.root_val,
1477514932 .val = try parent.val.fieldValue(sema.arena, field_index),
1477614933 .ty = parent.ty.structFieldType(field_index),
14777 .byte_offset = try sema.usizeCast(block, src, parent.byte_offset + field_offset),
14934 .byte_offset = byte_offset,
1477814935 .is_mutable = parent.is_mutable,
1477914936 };
1478014937 },
......@@ -14785,7 +14942,7 @@ fn beginComptimePtrLoad(
1478514942 .root_val = parent.root_val,
1478614943 .val = parent.val.castTag(.eu_payload).?.data,
1478714944 .ty = parent.ty.errorUnionPayload(),
14788 .byte_offset = undefined,
14945 .byte_offset = null,
1478914946 .is_mutable = parent.is_mutable,
1479014947 };
1479114948 },
......@@ -14796,7 +14953,7 @@ fn beginComptimePtrLoad(
1479614953 .root_val = parent.root_val,
1479714954 .val = parent.val.castTag(.opt_payload).?.data,
1479814955 .ty = try parent.ty.optionalChildAlloc(sema.arena),
14799 .byte_offset = undefined,
14956 .byte_offset = null,
1480014957 .is_mutable = parent.is_mutable,
1480114958 };
1480214959 },
......@@ -16090,28 +16247,12 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp
1609016247 switch (ty.tag()) {
1609116248 .@"struct" => {
1609216249 const struct_obj = ty.castTag(.@"struct").?.data;
16093 switch (struct_obj.status) {
16094 .none => {},
16095 .field_types_wip => {
16096 return sema.fail(block, src, "struct {} depends on itself", .{ty});
16097 },
16098 .have_field_types,
16099 .have_layout,
16100 .layout_wip,
16101 .fully_resolved_wip,
16102 .fully_resolved,
16103 => return ty,
16104 }
16105
16106 struct_obj.status = .field_types_wip;
16107 try semaStructFields(sema.mod, struct_obj);
16108
16109 if (struct_obj.fields.count() == 0) {
16110 struct_obj.status = .have_layout;
16111 } else {
16112 struct_obj.status = .have_field_types;
16113 }
16114
16250 try sema.resolveTypeFieldsStruct(block, src, ty, struct_obj);
16251 return ty;
16252 },
16253 .@"union", .union_tagged => {
16254 const union_obj = ty.cast(Type.Payload.Union).?.data;
16255 try sema.resolveTypeFieldsUnion(block, src, ty, union_obj);
1611516256 return ty;
1611616257 },
1611716258 .type_info => return sema.resolveBuiltinTypeFields(block, src, "TypeInfo"),
......@@ -16126,29 +16267,63 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp
1612616267 .call_options => return sema.resolveBuiltinTypeFields(block, src, "CallOptions"),
1612716268 .prefetch_options => return sema.resolveBuiltinTypeFields(block, src, "PrefetchOptions"),
1612816269
16129 .@"union", .union_tagged => {
16130 const union_obj = ty.cast(Type.Payload.Union).?.data;
16131 switch (union_obj.status) {
16132 .none => {},
16133 .field_types_wip => {
16134 return sema.fail(block, src, "union {} depends on itself", .{ty});
16135 },
16136 .have_field_types,
16137 .have_layout,
16138 .layout_wip,
16139 .fully_resolved_wip,
16140 .fully_resolved,
16141 => return ty,
16142 }
16270 else => return ty,
16271 }
16272}
1614316273
16144 union_obj.status = .field_types_wip;
16145 try semaUnionFields(sema.mod, union_obj);
16146 union_obj.status = .have_field_types;
16274fn resolveTypeFieldsStruct(
16275 sema: *Sema,
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});
1614916315 },
16150 else => return ty,
16316 .have_field_types,
16317 .have_layout,
16318 .layout_wip,
16319 .fully_resolved_wip,
16320 .fully_resolved,
16321 => return,
1615116322 }
16323
16324 union_obj.status = .field_types_wip;
16325 try semaUnionFields(sema.mod, union_obj);
16326 union_obj.status = .have_field_types;
1615216327}
1615316328
1615416329fn resolveBuiltinTypeFields(
......@@ -17295,3 +17470,198 @@ fn typePtrOrOptionalPtrTy(
1729517470 else => return null,
1729617471 }
1729717472}
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 {
725725 llvm_fn.setFunctionCallConv(toLlvmCallConv(fn_info.cc, target));
726726 }
727727
728 if (fn_info.alignment != 0) {
729 llvm_fn.setAlignment(fn_info.alignment);
730 }
731
728732 // Function attributes that are independent of analysis results of the function body.
729733 dg.addCommonFnAttributes(llvm_fn);
730734
src/target.zig+9
......@@ -637,3 +637,12 @@ pub fn llvmMachineAbi(target: std.Target) ?[:0]const u8 {
637637 else => return null,
638638 }
639639}
640
641pub fn defaultFunctionAlignment(target: std.Target) u32 {
642 return switch (target.cpu.arch) {
643 .arm, .armeb => 4,
644 .aarch64, .aarch64_32, .aarch64_be => 4,
645 .riscv64 => 2,
646 else => 1,
647 };
648}
src/type.zig+48-181
......@@ -5,6 +5,7 @@ const Allocator = std.mem.Allocator;
55const Target = std.Target;
66const Module = @import("Module.zig");
77const log = std.log.scoped(.Type);
8const target_util = @import("target.zig");
89
910const file_struct = @This();
1011
......@@ -577,21 +578,36 @@ pub const Type = extern union {
577578 }
578579 },
579580 .Fn => {
580 if (!a.fnReturnType().eql(b.fnReturnType()))
581 const a_info = a.fnInfo();
582 const b_info = b.fnInfo();
583
584 if (!eql(a_info.return_type, b_info.return_type))
581585 return false;
582 if (a.fnCallingConvention() != b.fnCallingConvention())
586
587 if (a_info.cc != b_info.cc)
583588 return false;
584 const a_param_len = a.fnParamLen();
585 const b_param_len = b.fnParamLen();
586 if (a_param_len != b_param_len)
589
590 if (a_info.param_types.len != b_info.param_types.len)
587591 return false;
588 var i: usize = 0;
589 while (i < a_param_len) : (i += 1) {
590 if (!a.fnParamType(i).eql(b.fnParamType(i)))
592
593 for (a_info.param_types) |a_param_ty, i| {
594 const b_param_ty = b_info.param_types[i];
595 if (!eql(a_param_ty, b_param_ty))
596 return false;
597
598 if (a_info.comptime_params[i] != b_info.comptime_params[i])
591599 return false;
592600 }
593 if (a.fnIsVarArgs() != b.fnIsVarArgs())
601
602 if (a_info.alignment != b_info.alignment)
603 return false;
604
605 if (a_info.is_var_args != b_info.is_var_args)
594606 return false;
607
608 if (a_info.is_generic != b_info.is_generic)
609 return false;
610
595611 return true;
596612 },
597613 .Optional => {
......@@ -686,6 +702,7 @@ pub const Type = extern union {
686702 return false;
687703 },
688704 .Float => return a.tag() == b.tag(),
705
689706 .BoundFn,
690707 .Frame,
691708 => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }),
......@@ -937,6 +954,7 @@ pub const Type = extern union {
937954 .return_type = try payload.return_type.copy(allocator),
938955 .param_types = param_types,
939956 .cc = payload.cc,
957 .alignment = payload.alignment,
940958 .is_var_args = payload.is_var_args,
941959 .is_generic = payload.is_generic,
942960 .comptime_params = comptime_params.ptr,
......@@ -1114,9 +1132,15 @@ pub const Type = extern union {
11141132 }
11151133 try writer.writeAll("...");
11161134 }
1117 try writer.writeAll(") callconv(.");
1118 try writer.writeAll(@tagName(payload.cc));
11191135 try writer.writeAll(") ");
1136 if (payload.cc != .Unspecified) {
1137 try writer.writeAll("callconv(.");
1138 try writer.writeAll(@tagName(payload.cc));
1139 try writer.writeAll(") ");
1140 }
1141 if (payload.alignment != 0) {
1142 try writer.print("align({d}) ", .{payload.alignment});
1143 }
11201144 ty = payload.return_type;
11211145 continue;
11221146 },
......@@ -1423,170 +1447,6 @@ pub const Type = extern union {
14231447 }
14241448 }
14251449
1426 /// Anything that reports hasCodeGenBits() false returns false here as well.
1427 /// `generic_poison` will return false.
1428 pub fn requiresComptime(ty: Type) bool {
1429 return switch (ty.tag()) {
1430 .u1,
1431 .u8,
1432 .i8,
1433 .u16,
1434 .i16,
1435 .u32,
1436 .i32,
1437 .u64,
1438 .i64,
1439 .u128,
1440 .i128,
1441 .usize,
1442 .isize,
1443 .c_short,
1444 .c_ushort,
1445 .c_int,
1446 .c_uint,
1447 .c_long,
1448 .c_ulong,
1449 .c_longlong,
1450 .c_ulonglong,
1451 .c_longdouble,
1452 .f16,
1453 .f32,
1454 .f64,
1455 .f128,
1456 .anyopaque,
1457 .bool,
1458 .void,
1459 .anyerror,
1460 .noreturn,
1461 .@"anyframe",
1462 .@"null",
1463 .@"undefined",
1464 .atomic_order,
1465 .atomic_rmw_op,
1466 .calling_convention,
1467 .address_space,
1468 .float_mode,
1469 .reduce_op,
1470 .call_options,
1471 .prefetch_options,
1472 .export_options,
1473 .extern_options,
1474 .manyptr_u8,
1475 .manyptr_const_u8,
1476 .manyptr_const_u8_sentinel_0,
1477 .fn_noreturn_no_args,
1478 .fn_void_no_args,
1479 .fn_naked_noreturn_no_args,
1480 .fn_ccc_void_no_args,
1481 .const_slice_u8,
1482 .const_slice_u8_sentinel_0,
1483 .anyerror_void_error_union,
1484 .empty_struct_literal,
1485 .function,
1486 .empty_struct,
1487 .error_set,
1488 .error_set_single,
1489 .error_set_inferred,
1490 .error_set_merged,
1491 .@"opaque",
1492 .generic_poison,
1493 .array_u8,
1494 .array_u8_sentinel_0,
1495 .int_signed,
1496 .int_unsigned,
1497 .enum_simple,
1498 => false,
1499
1500 .single_const_pointer_to_comptime_int,
1501 .type,
1502 .comptime_int,
1503 .comptime_float,
1504 .enum_literal,
1505 .type_info,
1506 => true,
1507
1508 .var_args_param => unreachable,
1509 .inferred_alloc_mut => unreachable,
1510 .inferred_alloc_const => unreachable,
1511 .bound_fn => unreachable,
1512
1513 .array,
1514 .array_sentinel,
1515 .vector,
1516 .pointer,
1517 .single_const_pointer,
1518 .single_mut_pointer,
1519 .many_const_pointer,
1520 .many_mut_pointer,
1521 .c_const_pointer,
1522 .c_mut_pointer,
1523 .const_slice,
1524 .mut_slice,
1525 => return requiresComptime(childType(ty)),
1526
1527 .optional,
1528 .optional_single_mut_pointer,
1529 .optional_single_const_pointer,
1530 => {
1531 var buf: Payload.ElemType = undefined;
1532 return requiresComptime(optionalChild(ty, &buf));
1533 },
1534
1535 .tuple => {
1536 const tuple = ty.castTag(.tuple).?.data;
1537 for (tuple.types) |field_ty| {
1538 if (requiresComptime(field_ty)) {
1539 return true;
1540 }
1541 }
1542 return false;
1543 },
1544
1545 .@"struct" => {
1546 const struct_obj = ty.castTag(.@"struct").?.data;
1547 switch (struct_obj.requires_comptime) {
1548 .no, .wip => return false,
1549 .yes => return true,
1550 .unknown => {
1551 struct_obj.requires_comptime = .wip;
1552 for (struct_obj.fields.values()) |field| {
1553 if (requiresComptime(field.ty)) {
1554 struct_obj.requires_comptime = .yes;
1555 return true;
1556 }
1557 }
1558 struct_obj.requires_comptime = .no;
1559 return false;
1560 },
1561 }
1562 },
1563
1564 .@"union", .union_tagged => {
1565 const union_obj = ty.cast(Payload.Union).?.data;
1566 switch (union_obj.requires_comptime) {
1567 .no, .wip => return false,
1568 .yes => return true,
1569 .unknown => {
1570 union_obj.requires_comptime = .wip;
1571 for (union_obj.fields.values()) |field| {
1572 if (requiresComptime(field.ty)) {
1573 union_obj.requires_comptime = .yes;
1574 return true;
1575 }
1576 }
1577 union_obj.requires_comptime = .no;
1578 return false;
1579 },
1580 }
1581 },
1582
1583 .error_union => return requiresComptime(errorUnionPayload(ty)),
1584 .anyframe_T => return ty.castTag(.anyframe_T).?.data.requiresComptime(),
1585 .enum_numbered => return ty.castTag(.enum_numbered).?.data.tag_ty.requiresComptime(),
1586 .enum_full, .enum_nonexhaustive => return ty.cast(Payload.EnumFull).?.data.tag_ty.requiresComptime(),
1587 };
1588 }
1589
15901450 pub fn toValue(self: Type, allocator: Allocator) Allocator.Error!Value {
15911451 switch (self.tag()) {
15921452 .u1 => return Value.initTag(.u1_type),
......@@ -1918,12 +1778,13 @@ pub const Type = extern union {
19181778 .fn_void_no_args, // represents machine code; not a pointer
19191779 .fn_naked_noreturn_no_args, // represents machine code; not a pointer
19201780 .fn_ccc_void_no_args, // represents machine code; not a pointer
1921 .function, // represents machine code; not a pointer
1922 => return switch (target.cpu.arch) {
1923 .arm, .armeb => 4,
1924 .aarch64, .aarch64_32, .aarch64_be => 4,
1925 .riscv64 => 2,
1926 else => 1,
1781 => return target_util.defaultFunctionAlignment(target),
1782
1783 // represents machine code; not a pointer
1784 .function => {
1785 const alignment = self.castTag(.function).?.data.alignment;
1786 if (alignment != 0) return alignment;
1787 return target_util.defaultFunctionAlignment(target);
19271788 },
19281789
19291790 .i16, .u16 => return 2,
......@@ -3424,6 +3285,7 @@ pub const Type = extern union {
34243285 .comptime_params = undefined,
34253286 .return_type = initTag(.noreturn),
34263287 .cc = .Unspecified,
3288 .alignment = 0,
34273289 .is_var_args = false,
34283290 .is_generic = false,
34293291 },
......@@ -3432,6 +3294,7 @@ pub const Type = extern union {
34323294 .comptime_params = undefined,
34333295 .return_type = initTag(.void),
34343296 .cc = .Unspecified,
3297 .alignment = 0,
34353298 .is_var_args = false,
34363299 .is_generic = false,
34373300 },
......@@ -3440,6 +3303,7 @@ pub const Type = extern union {
34403303 .comptime_params = undefined,
34413304 .return_type = initTag(.noreturn),
34423305 .cc = .Naked,
3306 .alignment = 0,
34433307 .is_var_args = false,
34443308 .is_generic = false,
34453309 },
......@@ -3448,6 +3312,7 @@ pub const Type = extern union {
34483312 .comptime_params = undefined,
34493313 .return_type = initTag(.void),
34503314 .cc = .C,
3315 .alignment = 0,
34513316 .is_var_args = false,
34523317 .is_generic = false,
34533318 },
......@@ -4572,6 +4437,8 @@ pub const Type = extern union {
45724437 param_types: []Type,
45734438 comptime_params: [*]bool,
45744439 return_type: Type,
4440 /// If zero use default target function code alignment.
4441 alignment: u32,
45754442 cc: std.builtin.CallingConvention,
45764443 is_var_args: bool,
45774444 is_generic: bool,
src/value.zig+10-2
......@@ -1520,6 +1520,11 @@ pub const Value = extern union {
15201520 }
15211521 return true;
15221522 },
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 },
15231528 else => {},
15241529 }
15251530 } else if (a_tag == .null_value or b_tag == .null_value) {
......@@ -1573,6 +1578,7 @@ pub const Value = extern union {
15731578 pub fn hash(val: Value, ty: Type, hasher: *std.hash.Wyhash) void {
15741579 const zig_ty_tag = ty.zigTypeTag();
15751580 std.hash.autoHash(hasher, zig_ty_tag);
1581 if (val.isUndef()) return;
15761582
15771583 switch (zig_ty_tag) {
15781584 .BoundFn => unreachable, // TODO remove this from the language
......@@ -1694,7 +1700,8 @@ pub const Value = extern union {
16941700 union_obj.val.hash(active_field_ty, hasher);
16951701 },
16961702 .Fn => {
1697 @panic("TODO implement hashing function values");
1703 const func = val.castTag(.function).?.data;
1704 return std.hash.autoHash(hasher, func.owner_decl);
16981705 },
16991706 .Frame => {
17001707 @panic("TODO implement hashing frame values");
......@@ -1703,7 +1710,8 @@ pub const Value = extern union {
17031710 @panic("TODO implement hashing anyframe values");
17041711 },
17051712 .EnumLiteral => {
1706 @panic("TODO implement hashing enum literal values");
1713 const bytes = val.castTag(.enum_literal).?.data;
1714 hasher.update(bytes);
17071715 },
17081716 }
17091717 }
test/behavior.zig+9-12
......@@ -2,22 +2,23 @@ const builtin = @import("builtin");
22
33test {
44 // Tests that pass for stage1, llvm backend, C backend, wasm backend, arm backend and x86_64 backend.
5 _ = @import("behavior/align.zig");
6 _ = @import("behavior/array.zig");
7 _ = @import("behavior/bool.zig");
8 _ = @import("behavior/bugs/655.zig");
9 _ = @import("behavior/bugs/679.zig");
510 _ = @import("behavior/bugs/1111.zig");
611 _ = @import("behavior/bugs/2346.zig");
7 _ = @import("behavior/slice_sentinel_comptime.zig");
8 _ = @import("behavior/bugs/679.zig");
912 _ = @import("behavior/bugs/6850.zig");
13 _ = @import("behavior/cast.zig");
14 _ = @import("behavior/comptime_memory.zig");
1015 _ = @import("behavior/fn_in_struct_in_comptime.zig");
1116 _ = @import("behavior/hasdecl.zig");
1217 _ = @import("behavior/hasfield.zig");
1318 _ = @import("behavior/prefetch.zig");
1419 _ = @import("behavior/pub_enum.zig");
20 _ = @import("behavior/slice_sentinel_comptime.zig");
1521 _ = @import("behavior/type.zig");
16 _ = @import("behavior/bugs/655.zig");
17 _ = @import("behavior/bool.zig");
18 _ = @import("behavior/align.zig");
19 _ = @import("behavior/array.zig");
20 _ = @import("behavior/cast.zig");
2122
2223 if (builtin.zig_backend != .stage2_arm and builtin.zig_backend != .stage2_x86_64) {
2324 // Tests that pass for stage1, llvm backend, C backend, wasm backend.
......@@ -113,11 +114,7 @@ test {
113114 _ = @import("behavior/switch.zig");
114115 _ = @import("behavior/widening.zig");
115116
116 if (builtin.zig_backend != .stage1) {
117 // When all comptime_memory.zig tests pass, #9646 can be closed.
118 // _ = @import("behavior/comptime_memory.zig");
119 _ = @import("behavior/slice_stage2.zig");
120 } else {
117 if (builtin.zig_backend == .stage1) {
121118 // Tests that only pass for the stage1 backend.
122119 _ = @import("behavior/align_stage1.zig");
123120 if (builtin.os.tag != .wasi) {
test/behavior/align.zig+20
......@@ -181,3 +181,23 @@ test "page aligned array on stack" {
181181 try expect(number1 == 42);
182182 try expect(number2 == 43);
183183}
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;
33const builtin = @import("builtin");
44const native_arch = builtin.target.cpu.arch;
55
6fn derp() align(@sizeOf(usize) * 2) i32 {
7 return 1234;
8}
9fn noop1() align(1) void {}
10fn noop4() align(4) void {}
11
12test "function alignment" {
13 // function alignment is a compile error on wasm32/wasm64
14 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
15
16 try expect(derp() == 1234);
17 try expect(@TypeOf(noop1) == fn () align(1) void);
18 try expect(@TypeOf(noop4) == fn () align(4) void);
19 noop1();
20 noop4();
21}
22
236test "implicitly decreasing fn alignment" {
247 // function alignment is a compile error on wasm32/wasm64
258 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
test/behavior/basic.zig+3-1
......@@ -259,6 +259,8 @@ fn fB() []const u8 {
259259}
260260
261261test "call function pointer in struct" {
262 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
263
262264 try expect(mem.eql(u8, f3(true), "a"));
263265 try expect(mem.eql(u8, f3(false), "b"));
264266}
......@@ -276,7 +278,7 @@ fn f3(x: bool) []const u8 {
276278}
277279
278280const FnPtrWrapper = struct {
279 fn_ptr: fn () []const u8,
281 fn_ptr: *const fn () []const u8,
280282};
281283
282284test "const ptr from var variable" {
test/behavior/basic_llvm.zig+3-1
......@@ -205,9 +205,11 @@ test "multiline string literal is null terminated" {
205205}
206206
207207test "self reference through fn ptr field" {
208 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
209
208210 const S = struct {
209211 const A = struct {
210 f: fn (A) u8,
212 f: *const fn (A) u8,
211213 };
212214
213215 fn foo(a: A) u8 {
test/behavior/bugs/1500.zig+1-1
......@@ -2,7 +2,7 @@ const A = struct {
22 b: B,
33};
44
5const B = fn (A) void;
5const B = *const fn (A) void;
66
77test "allow these dependencies" {
88 var a: A = undefined;
test/behavior/bugs/3112.zig+4-1
......@@ -1,9 +1,10 @@
1const builtin = @import("builtin");
12const std = @import("std");
23const expect = std.testing.expect;
34
45const State = struct {
56 const Self = @This();
6 enter: fn (previous: ?Self) void,
7 enter: *const fn (previous: ?Self) void,
78};
89
910fn prev(p: ?State) void {
......@@ -11,6 +12,8 @@ fn prev(p: ?State) void {
1112}
1213
1314test "zig test crash" {
15 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
16
1417 var global: State = undefined;
1518 global.enter = prev;
1619 global.enter(null);
test/behavior/cast_llvm.zig+4-2
......@@ -47,12 +47,14 @@ fn incrementVoidPtrArray(array: ?*anyopaque, len: usize) void {
4747}
4848
4949test "compile time int to ptr of function" {
50 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
5051 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) return error.SkipZigTest; // TODO
52
5153 try foobar(FUNCTION_CONSTANT);
5254}
5355
5456pub const FUNCTION_CONSTANT = @intToPtr(PFN_void, maxInt(usize));
55pub const PFN_void = fn (*anyopaque) callconv(.C) void;
57pub const PFN_void = *const fn (*anyopaque) callconv(.C) void;
5658
5759fn foobar(func: PFN_void) !void {
5860 try std.testing.expect(@ptrToInt(func) == maxInt(usize));
......@@ -154,7 +156,7 @@ test "implicit cast *[0]T to E![]const u8" {
154156
155157var global_array: [4]u8 = undefined;
156158test "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);
158160 try expect(@ptrToInt(f) == @ptrToInt(&global_array));
159161}
160162
test/behavior/comptime_memory.zig+98-1
......@@ -1,8 +1,15 @@
1const endian = @import("builtin").cpu.arch.endian();
1const builtin = @import("builtin");
2const endian = builtin.cpu.arch.endian();
23const testing = @import("std").testing;
34const ptr_size = @sizeOf(usize);
45
56test "type pun signed and unsigned as single pointer" {
7 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
8 if (builtin.zig_backend != .stage1) {
9 // TODO https://github.com/ziglang/zig/issues/9646
10 return error.SkipZigTest;
11 }
12
613 comptime {
714 var x: u32 = 0;
815 const y = @ptrCast(*i32, &x);
......@@ -12,6 +19,12 @@ test "type pun signed and unsigned as single pointer" {
1219}
1320
1421test "type pun signed and unsigned as many pointer" {
22 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
23 if (builtin.zig_backend != .stage1) {
24 // TODO https://github.com/ziglang/zig/issues/9646
25 return error.SkipZigTest;
26 }
27
1528 comptime {
1629 var x: u32 = 0;
1730 const y = @ptrCast([*]i32, &x);
......@@ -21,6 +34,12 @@ test "type pun signed and unsigned as many pointer" {
2134}
2235
2336test "type pun signed and unsigned as array pointer" {
37 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
38 if (builtin.zig_backend != .stage1) {
39 // TODO https://github.com/ziglang/zig/issues/9646
40 return error.SkipZigTest;
41 }
42
2443 comptime {
2544 var x: u32 = 0;
2645 const y = @ptrCast(*[1]i32, &x);
......@@ -30,6 +49,12 @@ test "type pun signed and unsigned as array pointer" {
3049}
3150
3251test "type pun signed and unsigned as offset many pointer" {
52 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
53 if (builtin.zig_backend != .stage1) {
54 // TODO https://github.com/ziglang/zig/issues/9646
55 return error.SkipZigTest;
56 }
57
3358 comptime {
3459 var x: u32 = 0;
3560 var y = @ptrCast([*]i32, &x);
......@@ -40,6 +65,12 @@ test "type pun signed and unsigned as offset many pointer" {
4065}
4166
4267test "type pun signed and unsigned as array pointer" {
68 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
69 if (builtin.zig_backend != .stage1) {
70 // TODO https://github.com/ziglang/zig/issues/9646
71 return error.SkipZigTest;
72 }
73
4374 comptime {
4475 var x: u32 = 0;
4576 const y = @ptrCast([*]i32, &x) - 10;
......@@ -50,6 +81,12 @@ test "type pun signed and unsigned as array pointer" {
5081}
5182
5283test "type pun value and struct" {
84 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
85 if (builtin.zig_backend != .stage1) {
86 // TODO https://github.com/ziglang/zig/issues/9646
87 return error.SkipZigTest;
88 }
89
5390 comptime {
5491 const StructOfU32 = extern struct { x: u32 };
5592 var inst: StructOfU32 = .{ .x = 0 };
......@@ -64,6 +101,12 @@ fn bigToNativeEndian(comptime T: type, v: T) T {
64101 return if (endian == .Big) v else @byteSwap(T, v);
65102}
66103test "type pun endianness" {
104 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
105 if (builtin.zig_backend != .stage1) {
106 // TODO https://github.com/ziglang/zig/issues/9646
107 return error.SkipZigTest;
108 }
109
67110 comptime {
68111 const StructOfBytes = extern struct { x: [4]u8 };
69112 var inst: StructOfBytes = .{ .x = [4]u8{ 0, 0, 0, 0 } };
......@@ -155,6 +198,12 @@ fn doTypePunBitsTest(as_bits: *Bits) !void {
155198}
156199
157200test "type pun bits" {
201 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
202 if (builtin.zig_backend != .stage1) {
203 // TODO https://github.com/ziglang/zig/issues/9646
204 return error.SkipZigTest;
205 }
206
158207 comptime {
159208 var v: u32 = undefined;
160209 try doTypePunBitsTest(@ptrCast(*Bits, &v));
......@@ -167,6 +216,12 @@ const imports = struct {
167216
168217// Make sure lazy values work on their own, before getting into more complex tests
169218test "basic pointer preservation" {
219 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
220 if (builtin.zig_backend != .stage1) {
221 // TODO https://github.com/ziglang/zig/issues/9646
222 return error.SkipZigTest;
223 }
224
170225 comptime {
171226 const lazy_address = @ptrToInt(&imports.global_u32);
172227 try testing.expectEqual(@ptrToInt(&imports.global_u32), lazy_address);
......@@ -175,6 +230,12 @@ test "basic pointer preservation" {
175230}
176231
177232test "byte copy preserves linker value" {
233 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
234 if (builtin.zig_backend != .stage1) {
235 // TODO https://github.com/ziglang/zig/issues/9646
236 return error.SkipZigTest;
237 }
238
178239 const ct_value = comptime blk: {
179240 const lazy = &imports.global_u32;
180241 var result: *u32 = undefined;
......@@ -193,6 +254,12 @@ test "byte copy preserves linker value" {
193254}
194255
195256test "unordered byte copy preserves linker value" {
257 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
258 if (builtin.zig_backend != .stage1) {
259 // TODO https://github.com/ziglang/zig/issues/9646
260 return error.SkipZigTest;
261 }
262
196263 const ct_value = comptime blk: {
197264 const lazy = &imports.global_u32;
198265 var result: *u32 = undefined;
......@@ -212,6 +279,12 @@ test "unordered byte copy preserves linker value" {
212279}
213280
214281test "shuffle chunks of linker value" {
282 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
283 if (builtin.zig_backend != .stage1) {
284 // TODO https://github.com/ziglang/zig/issues/9646
285 return error.SkipZigTest;
286 }
287
215288 const lazy_address = @ptrToInt(&imports.global_u32);
216289 const shuffled1_rt = shuffle(lazy_address, Bits, ShuffledBits);
217290 const unshuffled1_rt = shuffle(shuffled1_rt, ShuffledBits, Bits);
......@@ -225,6 +298,12 @@ test "shuffle chunks of linker value" {
225298}
226299
227300test "dance on linker values" {
301 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
302 if (builtin.zig_backend != .stage1) {
303 // TODO https://github.com/ziglang/zig/issues/9646
304 return error.SkipZigTest;
305 }
306
228307 comptime {
229308 var arr: [2]usize = undefined;
230309 arr[0] = @ptrToInt(&imports.global_u32);
......@@ -251,6 +330,12 @@ test "dance on linker values" {
251330}
252331
253332test "offset array ptr by element size" {
333 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
334 if (builtin.zig_backend != .stage1) {
335 // TODO https://github.com/ziglang/zig/issues/9646
336 return error.SkipZigTest;
337 }
338
254339 comptime {
255340 const VirtualStruct = struct { x: u32 };
256341 var arr: [4]VirtualStruct = .{
......@@ -273,6 +358,12 @@ test "offset array ptr by element size" {
273358}
274359
275360test "offset instance by field size" {
361 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
362 if (builtin.zig_backend != .stage1) {
363 // TODO https://github.com/ziglang/zig/issues/9646
364 return error.SkipZigTest;
365 }
366
276367 comptime {
277368 const VirtualStruct = struct { x: u32, y: u32, z: u32, w: u32 };
278369 var inst = VirtualStruct{ .x = 0, .y = 1, .z = 2, .w = 3 };
......@@ -293,6 +384,12 @@ test "offset instance by field size" {
293384}
294385
295386test "offset field ptr by enclosing array element size" {
387 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
388 if (builtin.zig_backend != .stage1) {
389 // TODO https://github.com/ziglang/zig/issues/9646
390 return error.SkipZigTest;
391 }
392
296393 comptime {
297394 const VirtualStruct = struct { x: u32 };
298395 var arr: [4]VirtualStruct = .{
test/behavior/error.zig+1
......@@ -1,3 +1,4 @@
1const builtin = @import("builtin");
12const std = @import("std");
23const expect = std.testing.expect;
34const expectError = std.testing.expectError;
test/behavior/fn.zig+9-3
......@@ -57,7 +57,7 @@ test "assign inline fn to const variable" {
5757
5858inline fn inlineFn() void {}
5959
60fn outer(y: u32) fn (u32) u32 {
60fn outer(y: u32) *const fn (u32) u32 {
6161 const Y = @TypeOf(y);
6262 const st = struct {
6363 fn get(z: u32) u32 {
......@@ -68,6 +68,8 @@ fn outer(y: u32) fn (u32) u32 {
6868}
6969
7070test "return inner function which references comptime variable of outer function" {
71 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
72
7173 var func = outer(10);
7274 try expect(func(3) == 7);
7375}
......@@ -92,6 +94,8 @@ test "discard the result of a function that returns a struct" {
9294}
9395
9496test "inline function call that calls optional function pointer, return pointer at callsite interacts correctly with callsite return type" {
97 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
98
9599 const S = struct {
96100 field: u32,
97101
......@@ -113,7 +117,7 @@ test "inline function call that calls optional function pointer, return pointer
113117 return bar2.?();
114118 }
115119
116 var bar2: ?fn () u32 = null;
120 var bar2: ?*const fn () u32 = null;
117121
118122 fn actualFn() u32 {
119123 return 1234;
......@@ -135,8 +139,10 @@ fn fnWithUnreachable() noreturn {
135139}
136140
137141test "extern struct with stdcallcc fn pointer" {
142 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
143
138144 const S = extern struct {
139 ptr: fn () callconv(if (builtin.target.cpu.arch == .i386) .Stdcall else .C) i32,
145 ptr: *const fn () callconv(if (builtin.target.cpu.arch == .i386) .Stdcall else .C) i32,
140146
141147 fn foo() callconv(if (builtin.target.cpu.arch == .i386) .Stdcall else .C) i32 {
142148 return 1234;
test/behavior/inttoptr.zig+7-5
......@@ -1,14 +1,16 @@
11const builtin = @import("builtin");
22
3test "casting random address to function pointer" {
3test "casting integer address to function pointer" {
4 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
45 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) return error.SkipZigTest; // TODO
5 randomAddressToFunction();
6 comptime randomAddressToFunction();
6
7 addressToFunction();
8 comptime addressToFunction();
79}
810
9fn randomAddressToFunction() void {
11fn addressToFunction() void {
1012 var addr: usize = 0xdeadbeef;
11 _ = @intToPtr(fn () void, addr);
13 _ = @intToPtr(*const fn () void, addr);
1214}
1315
1416test "mutate through ptr initialized with constant intToPtr value" {
test/behavior/member_func.zig+8-2
......@@ -1,8 +1,10 @@
1const expect = @import("std").testing.expect;
1const builtin = @import("builtin");
2const std = @import("std");
3const expect = std.testing.expect;
24
35const HasFuncs = struct {
46 state: u32,
5 func_field: fn (u32) u32,
7 func_field: *const fn (u32) u32,
68
79 fn inc(self: *HasFuncs) void {
810 self.state += 1;
......@@ -25,6 +27,8 @@ const HasFuncs = struct {
2527};
2628
2729test "standard field calls" {
30 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
31
2832 try expect(HasFuncs.one(0) == 1);
2933 try expect(HasFuncs.two(0) == 2);
3034
......@@ -64,6 +68,8 @@ test "standard field calls" {
6468}
6569
6670test "@field field calls" {
71 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
72
6773 try expect(@field(HasFuncs, "one")(0) == 1);
6874 try expect(@field(HasFuncs, "two")(0) == 2);
6975
test/behavior/slice.zig+13
......@@ -1,3 +1,4 @@
1const builtin = @import("builtin");
12const std = @import("std");
23const expect = std.testing.expect;
34const expectEqualSlices = std.testing.expectEqualSlices;
......@@ -166,3 +167,15 @@ test "slicing zero length array" {
166167 try expect(mem.eql(u8, s1, ""));
167168 try expect(mem.eql(u32, s2, &[_]u32{}));
168169}
170
171const x = @intToPtr([*]i32, 0x1000)[0..0x500];
172const y = x[0x100..];
173test "compile time slice of pointer to hard coded address" {
174 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
175
176 try expect(@ptrToInt(x) == 0x1000);
177 try expect(x.len == 0x500);
178
179 try expect(@ptrToInt(y) == 0x1400);
180 try expect(y.len == 0x400);
181}
test/behavior/slice_stage2.zig deleted-12
......@@ -1,12 +0,0 @@
1const std = @import("std");
2const expect = std.testing.expect;
3
4const x = @intToPtr([*]i32, 0x1000)[0..0x500];
5const y = x[0x100..];
6test "compile time slice of pointer to hard coded address" {
7 try expect(@ptrToInt(x) == 0x1000);
8 try expect(x.len == 0x500);
9
10 try expect(@ptrToInt(y) == 0x1400);
11 try expect(y.len == 0x400);
12}
test/behavior/union.zig+4-1
......@@ -1,3 +1,4 @@
1const builtin = @import("builtin");
12const std = @import("std");
23const expect = std.testing.expect;
34const expectEqual = std.testing.expectEqual;
......@@ -166,8 +167,10 @@ test "union with specified enum tag" {
166167}
167168
168169test "packed union generates correctly aligned LLVM type" {
170 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
171
169172 const U = packed union {
170 f1: fn () error{TestUnexpectedResult}!void,
173 f1: *const fn () error{TestUnexpectedResult}!void,
171174 f2: u32,
172175 };
173176 var foo = [_]U{