authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-06-20 13:39:35+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-24 16:47:49-07:00
logbe0c69957e7489423606023ad820599652a60e15
treeda3b52a40593e6d55f718a344fb660f8348a63ae
parent13853bef0df3c90633021850cc6d6abaeea03282

compiler: remove destination type from cast builtins

Resolves: #5909

7 files changed, 680 insertions(+), 356 deletions(-)

src/AstGen.zig+162-53
...@@ -335,6 +335,32 @@ const ResultInfo = struct {...@@ -335,6 +335,32 @@ const ResultInfo = struct {
335 },335 },
336 }336 }
337 }337 }
338
339 /// Find the result type for a cast builtin given the result location.
340 /// If the location does not have a known result type, emits an error on
341 /// the given node.
342 fn resultType(rl: Loc, gz: *GenZir, node: Ast.Node.Index, builtin_name: []const u8) !Zir.Inst.Ref {
343 const astgen = gz.astgen;
344 switch (rl) {
345 .discard, .none, .ref, .inferred_ptr => {},
346 .ty, .coerced_ty => |ty_ref| return ty_ref,
347 .ptr => |ptr| {
348 const ptr_ty = try gz.addUnNode(.typeof, ptr.inst, node);
349 return gz.addUnNode(.elem_type, ptr_ty, node);
350 },
351 .block_ptr => |block_scope| {
352 if (block_scope.rl_ty_inst != .none) return block_scope.rl_ty_inst;
353 if (block_scope.break_result_info.rl == .ptr) {
354 const ptr_ty = try gz.addUnNode(.typeof, block_scope.break_result_info.rl.ptr.inst, node);
355 return gz.addUnNode(.elem_type, ptr_ty, node);
356 }
357 },
358 }
359
360 return astgen.failNodeNotes(node, "{s} must have a known result type", .{builtin_name}, &.{
361 try astgen.errNoteNode(node, "use @as to provide explicit result type", .{}),
362 });
363 }
338 };364 };
339365
340 const Context = enum {366 const Context = enum {
...@@ -2521,6 +2547,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2521,6 +2547,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2521 .array_type,2547 .array_type,
2522 .array_type_sentinel,2548 .array_type_sentinel,
2523 .elem_type_index,2549 .elem_type_index,
2550 .elem_type,
2524 .vector_type,2551 .vector_type,
2525 .indexable_ptr_len,2552 .indexable_ptr_len,
2526 .anyframe_type,2553 .anyframe_type,
...@@ -2662,7 +2689,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2662,7 +2689,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2662 .int_cast,2689 .int_cast,
2663 .ptr_cast,2690 .ptr_cast,
2664 .truncate,2691 .truncate,
2665 .align_cast,
2666 .has_decl,2692 .has_decl,
2667 .has_field,2693 .has_field,
2668 .clz,2694 .clz,
...@@ -7924,11 +7950,10 @@ fn bitCast(...@@ -7924,11 +7950,10 @@ fn bitCast(
7924 scope: *Scope,7950 scope: *Scope,
7925 ri: ResultInfo,7951 ri: ResultInfo,
7926 node: Ast.Node.Index,7952 node: Ast.Node.Index,
7927 lhs: Ast.Node.Index,7953 operand_node: Ast.Node.Index,
7928 rhs: Ast.Node.Index,
7929) InnerError!Zir.Inst.Ref {7954) InnerError!Zir.Inst.Ref {
7930 const dest_type = try reachableTypeExpr(gz, scope, lhs, node);7955 const dest_type = try ri.rl.resultType(gz, node, "@bitCast");
7931 const operand = try reachableExpr(gz, scope, .{ .rl = .none }, rhs, node);7956 const operand = try reachableExpr(gz, scope, .{ .rl = .none }, operand_node, node);
7932 const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{7957 const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{
7933 .lhs = dest_type,7958 .lhs = dest_type,
7934 .rhs = operand,7959 .rhs = operand,
...@@ -7936,6 +7961,116 @@ fn bitCast(...@@ -7936,6 +7961,116 @@ fn bitCast(
7936 return rvalue(gz, ri, result, node);7961 return rvalue(gz, ri, result, node);
7937}7962}
79387963
7964/// Handle one or more nested pointer cast builtins:
7965/// * @ptrCast
7966/// * @alignCast
7967/// * @addrSpaceCast
7968/// * @constCast
7969/// * @volatileCast
7970/// Any sequence of such builtins is treated as a single operation. This allowed
7971/// for sequences like `@ptrCast(@alignCast(ptr))` to work correctly despite the
7972/// intermediate result type being unknown.
7973fn ptrCast(
7974 gz: *GenZir,
7975 scope: *Scope,
7976 ri: ResultInfo,
7977 root_node: Ast.Node.Index,
7978) InnerError!Zir.Inst.Ref {
7979 const astgen = gz.astgen;
7980 const tree = astgen.tree;
7981 const main_tokens = tree.nodes.items(.main_token);
7982 const node_datas = tree.nodes.items(.data);
7983 const node_tags = tree.nodes.items(.tag);
7984
7985 var flags: Zir.Inst.FullPtrCastFlags = .{};
7986
7987 // Note that all pointer cast builtins have one parameter, so we only need
7988 // to handle `builtin_call_two`.
7989 var node = root_node;
7990 while (true) {
7991 switch (node_tags[node]) {
7992 .builtin_call_two, .builtin_call_two_comma => {},
7993 .grouped_expression => {
7994 // Handle the chaining even with redundant parentheses
7995 node = node_datas[node].lhs;
7996 continue;
7997 },
7998 else => break,
7999 }
8000
8001 if (node_datas[node].lhs == 0) break; // 0 args
8002 if (node_datas[node].rhs != 0) break; // 2 args
8003
8004 const builtin_token = main_tokens[node];
8005 const builtin_name = tree.tokenSlice(builtin_token);
8006 const info = BuiltinFn.list.get(builtin_name) orelse break;
8007 if (info.param_count != 1) break;
8008
8009 switch (info.tag) {
8010 else => break,
8011 inline .ptr_cast,
8012 .align_cast,
8013 .addrspace_cast,
8014 .const_cast,
8015 .volatile_cast,
8016 => |tag| {
8017 if (@field(flags, @tagName(tag))) {
8018 return astgen.failNode(node, "redundant {s}", .{builtin_name});
8019 }
8020 @field(flags, @tagName(tag)) = true;
8021 },
8022 }
8023
8024 node = node_datas[node].lhs;
8025 }
8026
8027 const flags_i = @bitCast(u5, flags);
8028 assert(flags_i != 0);
8029
8030 const ptr_only: Zir.Inst.FullPtrCastFlags = .{ .ptr_cast = true };
8031 if (flags_i == @bitCast(u5, ptr_only)) {
8032 // Special case: simpler representation
8033 return typeCast(gz, scope, ri, root_node, node, .ptr_cast, "@ptrCast");
8034 }
8035
8036 const no_result_ty_flags: Zir.Inst.FullPtrCastFlags = .{
8037 .const_cast = true,
8038 .volatile_cast = true,
8039 };
8040 if ((flags_i & ~@bitCast(u5, no_result_ty_flags)) == 0) {
8041 // Result type not needed
8042 const cursor = maybeAdvanceSourceCursorToMainToken(gz, root_node);
8043 const operand = try expr(gz, scope, .{ .rl = .none }, node);
8044 try emitDbgStmt(gz, cursor);
8045 const result = try gz.addExtendedPayloadSmall(.ptr_cast_no_dest, flags_i, Zir.Inst.UnNode{
8046 .node = gz.nodeIndexToRelative(root_node),
8047 .operand = operand,
8048 });
8049 return rvalue(gz, ri, result, root_node);
8050 }
8051
8052 // Full cast including result type
8053 const need_result_type_builtin = if (flags.ptr_cast)
8054 "@ptrCast"
8055 else if (flags.align_cast)
8056 "@alignCast"
8057 else if (flags.addrspace_cast)
8058 "@addrSpaceCast"
8059 else
8060 unreachable;
8061
8062 const cursor = maybeAdvanceSourceCursorToMainToken(gz, root_node);
8063 const result_type = try ri.rl.resultType(gz, root_node, need_result_type_builtin);
8064 const operand = try expr(gz, scope, .{ .rl = .none }, node);
8065 try emitDbgStmt(gz, cursor);
8066 const result = try gz.addExtendedPayloadSmall(.ptr_cast_full, flags_i, Zir.Inst.BinNode{
8067 .node = gz.nodeIndexToRelative(root_node),
8068 .lhs = result_type,
8069 .rhs = operand,
8070 });
8071 return rvalue(gz, ri, result, root_node);
8072}
8073
7939fn typeOf(8074fn typeOf(
7940 gz: *GenZir,8075 gz: *GenZir,
7941 scope: *Scope,8076 scope: *Scope,
...@@ -8123,7 +8258,7 @@ fn builtinCall(...@@ -8123,7 +8258,7 @@ fn builtinCall(
81238258
8124 // zig fmt: off8259 // zig fmt: off
8125 .as => return as( gz, scope, ri, node, params[0], params[1]),8260 .as => return as( gz, scope, ri, node, params[0], params[1]),
8126 .bit_cast => return bitCast( gz, scope, ri, node, params[0], params[1]),8261 .bit_cast => return bitCast( gz, scope, ri, node, params[0]),
8127 .TypeOf => return typeOf( gz, scope, ri, node, params),8262 .TypeOf => return typeOf( gz, scope, ri, node, params),
8128 .union_init => return unionInit(gz, scope, ri, node, params),8263 .union_init => return unionInit(gz, scope, ri, node, params),
8129 .c_import => return cImport( gz, scope, node, params[0]),8264 .c_import => return cImport( gz, scope, node, params[0]),
...@@ -8308,14 +8443,13 @@ fn builtinCall(...@@ -8308,14 +8443,13 @@ fn builtinCall(
8308 .Frame => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .frame_type),8443 .Frame => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .frame_type),
8309 .frame_size => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .frame_size),8444 .frame_size => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .frame_size),
83108445
8311 .int_from_float => return typeCast(gz, scope, ri, node, params[0], params[1], .int_from_float),8446 .int_from_float => return typeCast(gz, scope, ri, node, params[0], .int_from_float, builtin_name),
8312 .float_from_int => return typeCast(gz, scope, ri, node, params[0], params[1], .float_from_int),8447 .float_from_int => return typeCast(gz, scope, ri, node, params[0], .float_from_int, builtin_name),
8313 .ptr_from_int => return typeCast(gz, scope, ri, node, params[0], params[1], .ptr_from_int),8448 .ptr_from_int => return typeCast(gz, scope, ri, node, params[0], .ptr_from_int, builtin_name),
8314 .enum_from_int => return typeCast(gz, scope, ri, node, params[0], params[1], .enum_from_int),8449 .enum_from_int => return typeCast(gz, scope, ri, node, params[0], .enum_from_int, builtin_name),
8315 .float_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .float_cast),8450 .float_cast => return typeCast(gz, scope, ri, node, params[0], .float_cast, builtin_name),
8316 .int_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .int_cast),8451 .int_cast => return typeCast(gz, scope, ri, node, params[0], .int_cast, builtin_name),
8317 .ptr_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .ptr_cast),8452 .truncate => return typeCast(gz, scope, ri, node, params[0], .truncate, builtin_name),
8318 .truncate => return typeCast(gz, scope, ri, node, params[0], params[1], .truncate),
8319 // zig fmt: on8453 // zig fmt: on
83208454
8321 .Type => {8455 .Type => {
...@@ -8368,49 +8502,22 @@ fn builtinCall(...@@ -8368,49 +8502,22 @@ fn builtinCall(
8368 });8502 });
8369 return rvalue(gz, ri, result, node);8503 return rvalue(gz, ri, result, node);
8370 },8504 },
8371 .align_cast => {
8372 const dest_align = try comptimeExpr(gz, scope, align_ri, params[0]);
8373 const rhs = try expr(gz, scope, .{ .rl = .none }, params[1]);
8374 const result = try gz.addPlNode(.align_cast, node, Zir.Inst.Bin{
8375 .lhs = dest_align,
8376 .rhs = rhs,
8377 });
8378 return rvalue(gz, ri, result, node);
8379 },
8380 .err_set_cast => {8505 .err_set_cast => {
8381 try emitDbgNode(gz, node);8506 try emitDbgNode(gz, node);
83828507
8383 const result = try gz.addExtendedPayload(.err_set_cast, Zir.Inst.BinNode{8508 const result = try gz.addExtendedPayload(.err_set_cast, Zir.Inst.BinNode{
8384 .lhs = try typeExpr(gz, scope, params[0]),8509 .lhs = try ri.rl.resultType(gz, node, "@errSetCast"),
8385 .rhs = try expr(gz, scope, .{ .rl = .none }, params[1]),8510 .rhs = try expr(gz, scope, .{ .rl = .none }, params[0]),
8386 .node = gz.nodeIndexToRelative(node),8511 .node = gz.nodeIndexToRelative(node),
8387 });8512 });
8388 return rvalue(gz, ri, result, node);8513 return rvalue(gz, ri, result, node);
8389 },8514 },
8390 .addrspace_cast => {8515 .ptr_cast,
8391 const result = try gz.addExtendedPayload(.addrspace_cast, Zir.Inst.BinNode{8516 .align_cast,
8392 .lhs = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .address_space_type } }, params[0]),8517 .addrspace_cast,
8393 .rhs = try expr(gz, scope, .{ .rl = .none }, params[1]),8518 .const_cast,
8394 .node = gz.nodeIndexToRelative(node),8519 .volatile_cast,
8395 });8520 => return ptrCast(gz, scope, ri, node),
8396 return rvalue(gz, ri, result, node);
8397 },
8398 .const_cast => {
8399 const operand = try expr(gz, scope, .{ .rl = .none }, params[0]);
8400 const result = try gz.addExtendedPayload(.const_cast, Zir.Inst.UnNode{
8401 .node = gz.nodeIndexToRelative(node),
8402 .operand = operand,
8403 });
8404 return rvalue(gz, ri, result, node);
8405 },
8406 .volatile_cast => {
8407 const operand = try expr(gz, scope, .{ .rl = .none }, params[0]);
8408 const result = try gz.addExtendedPayload(.volatile_cast, Zir.Inst.UnNode{
8409 .node = gz.nodeIndexToRelative(node),
8410 .operand = operand,
8411 });
8412 return rvalue(gz, ri, result, node);
8413 },
84148521
8415 // zig fmt: off8522 // zig fmt: off
8416 .has_decl => return hasDeclOrField(gz, scope, ri, node, params[0], params[1], .has_decl),8523 .has_decl => return hasDeclOrField(gz, scope, ri, node, params[0], params[1], .has_decl),
...@@ -8725,13 +8832,13 @@ fn typeCast(...@@ -8725,13 +8832,13 @@ fn typeCast(
8725 scope: *Scope,8832 scope: *Scope,
8726 ri: ResultInfo,8833 ri: ResultInfo,
8727 node: Ast.Node.Index,8834 node: Ast.Node.Index,
8728 lhs_node: Ast.Node.Index,8835 operand_node: Ast.Node.Index,
8729 rhs_node: Ast.Node.Index,
8730 tag: Zir.Inst.Tag,8836 tag: Zir.Inst.Tag,
8837 builtin_name: []const u8,
8731) InnerError!Zir.Inst.Ref {8838) InnerError!Zir.Inst.Ref {
8732 const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);8839 const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
8733 const result_type = try typeExpr(gz, scope, lhs_node);8840 const result_type = try ri.rl.resultType(gz, node, builtin_name);
8734 const operand = try expr(gz, scope, .{ .rl = .none }, rhs_node);8841 const operand = try expr(gz, scope, .{ .rl = .none }, operand_node);
87358842
8736 try emitDbgStmt(gz, cursor);8843 try emitDbgStmt(gz, cursor);
8737 const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{8844 const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{
...@@ -9432,6 +9539,7 @@ fn nodeMayNeedMemoryLocation(tree: *const Ast, start_node: Ast.Node.Index, have_...@@ -9432,6 +9539,7 @@ fn nodeMayNeedMemoryLocation(tree: *const Ast, start_node: Ast.Node.Index, have_
9432 switch (builtin_info.needs_mem_loc) {9539 switch (builtin_info.needs_mem_loc) {
9433 .never => return false,9540 .never => return false,
9434 .always => return true,9541 .always => return true,
9542 .forward0 => node = node_datas[node].lhs,
9435 .forward1 => node = node_datas[node].rhs,9543 .forward1 => node = node_datas[node].rhs,
9436 }9544 }
9437 // Missing builtin arg is not a parsing error, expect an error later.9545 // Missing builtin arg is not a parsing error, expect an error later.
...@@ -9448,6 +9556,7 @@ fn nodeMayNeedMemoryLocation(tree: *const Ast, start_node: Ast.Node.Index, have_...@@ -9448,6 +9556,7 @@ fn nodeMayNeedMemoryLocation(tree: *const Ast, start_node: Ast.Node.Index, have_
9448 switch (builtin_info.needs_mem_loc) {9556 switch (builtin_info.needs_mem_loc) {
9449 .never => return false,9557 .never => return false,
9450 .always => return true,9558 .always => return true,
9559 .forward0 => node = params[0],
9451 .forward1 => node = params[1],9560 .forward1 => node = params[1],
9452 }9561 }
9453 // Missing builtin arg is not a parsing error, expect an error later.9562 // Missing builtin arg is not a parsing error, expect an error later.
src/Autodoc.zig-3
...@@ -1529,7 +1529,6 @@ fn walkInstruction(...@@ -1529,7 +1529,6 @@ fn walkInstruction(
1529 .int_cast,1529 .int_cast,
1530 .ptr_cast,1530 .ptr_cast,
1531 .truncate,1531 .truncate,
1532 .align_cast,
1533 .has_decl,1532 .has_decl,
1534 .has_field,1533 .has_field,
1535 .div_exact,1534 .div_exact,
...@@ -3024,8 +3023,6 @@ fn walkInstruction(...@@ -3024,8 +3023,6 @@ fn walkInstruction(
3024 .int_from_error,3023 .int_from_error,
3025 .error_from_int,3024 .error_from_int,
3026 .reify,3025 .reify,
3027 .const_cast,
3028 .volatile_cast,
3029 => {3026 => {
3030 const extra = file.zir.extraData(Zir.Inst.UnNode, extended.operand).data;3027 const extra = file.zir.extraData(Zir.Inst.UnNode, extended.operand).data;
3031 const bin_index = self.exprs.items.len;3028 const bin_index = self.exprs.items.len;
src/BuiltinFn.zig+15-13
...@@ -129,6 +129,8 @@ pub const MemLocRequirement = enum {...@@ -129,6 +129,8 @@ pub const MemLocRequirement = enum {
129 never,129 never,
130 /// The builtin always needs a memory location.130 /// The builtin always needs a memory location.
131 always,131 always,
132 /// The builtin forwards the question to argument at index 0.
133 forward0,
132 /// The builtin forwards the question to argument at index 1.134 /// The builtin forwards the question to argument at index 1.
133 forward1,135 forward1,
134};136};
...@@ -168,14 +170,14 @@ pub const list = list: {...@@ -168,14 +170,14 @@ pub const list = list: {
168 "@addrSpaceCast",170 "@addrSpaceCast",
169 .{171 .{
170 .tag = .addrspace_cast,172 .tag = .addrspace_cast,
171 .param_count = 2,173 .param_count = 1,
172 },174 },
173 },175 },
174 .{176 .{
175 "@alignCast",177 "@alignCast",
176 .{178 .{
177 .tag = .align_cast,179 .tag = .align_cast,
178 .param_count = 2,180 .param_count = 1,
179 },181 },
180 },182 },
181 .{183 .{
...@@ -226,8 +228,8 @@ pub const list = list: {...@@ -226,8 +228,8 @@ pub const list = list: {
226 "@bitCast",228 "@bitCast",
227 .{229 .{
228 .tag = .bit_cast,230 .tag = .bit_cast,
229 .needs_mem_loc = .forward1,231 .needs_mem_loc = .forward0,
230 .param_count = 2,232 .param_count = 1,
231 },233 },
232 },234 },
233 .{235 .{
...@@ -457,7 +459,7 @@ pub const list = list: {...@@ -457,7 +459,7 @@ pub const list = list: {
457 .{459 .{
458 .tag = .err_set_cast,460 .tag = .err_set_cast,
459 .eval_to_error = .always,461 .eval_to_error = .always,
460 .param_count = 2,462 .param_count = 1,
461 },463 },
462 },464 },
463 .{465 .{
...@@ -502,14 +504,14 @@ pub const list = list: {...@@ -502,14 +504,14 @@ pub const list = list: {
502 "@floatCast",504 "@floatCast",
503 .{505 .{
504 .tag = .float_cast,506 .tag = .float_cast,
505 .param_count = 2,507 .param_count = 1,
506 },508 },
507 },509 },
508 .{510 .{
509 "@intFromFloat",511 "@intFromFloat",
510 .{512 .{
511 .tag = .int_from_float,513 .tag = .int_from_float,
512 .param_count = 2,514 .param_count = 1,
513 },515 },
514 },516 },
515 .{517 .{
...@@ -572,14 +574,14 @@ pub const list = list: {...@@ -572,14 +574,14 @@ pub const list = list: {
572 "@intCast",574 "@intCast",
573 .{575 .{
574 .tag = .int_cast,576 .tag = .int_cast,
575 .param_count = 2,577 .param_count = 1,
576 },578 },
577 },579 },
578 .{580 .{
579 "@enumFromInt",581 "@enumFromInt",
580 .{582 .{
581 .tag = .enum_from_int,583 .tag = .enum_from_int,
582 .param_count = 2,584 .param_count = 1,
583 },585 },
584 },586 },
585 .{587 .{
...@@ -594,14 +596,14 @@ pub const list = list: {...@@ -594,14 +596,14 @@ pub const list = list: {
594 "@floatFromInt",596 "@floatFromInt",
595 .{597 .{
596 .tag = .float_from_int,598 .tag = .float_from_int,
597 .param_count = 2,599 .param_count = 1,
598 },600 },
599 },601 },
600 .{602 .{
601 "@ptrFromInt",603 "@ptrFromInt",
602 .{604 .{
603 .tag = .ptr_from_int,605 .tag = .ptr_from_int,
604 .param_count = 2,606 .param_count = 1,
605 },607 },
606 },608 },
607 .{609 .{
...@@ -685,7 +687,7 @@ pub const list = list: {...@@ -685,7 +687,7 @@ pub const list = list: {
685 "@ptrCast",687 "@ptrCast",
686 .{688 .{
687 .tag = .ptr_cast,689 .tag = .ptr_cast,
688 .param_count = 2,690 .param_count = 1,
689 },691 },
690 },692 },
691 .{693 .{
...@@ -938,7 +940,7 @@ pub const list = list: {...@@ -938,7 +940,7 @@ pub const list = list: {
938 "@truncate",940 "@truncate",
939 .{941 .{
940 .tag = .truncate,942 .tag = .truncate,
941 .param_count = 2,943 .param_count = 1,
942 },944 },
943 },945 },
944 .{946 .{
src/Sema.zig+443-264
...@@ -960,6 +960,7 @@ fn analyzeBodyInner(...@@ -960,6 +960,7 @@ fn analyzeBodyInner(
960 .elem_val => try sema.zirElemVal(block, inst),960 .elem_val => try sema.zirElemVal(block, inst),
961 .elem_val_node => try sema.zirElemValNode(block, inst),961 .elem_val_node => try sema.zirElemValNode(block, inst),
962 .elem_type_index => try sema.zirElemTypeIndex(block, inst),962 .elem_type_index => try sema.zirElemTypeIndex(block, inst),
963 .elem_type => try sema.zirElemType(block, inst),
963 .enum_literal => try sema.zirEnumLiteral(block, inst),964 .enum_literal => try sema.zirEnumLiteral(block, inst),
964 .int_from_enum => try sema.zirIntFromEnum(block, inst),965 .int_from_enum => try sema.zirIntFromEnum(block, inst),
965 .enum_from_int => try sema.zirEnumFromInt(block, inst),966 .enum_from_int => try sema.zirEnumFromInt(block, inst),
...@@ -1044,7 +1045,6 @@ fn analyzeBodyInner(...@@ -1044,7 +1045,6 @@ fn analyzeBodyInner(
1044 .int_cast => try sema.zirIntCast(block, inst),1045 .int_cast => try sema.zirIntCast(block, inst),
1045 .ptr_cast => try sema.zirPtrCast(block, inst),1046 .ptr_cast => try sema.zirPtrCast(block, inst),
1046 .truncate => try sema.zirTruncate(block, inst),1047 .truncate => try sema.zirTruncate(block, inst),
1047 .align_cast => try sema.zirAlignCast(block, inst),
1048 .has_decl => try sema.zirHasDecl(block, inst),1048 .has_decl => try sema.zirHasDecl(block, inst),
1049 .has_field => try sema.zirHasField(block, inst),1049 .has_field => try sema.zirHasField(block, inst),
1050 .byte_swap => try sema.zirByteSwap(block, inst),1050 .byte_swap => try sema.zirByteSwap(block, inst),
...@@ -1172,13 +1172,12 @@ fn analyzeBodyInner(...@@ -1172,13 +1172,12 @@ fn analyzeBodyInner(
1172 .reify => try sema.zirReify( block, extended, inst),1172 .reify => try sema.zirReify( block, extended, inst),
1173 .builtin_async_call => try sema.zirBuiltinAsyncCall( block, extended),1173 .builtin_async_call => try sema.zirBuiltinAsyncCall( block, extended),
1174 .cmpxchg => try sema.zirCmpxchg( block, extended),1174 .cmpxchg => try sema.zirCmpxchg( block, extended),
1175 .addrspace_cast => try sema.zirAddrSpaceCast( block, extended),
1176 .c_va_arg => try sema.zirCVaArg( block, extended),1175 .c_va_arg => try sema.zirCVaArg( block, extended),
1177 .c_va_copy => try sema.zirCVaCopy( block, extended),1176 .c_va_copy => try sema.zirCVaCopy( block, extended),
1178 .c_va_end => try sema.zirCVaEnd( block, extended),1177 .c_va_end => try sema.zirCVaEnd( block, extended),
1179 .c_va_start => try sema.zirCVaStart( block, extended),1178 .c_va_start => try sema.zirCVaStart( block, extended),
1180 .const_cast, => try sema.zirConstCast( block, extended),1179 .ptr_cast_full => try sema.zirPtrCastFull( block, extended),
1181 .volatile_cast, => try sema.zirVolatileCast( block, extended),1180 .ptr_cast_no_dest => try sema.zirPtrCastNoDest( block, extended),
1182 .work_item_id => try sema.zirWorkItem( block, extended, extended.opcode),1181 .work_item_id => try sema.zirWorkItem( block, extended, extended.opcode),
1183 .work_group_size => try sema.zirWorkItem( block, extended, extended.opcode),1182 .work_group_size => try sema.zirWorkItem( block, extended, extended.opcode),
1184 .work_group_id => try sema.zirWorkItem( block, extended, extended.opcode),1183 .work_group_id => try sema.zirWorkItem( block, extended, extended.opcode),
...@@ -1821,6 +1820,24 @@ pub fn resolveType(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Ins...@@ -1821,6 +1820,24 @@ pub fn resolveType(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Ins
1821 return ty;1820 return ty;
1822}1821}
18231822
1823fn resolveCastDestType(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref, builtin_name: []const u8) !Type {
1824 return sema.resolveType(block, src, zir_ref) catch |err| switch (err) {
1825 error.GenericPoison => {
1826 // Cast builtins use their result type as the destination type, but
1827 // it could be an anytype argument, which we can't catch in AstGen.
1828 const msg = msg: {
1829 const msg = try sema.errMsg(block, src, "{s} must have a known result type", .{builtin_name});
1830 errdefer msg.destroy(sema.gpa);
1831 try sema.errNote(block, src, msg, "result type is unknown due to anytype parameter", .{});
1832 try sema.errNote(block, src, msg, "use @as to provide explicit result type", .{});
1833 break :msg msg;
1834 };
1835 return sema.failWithOwnedErrorMsg(msg);
1836 },
1837 else => |e| return e,
1838 };
1839}
1840
1824fn analyzeAsType(1841fn analyzeAsType(
1825 sema: *Sema,1842 sema: *Sema,
1826 block: *Block,1843 block: *Block,
...@@ -7953,6 +7970,14 @@ fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr...@@ -7953,6 +7970,14 @@ fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
7953 }7970 }
7954}7971}
79557972
7973fn zirElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
7974 const mod = sema.mod;
7975 const un_node = sema.code.instructions.items(.data)[inst].un_node;
7976 const ptr_ty = try sema.resolveType(block, .unneeded, un_node.operand);
7977 assert(ptr_ty.zigTypeTag(mod) == .Pointer); // validated by a previous instruction
7978 return sema.addType(ptr_ty.childType(mod));
7979}
7980
7956fn zirVectorType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {7981fn zirVectorType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
7957 const mod = sema.mod;7982 const mod = sema.mod;
7958 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;7983 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
...@@ -8278,13 +8303,12 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -8278,13 +8303,12 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
8278 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;8303 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
8279 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;8304 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
8280 const src = inst_data.src();8305 const src = inst_data.src();
8281 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };8306 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
8282 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };8307 const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, "@enumFromInt");
8283 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
8284 const operand = try sema.resolveInst(extra.rhs);8308 const operand = try sema.resolveInst(extra.rhs);
82858309
8286 if (dest_ty.zigTypeTag(mod) != .Enum) {8310 if (dest_ty.zigTypeTag(mod) != .Enum) {
8287 return sema.fail(block, dest_ty_src, "expected enum, found '{}'", .{dest_ty.fmt(mod)});8311 return sema.fail(block, src, "expected enum, found '{}'", .{dest_ty.fmt(mod)});
8288 }8312 }
8289 _ = try sema.checkIntType(block, operand_src, sema.typeOf(operand));8313 _ = try sema.checkIntType(block, operand_src, sema.typeOf(operand));
82908314
...@@ -9572,14 +9596,14 @@ fn zirIntCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -9572,14 +9596,14 @@ fn zirIntCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
9572 defer tracy.end();9596 defer tracy.end();
95739597
9574 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;9598 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
9575 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };9599 const src = inst_data.src();
9576 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };9600 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
9577 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;9601 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
95789602
9579 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);9603 const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, "@intCast");
9580 const operand = try sema.resolveInst(extra.rhs);9604 const operand = try sema.resolveInst(extra.rhs);
95819605
9582 return sema.intCast(block, inst_data.src(), dest_ty, dest_ty_src, operand, operand_src, true);9606 return sema.intCast(block, inst_data.src(), dest_ty, src, operand, operand_src, true);
9583}9607}
95849608
9585fn intCast(9609fn intCast(
...@@ -9733,11 +9757,11 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -9733,11 +9757,11 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
97339757
9734 const mod = sema.mod;9758 const mod = sema.mod;
9735 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;9759 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
9736 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };9760 const src = inst_data.src();
9737 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };9761 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
9738 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;9762 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
97399763
9740 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);9764 const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, "@bitCast");
9741 const operand = try sema.resolveInst(extra.rhs);9765 const operand = try sema.resolveInst(extra.rhs);
9742 const operand_ty = sema.typeOf(operand);9766 const operand_ty = sema.typeOf(operand);
9743 switch (dest_ty.zigTypeTag(mod)) {9767 switch (dest_ty.zigTypeTag(mod)) {
...@@ -9756,14 +9780,14 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -9756,14 +9780,14 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
9756 .Type,9780 .Type,
9757 .Undefined,9781 .Undefined,
9758 .Void,9782 .Void,
9759 => return sema.fail(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(mod)}),9783 => return sema.fail(block, src, "cannot @bitCast to '{}'", .{dest_ty.fmt(mod)}),
97609784
9761 .Enum => {9785 .Enum => {
9762 const msg = msg: {9786 const msg = msg: {
9763 const msg = try sema.errMsg(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(mod)});9787 const msg = try sema.errMsg(block, src, "cannot @bitCast to '{}'", .{dest_ty.fmt(mod)});
9764 errdefer msg.destroy(sema.gpa);9788 errdefer msg.destroy(sema.gpa);
9765 switch (operand_ty.zigTypeTag(mod)) {9789 switch (operand_ty.zigTypeTag(mod)) {
9766 .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @enumFromInt to cast from '{}'", .{operand_ty.fmt(mod)}),9790 .Int, .ComptimeInt => try sema.errNote(block, src, msg, "use @enumFromInt to cast from '{}'", .{operand_ty.fmt(mod)}),
9767 else => {},9791 else => {},
9768 }9792 }
97699793
...@@ -9774,11 +9798,11 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -9774,11 +9798,11 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
97749798
9775 .Pointer => {9799 .Pointer => {
9776 const msg = msg: {9800 const msg = msg: {
9777 const msg = try sema.errMsg(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(mod)});9801 const msg = try sema.errMsg(block, src, "cannot @bitCast to '{}'", .{dest_ty.fmt(mod)});
9778 errdefer msg.destroy(sema.gpa);9802 errdefer msg.destroy(sema.gpa);
9779 switch (operand_ty.zigTypeTag(mod)) {9803 switch (operand_ty.zigTypeTag(mod)) {
9780 .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @ptrFromInt to cast from '{}'", .{operand_ty.fmt(mod)}),9804 .Int, .ComptimeInt => try sema.errNote(block, src, msg, "use @ptrFromInt to cast from '{}'", .{operand_ty.fmt(mod)}),
9781 .Pointer => try sema.errNote(block, dest_ty_src, msg, "use @ptrCast to cast from '{}'", .{operand_ty.fmt(mod)}),9805 .Pointer => try sema.errNote(block, src, msg, "use @ptrCast to cast from '{}'", .{operand_ty.fmt(mod)}),
9782 else => {},9806 else => {},
9783 }9807 }
97849808
...@@ -9792,7 +9816,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -9792,7 +9816,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
9792 .Union => "union",9816 .Union => "union",
9793 else => unreachable,9817 else => unreachable,
9794 };9818 };
9795 return sema.fail(block, dest_ty_src, "cannot @bitCast to '{}'; {s} does not have a guaranteed in-memory layout", .{9819 return sema.fail(block, src, "cannot @bitCast to '{}'; {s} does not have a guaranteed in-memory layout", .{
9796 dest_ty.fmt(mod), container,9820 dest_ty.fmt(mod), container,
9797 });9821 });
9798 },9822 },
...@@ -9876,11 +9900,11 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -9876,11 +9900,11 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
98769900
9877 const mod = sema.mod;9901 const mod = sema.mod;
9878 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;9902 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
9879 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };9903 const src = inst_data.src();
9880 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };9904 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
9881 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;9905 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
98829906
9883 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);9907 const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, "@floatCast");
9884 const operand = try sema.resolveInst(extra.rhs);9908 const operand = try sema.resolveInst(extra.rhs);
98859909
9886 const target = mod.getTarget();9910 const target = mod.getTarget();
...@@ -9889,7 +9913,7 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -9889,7 +9913,7 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
9889 .Float => false,9913 .Float => false,
9890 else => return sema.fail(9914 else => return sema.fail(
9891 block,9915 block,
9892 dest_ty_src,9916 src,
9893 "expected float type, found '{}'",9917 "expected float type, found '{}'",
9894 .{dest_ty.fmt(mod)},9918 .{dest_ty.fmt(mod)},
9895 ),9919 ),
...@@ -20552,50 +20576,6 @@ fn reifyStruct(...@@ -20552,50 +20576,6 @@ fn reifyStruct(
20552 return decl_val;20576 return decl_val;
20553}20577}
2055420578
20555fn zirAddrSpaceCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
20556 const mod = sema.mod;
20557 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
20558 const src = LazySrcLoc.nodeOffset(extra.node);
20559 const addrspace_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
20560 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
20561
20562 const dest_addrspace = try sema.analyzeAddressSpace(block, addrspace_src, extra.lhs, .pointer);
20563 const ptr = try sema.resolveInst(extra.rhs);
20564 const ptr_ty = sema.typeOf(ptr);
20565
20566 try sema.checkPtrOperand(block, ptr_src, ptr_ty);
20567
20568 var ptr_info = ptr_ty.ptrInfo(mod);
20569 const src_addrspace = ptr_info.flags.address_space;
20570 if (!target_util.addrSpaceCastIsValid(sema.mod.getTarget(), src_addrspace, dest_addrspace)) {
20571 const msg = msg: {
20572 const msg = try sema.errMsg(block, src, "invalid address space cast", .{});
20573 errdefer msg.destroy(sema.gpa);
20574 try sema.errNote(block, src, msg, "address space '{s}' is not compatible with address space '{s}'", .{ @tagName(src_addrspace), @tagName(dest_addrspace) });
20575 break :msg msg;
20576 };
20577 return sema.failWithOwnedErrorMsg(msg);
20578 }
20579
20580 ptr_info.flags.address_space = dest_addrspace;
20581 const dest_ptr_ty = try mod.ptrType(ptr_info);
20582 const dest_ty = if (ptr_ty.zigTypeTag(mod) == .Optional)
20583 try mod.optionalType(dest_ptr_ty.toIntern())
20584 else
20585 dest_ptr_ty;
20586
20587 try sema.requireRuntimeBlock(block, src, ptr_src);
20588 // TODO: Address space cast safety?
20589
20590 return block.addInst(.{
20591 .tag = .addrspace_cast,
20592 .data = .{ .ty_op = .{
20593 .ty = try sema.addType(dest_ty),
20594 .operand = ptr,
20595 } },
20596 });
20597}
20598
20599fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref {20579fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref {
20600 const va_list_ty = try sema.getBuiltinType("VaList");20580 const va_list_ty = try sema.getBuiltinType("VaList");
20601 const va_list_ptr = try sema.mod.singleMutPtrType(va_list_ty);20581 const va_list_ptr = try sema.mod.singleMutPtrType(va_list_ty);
...@@ -20711,14 +20691,14 @@ fn zirFrameSize(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -20711,14 +20691,14 @@ fn zirFrameSize(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
20711fn zirIntFromFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {20691fn zirIntFromFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
20712 const mod = sema.mod;20692 const mod = sema.mod;
20713 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;20693 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
20694 const src = inst_data.src();
20714 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;20695 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
20715 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };20696 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
20716 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };20697 const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, "@intFromFloat");
20717 const dest_ty = try sema.resolveType(block, ty_src, extra.lhs);
20718 const operand = try sema.resolveInst(extra.rhs);20698 const operand = try sema.resolveInst(extra.rhs);
20719 const operand_ty = sema.typeOf(operand);20699 const operand_ty = sema.typeOf(operand);
2072020700
20721 _ = try sema.checkIntType(block, ty_src, dest_ty);20701 _ = try sema.checkIntType(block, src, dest_ty);
20722 try sema.checkFloatType(block, operand_src, operand_ty);20702 try sema.checkFloatType(block, operand_src, operand_ty);
2072320703
20724 if (try sema.resolveMaybeUndefVal(operand)) |val| {20704 if (try sema.resolveMaybeUndefVal(operand)) |val| {
...@@ -20751,14 +20731,14 @@ fn zirIntFromFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro...@@ -20751,14 +20731,14 @@ fn zirIntFromFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
20751fn zirFloatFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {20731fn zirFloatFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
20752 const mod = sema.mod;20732 const mod = sema.mod;
20753 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;20733 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
20734 const src = inst_data.src();
20754 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;20735 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
20755 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };20736 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
20756 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };20737 const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, "@floatFromInt");
20757 const dest_ty = try sema.resolveType(block, ty_src, extra.lhs);
20758 const operand = try sema.resolveInst(extra.rhs);20738 const operand = try sema.resolveInst(extra.rhs);
20759 const operand_ty = sema.typeOf(operand);20739 const operand_ty = sema.typeOf(operand);
2076020740
20761 try sema.checkFloatType(block, ty_src, dest_ty);20741 try sema.checkFloatType(block, src, dest_ty);
20762 _ = try sema.checkIntType(block, operand_src, operand_ty);20742 _ = try sema.checkIntType(block, operand_src, operand_ty);
2076320743
20764 if (try sema.resolveMaybeUndefVal(operand)) |val| {20744 if (try sema.resolveMaybeUndefVal(operand)) |val| {
...@@ -20779,21 +20759,20 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -20779,21 +20759,20 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
2077920759
20780 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;20760 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
2078120761
20782 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };20762 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
20783 const operand_res = try sema.resolveInst(extra.rhs);20763 const operand_res = try sema.resolveInst(extra.rhs);
20784 const operand_coerced = try sema.coerce(block, Type.usize, operand_res, operand_src);20764 const operand_coerced = try sema.coerce(block, Type.usize, operand_res, operand_src);
2078520765
20786 const type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };20766 const ptr_ty = try sema.resolveCastDestType(block, src, extra.lhs, "@ptrFromInt");
20787 const ptr_ty = try sema.resolveType(block, src, extra.lhs);20767 try sema.checkPtrType(block, src, ptr_ty);
20788 try sema.checkPtrType(block, type_src, ptr_ty);
20789 const elem_ty = ptr_ty.elemType2(mod);20768 const elem_ty = ptr_ty.elemType2(mod);
20790 const ptr_align = try ptr_ty.ptrAlignmentAdvanced(mod, sema);20769 const ptr_align = try ptr_ty.ptrAlignmentAdvanced(mod, sema);
2079120770
20792 if (ptr_ty.isSlice(mod)) {20771 if (ptr_ty.isSlice(mod)) {
20793 const msg = msg: {20772 const msg = msg: {
20794 const msg = try sema.errMsg(block, type_src, "integer cannot be converted to slice type '{}'", .{ptr_ty.fmt(sema.mod)});20773 const msg = try sema.errMsg(block, src, "integer cannot be converted to slice type '{}'", .{ptr_ty.fmt(sema.mod)});
20795 errdefer msg.destroy(sema.gpa);20774 errdefer msg.destroy(sema.gpa);
20796 try sema.errNote(block, type_src, msg, "slice length cannot be inferred from address", .{});20775 try sema.errNote(block, src, msg, "slice length cannot be inferred from address", .{});
20797 break :msg msg;20776 break :msg msg;
20798 };20777 };
20799 return sema.failWithOwnedErrorMsg(msg);20778 return sema.failWithOwnedErrorMsg(msg);
...@@ -20841,12 +20820,11 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat...@@ -20841,12 +20820,11 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
20841 const ip = &mod.intern_pool;20820 const ip = &mod.intern_pool;
20842 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;20821 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
20843 const src = LazySrcLoc.nodeOffset(extra.node);20822 const src = LazySrcLoc.nodeOffset(extra.node);
20844 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };20823 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
20845 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };20824 const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, "@errSetCast");
20846 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
20847 const operand = try sema.resolveInst(extra.rhs);20825 const operand = try sema.resolveInst(extra.rhs);
20848 const operand_ty = sema.typeOf(operand);20826 const operand_ty = sema.typeOf(operand);
20849 try sema.checkErrorSetType(block, dest_ty_src, dest_ty);20827 try sema.checkErrorSetType(block, src, dest_ty);
20850 try sema.checkErrorSetType(block, operand_src, operand_ty);20828 try sema.checkErrorSetType(block, operand_src, operand_ty);
2085120829
20852 // operand must be defined since it can be an invalid error value20830 // operand must be defined since it can be an invalid error value
...@@ -20869,7 +20847,7 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat...@@ -20869,7 +20847,7 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
20869 break :disjoint true;20847 break :disjoint true;
20870 }20848 }
2087120849
20872 try sema.resolveInferredErrorSetTy(block, dest_ty_src, dest_ty);20850 try sema.resolveInferredErrorSetTy(block, src, dest_ty);
20873 try sema.resolveInferredErrorSetTy(block, operand_src, operand_ty);20851 try sema.resolveInferredErrorSetTy(block, operand_src, operand_ty);
20874 for (dest_ty.errorSetNames(mod)) |dest_err_name| {20852 for (dest_ty.errorSetNames(mod)) |dest_err_name| {
20875 if (Type.errorSetHasFieldIp(ip, operand_ty.toIntern(), dest_err_name))20853 if (Type.errorSetHasFieldIp(ip, operand_ty.toIntern(), dest_err_name))
...@@ -20924,159 +20902,415 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat...@@ -20924,159 +20902,415 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
20924 return block.addBitCast(dest_ty, operand);20902 return block.addBitCast(dest_ty, operand);
20925}20903}
2092620904
20905fn zirPtrCastFull(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
20906 const flags = @bitCast(Zir.Inst.FullPtrCastFlags, @truncate(u5, extended.small));
20907 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
20908 const src = LazySrcLoc.nodeOffset(extra.node);
20909 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
20910 const operand = try sema.resolveInst(extra.rhs);
20911 const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, "@ptrCast"); // TODO: better error message (builtin name)
20912 return sema.ptrCastFull(
20913 block,
20914 flags,
20915 src,
20916 operand,
20917 operand_src,
20918 dest_ty,
20919 );
20920}
20921
20927fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {20922fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
20928 const mod = sema.mod;
20929 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;20923 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
20930 const src = inst_data.src();20924 const src = inst_data.src();
20931 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };20925 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
20932 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
20933 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;20926 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
20934 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);20927 const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, "@ptrCast");
20935 const operand = try sema.resolveInst(extra.rhs);20928 const operand = try sema.resolveInst(extra.rhs);
20929
20930 return sema.ptrCastFull(
20931 block,
20932 .{ .ptr_cast = true },
20933 src,
20934 operand,
20935 operand_src,
20936 dest_ty,
20937 );
20938}
20939
20940fn ptrCastFull(
20941 sema: *Sema,
20942 block: *Block,
20943 flags: Zir.Inst.FullPtrCastFlags,
20944 src: LazySrcLoc,
20945 operand: Air.Inst.Ref,
20946 operand_src: LazySrcLoc,
20947 dest_ty: Type,
20948) CompileError!Air.Inst.Ref {
20949 const mod = sema.mod;
20936 const operand_ty = sema.typeOf(operand);20950 const operand_ty = sema.typeOf(operand);
2093720951
20938 try sema.checkPtrType(block, dest_ty_src, dest_ty);20952 try sema.checkPtrType(block, src, dest_ty);
20939 try sema.checkPtrOperand(block, operand_src, operand_ty);20953 try sema.checkPtrOperand(block, operand_src, operand_ty);
2094020954
20941 const operand_info = operand_ty.ptrInfo(mod);20955 const src_info = operand_ty.ptrInfo(mod);
20942 const dest_info = dest_ty.ptrInfo(mod);20956 const dest_info = dest_ty.ptrInfo(mod);
20943 if (operand_info.flags.is_const and !dest_info.flags.is_const) {
20944 const msg = msg: {
20945 const msg = try sema.errMsg(block, src, "cast discards const qualifier", .{});
20946 errdefer msg.destroy(sema.gpa);
2094720957
20948 try sema.errNote(block, src, msg, "consider using '@constCast'", .{});20958 try sema.resolveTypeLayout(src_info.child.toType());
20949 break :msg msg;20959 try sema.resolveTypeLayout(dest_info.child.toType());
20950 };
20951 return sema.failWithOwnedErrorMsg(msg);
20952 }
20953 if (operand_info.flags.is_volatile and !dest_info.flags.is_volatile) {
20954 const msg = msg: {
20955 const msg = try sema.errMsg(block, src, "cast discards volatile qualifier", .{});
20956 errdefer msg.destroy(sema.gpa);
2095720960
20958 try sema.errNote(block, src, msg, "consider using '@volatileCast'", .{});20961 const src_slice_like = src_info.flags.size == .Slice or
20959 break :msg msg;20962 (src_info.flags.size == .One and src_info.child.toType().zigTypeTag(mod) == .Array);
20960 };20963
20961 return sema.failWithOwnedErrorMsg(msg);20964 const dest_slice_like = dest_info.flags.size == .Slice or
20965 (dest_info.flags.size == .One and dest_info.child.toType().zigTypeTag(mod) == .Array);
20966
20967 if (dest_info.flags.size == .Slice and !src_slice_like) {
20968 return sema.fail(block, src, "illegal pointer cast to slice", .{});
20962 }20969 }
20963 if (operand_info.flags.address_space != dest_info.flags.address_space) {
20964 const msg = msg: {
20965 const msg = try sema.errMsg(block, src, "cast changes pointer address space", .{});
20966 errdefer msg.destroy(sema.gpa);
2096720970
20968 try sema.errNote(block, src, msg, "consider using '@addrSpaceCast'", .{});20971 if (dest_info.flags.size == .Slice) {
20969 break :msg msg;20972 const src_elem_size = switch (src_info.flags.size) {
20973 .Slice => src_info.child.toType().abiSize(mod),
20974 // pointer to array
20975 .One => src_info.child.toType().childType(mod).abiSize(mod),
20976 else => unreachable,
20970 };20977 };
20971 return sema.failWithOwnedErrorMsg(msg);20978 const dest_elem_size = dest_info.child.toType().abiSize(mod);
20979 if (src_elem_size != dest_elem_size) {
20980 return sema.fail(block, src, "TODO: implement @ptrCast between slices changing the length", .{});
20981 }
20972 }20982 }
2097320983
20974 const dest_is_slice = dest_ty.isSlice(mod);20984 // The checking logic in this function must stay in sync with Sema.coerceInMemoryAllowedPtrs
20975 const operand_is_slice = operand_ty.isSlice(mod);
20976 if (dest_is_slice and !operand_is_slice) {
20977 return sema.fail(block, dest_ty_src, "illegal pointer cast to slice", .{});
20978 }
20979 const ptr = if (operand_is_slice and !dest_is_slice)
20980 try sema.analyzeSlicePtr(block, operand_src, operand, operand_ty)
20981 else
20982 operand;
2098320985
20984 const dest_elem_ty = dest_ty.elemType2(mod);20986 if (!flags.ptr_cast) {
20985 try sema.resolveTypeLayout(dest_elem_ty);20987 check_size: {
20986 const dest_align = dest_ty.ptrAlignment(mod);20988 if (src_info.flags.size == dest_info.flags.size) break :check_size;
2098720989 if (src_slice_like and dest_slice_like) break :check_size;
20988 const operand_elem_ty = operand_ty.elemType2(mod);20990 if (src_info.flags.size == .C) break :check_size;
20989 try sema.resolveTypeLayout(operand_elem_ty);20991 if (dest_info.flags.size == .C) break :check_size;
20990 const operand_align = operand_ty.ptrAlignment(mod);20992 return sema.failWithOwnedErrorMsg(msg: {
2099120993 const msg = try sema.errMsg(block, src, "cannot implicitly convert {s} pointer to {s} pointer", .{
20992 // If the destination is less aligned than the source, preserve the source alignment20994 pointerSizeString(src_info.flags.size),
20993 const aligned_dest_ty = if (operand_align <= dest_align) dest_ty else blk: {20995 pointerSizeString(dest_info.flags.size),
20994 // Unwrap the pointer (or pointer-like optional) type, set alignment, and re-wrap into result20996 });
20995 var dest_ptr_info = dest_ty.ptrInfo(mod);20997 errdefer msg.destroy(sema.gpa);
20996 dest_ptr_info.flags.alignment = Alignment.fromNonzeroByteUnits(operand_align);20998 if (dest_info.flags.size == .Many and
20997 if (dest_ty.zigTypeTag(mod) == .Optional) {20999 (src_info.flags.size == .Slice or
20998 break :blk try mod.optionalType((try mod.ptrType(dest_ptr_info)).toIntern());21000 (src_info.flags.size == .One and src_info.child.toType().zigTypeTag(mod) == .Array)))
20999 } else {21001 {
21000 break :blk try mod.ptrType(dest_ptr_info);21002 try sema.errNote(block, src, msg, "use 'ptr' field to convert slice to many pointer", .{});
21003 } else {
21004 try sema.errNote(block, src, msg, "use @ptrCast to change pointer size", .{});
21005 }
21006 break :msg msg;
21007 });
21008 }
21009
21010 check_child: {
21011 const src_child = if (dest_info.flags.size == .Slice and src_info.flags.size == .One) blk: {
21012 // *[n]T -> []T
21013 break :blk src_info.child.toType().childType(mod);
21014 } else src_info.child.toType();
21015
21016 const dest_child = dest_info.child.toType();
21017
21018 const imc_res = try sema.coerceInMemoryAllowed(
21019 block,
21020 dest_child,
21021 src_child,
21022 !dest_info.flags.is_const,
21023 mod.getTarget(),
21024 src,
21025 operand_src,
21026 );
21027 if (imc_res == .ok) break :check_child;
21028 return sema.failWithOwnedErrorMsg(msg: {
21029 const msg = try sema.errMsg(block, src, "pointer element type '{}' cannot coerce into element type '{}'", .{
21030 src_child.fmt(mod),
21031 dest_child.fmt(mod),
21032 });
21033 errdefer msg.destroy(sema.gpa);
21034 try imc_res.report(sema, block, src, msg);
21035 try sema.errNote(block, src, msg, "use @ptrCast to cast pointer element type", .{});
21036 break :msg msg;
21037 });
21038 }
21039
21040 check_sent: {
21041 if (dest_info.sentinel == .none) break :check_sent;
21042 if (src_info.flags.size == .C) break :check_sent;
21043 if (src_info.sentinel != .none) {
21044 const coerced_sent = try mod.intern_pool.getCoerced(sema.gpa, src_info.sentinel, dest_info.child);
21045 if (dest_info.sentinel == coerced_sent) break :check_sent;
21046 }
21047 if (src_slice_like and src_info.flags.size == .One and dest_info.flags.size == .Slice) {
21048 // [*]nT -> []T
21049 const arr_ty = src_info.child.toType();
21050 if (arr_ty.sentinel(mod)) |src_sentinel| {
21051 const coerced_sent = try mod.intern_pool.getCoerced(sema.gpa, src_sentinel.toIntern(), dest_info.child);
21052 if (dest_info.sentinel == coerced_sent) break :check_sent;
21053 }
21054 }
21055 return sema.failWithOwnedErrorMsg(msg: {
21056 const msg = if (src_info.sentinel == .none) blk: {
21057 break :blk try sema.errMsg(block, src, "destination pointer requires '{}' sentinel", .{
21058 dest_info.sentinel.toValue().fmtValue(dest_info.child.toType(), mod),
21059 });
21060 } else blk: {
21061 break :blk try sema.errMsg(block, src, "pointer sentinel '{}' cannot coerce into pointer sentinel '{}'", .{
21062 src_info.sentinel.toValue().fmtValue(src_info.child.toType(), mod),
21063 dest_info.sentinel.toValue().fmtValue(dest_info.child.toType(), mod),
21064 });
21065 };
21066 errdefer msg.destroy(sema.gpa);
21067 try sema.errNote(block, src, msg, "use @ptrCast to cast pointer sentinel", .{});
21068 break :msg msg;
21069 });
21001 }21070 }
21002 };
2100321071
21004 if (dest_is_slice) {21072 if (src_info.packed_offset.host_size != dest_info.packed_offset.host_size) {
21005 const operand_elem_size = operand_elem_ty.abiSize(mod);21073 return sema.failWithOwnedErrorMsg(msg: {
21006 const dest_elem_size = dest_elem_ty.abiSize(mod);21074 const msg = try sema.errMsg(block, src, "pointer host size '{}' cannot coerce into pointer host size '{}'", .{
21007 if (operand_elem_size != dest_elem_size) {21075 src_info.packed_offset.host_size,
21008 return sema.fail(block, dest_ty_src, "TODO: implement @ptrCast between slices changing the length", .{});21076 dest_info.packed_offset.host_size,
21077 });
21078 errdefer msg.destroy(sema.gpa);
21079 try sema.errNote(block, src, msg, "use @ptrCast to cast pointer host size", .{});
21080 break :msg msg;
21081 });
21082 }
21083
21084 if (src_info.packed_offset.bit_offset != dest_info.packed_offset.bit_offset) {
21085 return sema.failWithOwnedErrorMsg(msg: {
21086 const msg = try sema.errMsg(block, src, "pointer bit offset '{}' cannot coerce into pointer bit offset '{}'", .{
21087 src_info.packed_offset.bit_offset,
21088 dest_info.packed_offset.bit_offset,
21089 });
21090 errdefer msg.destroy(sema.gpa);
21091 try sema.errNote(block, src, msg, "use @ptrCast to cast pointer bit offset", .{});
21092 break :msg msg;
21093 });
21094 }
21095
21096 check_allowzero: {
21097 const src_allows_zero = operand_ty.ptrAllowsZero(mod);
21098 const dest_allows_zero = dest_ty.ptrAllowsZero(mod);
21099 if (!src_allows_zero) break :check_allowzero;
21100 if (dest_allows_zero) break :check_allowzero;
21101
21102 return sema.failWithOwnedErrorMsg(msg: {
21103 const msg = try sema.errMsg(block, src, "'{}' could have null values which are illegal in type '{}'", .{
21104 operand_ty.fmt(mod),
21105 dest_ty.fmt(mod),
21106 });
21107 errdefer msg.destroy(sema.gpa);
21108 try sema.errNote(block, src, msg, "use @ptrCast to assert the pointer is not null", .{});
21109 break :msg msg;
21110 });
21009 }21111 }
21112
21113 // TODO: vector index?
21010 }21114 }
2101121115
21012 if (dest_align > operand_align) {21116 const src_align = src_info.flags.alignment.toByteUnitsOptional() orelse src_info.child.toType().abiAlignment(mod);
21013 const msg = msg: {21117 const dest_align = dest_info.flags.alignment.toByteUnitsOptional() orelse dest_info.child.toType().abiAlignment(mod);
21014 const msg = try sema.errMsg(block, src, "cast increases pointer alignment", .{});21118 if (!flags.align_cast) {
21015 errdefer msg.destroy(sema.gpa);21119 if (dest_align > src_align) {
21120 return sema.failWithOwnedErrorMsg(msg: {
21121 const msg = try sema.errMsg(block, src, "cast increases pointer alignment", .{});
21122 errdefer msg.destroy(sema.gpa);
21123 try sema.errNote(block, operand_src, msg, "'{}' has alignment '{d}'", .{
21124 operand_ty.fmt(mod), src_align,
21125 });
21126 try sema.errNote(block, src, msg, "'{}' has alignment '{d}'", .{
21127 dest_ty.fmt(mod), dest_align,
21128 });
21129 try sema.errNote(block, src, msg, "use @alignCast to assert pointer alignment", .{});
21130 break :msg msg;
21131 });
21132 }
21133 }
2101621134
21017 try sema.errNote(block, operand_src, msg, "'{}' has alignment '{d}'", .{21135 if (!flags.addrspace_cast) {
21018 operand_ty.fmt(mod), operand_align,21136 if (src_info.flags.address_space != dest_info.flags.address_space) {
21137 return sema.failWithOwnedErrorMsg(msg: {
21138 const msg = try sema.errMsg(block, src, "cast changes pointer address space", .{});
21139 errdefer msg.destroy(sema.gpa);
21140 try sema.errNote(block, operand_src, msg, "'{}' has address space '{s}'", .{
21141 operand_ty.fmt(mod), @tagName(src_info.flags.address_space),
21142 });
21143 try sema.errNote(block, src, msg, "'{}' has address space '{s}'", .{
21144 dest_ty.fmt(mod), @tagName(dest_info.flags.address_space),
21145 });
21146 try sema.errNote(block, src, msg, "use @addrSpaceCast to cast pointer address space", .{});
21147 break :msg msg;
21148 });
21149 }
21150 } else {
21151 // Some address space casts are always disallowed
21152 if (!target_util.addrSpaceCastIsValid(mod.getTarget(), src_info.flags.address_space, dest_info.flags.address_space)) {
21153 return sema.failWithOwnedErrorMsg(msg: {
21154 const msg = try sema.errMsg(block, src, "invalid address space cast", .{});
21155 errdefer msg.destroy(sema.gpa);
21156 try sema.errNote(block, operand_src, msg, "address space '{s}' is not compatible with address space '{s}'", .{
21157 @tagName(src_info.flags.address_space),
21158 @tagName(dest_info.flags.address_space),
21159 });
21160 break :msg msg;
21019 });21161 });
21020 try sema.errNote(block, dest_ty_src, msg, "'{}' has alignment '{d}'", .{21162 }
21021 dest_ty.fmt(mod), dest_align,21163 }
21164
21165 if (!flags.const_cast) {
21166 if (src_info.flags.is_const and !dest_info.flags.is_const) {
21167 return sema.failWithOwnedErrorMsg(msg: {
21168 const msg = try sema.errMsg(block, src, "cast discards const qualifier", .{});
21169 errdefer msg.destroy(sema.gpa);
21170 try sema.errNote(block, src, msg, "use @constCast to discard const qualifier", .{});
21171 break :msg msg;
21022 });21172 });
21173 }
21174 }
2102321175
21024 try sema.errNote(block, src, msg, "consider using '@alignCast'", .{});21176 if (!flags.volatile_cast) {
21025 break :msg msg;21177 if (src_info.flags.is_volatile and !dest_info.flags.is_volatile) {
21026 };21178 return sema.failWithOwnedErrorMsg(msg: {
21027 return sema.failWithOwnedErrorMsg(msg);21179 const msg = try sema.errMsg(block, src, "cast discards volatile qualifier", .{});
21180 errdefer msg.destroy(sema.gpa);
21181 try sema.errNote(block, src, msg, "use @volatileCast to discard volatile qualifier", .{});
21182 break :msg msg;
21183 });
21184 }
21028 }21185 }
2102921186
21030 if (try sema.resolveMaybeUndefVal(ptr)) |operand_val| {21187 const ptr = if (src_info.flags.size == .Slice and dest_info.flags.size != .Slice) ptr: {
21031 if (!dest_ty.ptrAllowsZero(mod) and operand_val.isUndef(mod)) {21188 break :ptr try sema.analyzeSlicePtr(block, operand_src, operand, operand_ty);
21032 return sema.failWithUseOfUndef(block, operand_src);21189 } else operand;
21190
21191 const dest_ptr_ty = if (dest_info.flags.size == .Slice and src_info.flags.size != .Slice) blk: {
21192 // Only convert to a many-pointer at first
21193 var info = dest_info;
21194 info.flags.size = .Many;
21195 const ty = try mod.ptrType(info);
21196 if (dest_ty.zigTypeTag(mod) == .Optional) {
21197 break :blk try mod.optionalType(ty.toIntern());
21198 } else {
21199 break :blk ty;
21033 }21200 }
21034 if (!dest_ty.ptrAllowsZero(mod) and operand_val.isNull(mod)) {21201 } else dest_ty;
21035 return sema.fail(block, operand_src, "null pointer casted to type '{}'", .{dest_ty.fmt(mod)});21202
21203 // Cannot do @addrSpaceCast at comptime
21204 if (!flags.addrspace_cast) {
21205 if (try sema.resolveMaybeUndefVal(ptr)) |ptr_val| {
21206 if (!dest_ty.ptrAllowsZero(mod) and ptr_val.isUndef(mod)) {
21207 return sema.failWithUseOfUndef(block, operand_src);
21208 }
21209 if (!dest_ty.ptrAllowsZero(mod) and ptr_val.isNull(mod)) {
21210 return sema.fail(block, operand_src, "null pointer casted to type '{}'", .{dest_ty.fmt(mod)});
21211 }
21212 if (dest_align > src_align) {
21213 if (try ptr_val.getUnsignedIntAdvanced(mod, null)) |addr| {
21214 if (addr % dest_align != 0) {
21215 return sema.fail(block, operand_src, "pointer address 0x{X} is not aligned to {d} bytes", .{ addr, dest_align });
21216 }
21217 }
21218 }
21219 if (dest_info.flags.size == .Slice and src_info.flags.size != .Slice) {
21220 if (ptr_val.isUndef(mod)) return sema.addConstUndef(dest_ty);
21221 const arr_len = try mod.intValue(Type.usize, src_info.child.toType().arrayLen(mod));
21222 return sema.addConstant((try mod.intern(.{ .ptr = .{
21223 .ty = dest_ty.toIntern(),
21224 .addr = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr,
21225 .len = arr_len.toIntern(),
21226 } })).toValue());
21227 } else {
21228 assert(dest_ptr_ty.eql(dest_ty, mod));
21229 return sema.addConstant(try mod.getCoerced(ptr_val, dest_ty));
21230 }
21036 }21231 }
21037 return sema.addConstant(try mod.getCoerced(operand_val, aligned_dest_ty));
21038 }21232 }
2103921233
21040 try sema.requireRuntimeBlock(block, src, null);21234 try sema.requireRuntimeBlock(block, src, null);
21235
21041 if (block.wantSafety() and operand_ty.ptrAllowsZero(mod) and !dest_ty.ptrAllowsZero(mod) and21236 if (block.wantSafety() and operand_ty.ptrAllowsZero(mod) and !dest_ty.ptrAllowsZero(mod) and
21042 (try sema.typeHasRuntimeBits(dest_ty.elemType2(mod)) or dest_ty.elemType2(mod).zigTypeTag(mod) == .Fn))21237 (try sema.typeHasRuntimeBits(dest_info.child.toType()) or dest_info.child.toType().zigTypeTag(mod) == .Fn))
21043 {21238 {
21044 const ptr_int = try block.addUnOp(.int_from_ptr, ptr);21239 const ptr_int = try block.addUnOp(.int_from_ptr, ptr);
21045 const is_non_zero = try block.addBinOp(.cmp_neq, ptr_int, .zero_usize);21240 const is_non_zero = try block.addBinOp(.cmp_neq, ptr_int, .zero_usize);
21046 const ok = if (operand_is_slice) ok: {21241 const ok = if (src_info.flags.size == .Slice and dest_info.flags.size == .Slice) ok: {
21047 const len = try sema.analyzeSliceLen(block, operand_src, operand);21242 const len = try sema.analyzeSliceLen(block, operand_src, ptr);
21048 const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);21243 const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);
21049 break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero);21244 break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero);
21050 } else is_non_zero;21245 } else is_non_zero;
21051 try sema.addSafetyCheck(block, ok, .cast_to_null);21246 try sema.addSafetyCheck(block, ok, .cast_to_null);
21052 }21247 }
2105321248
21054 return block.addBitCast(aligned_dest_ty, ptr);21249 if (block.wantSafety() and dest_align > src_align and try sema.typeHasRuntimeBits(dest_info.child.toType())) {
21055}21250 const align_minus_1 = try sema.addConstant(
2105621251 try mod.intValue(Type.usize, dest_align - 1),
21057fn zirConstCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {21252 );
21058 const mod = sema.mod;21253 const ptr_int = try block.addUnOp(.int_from_ptr, ptr);
21059 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;21254 const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1);
21060 const src = LazySrcLoc.nodeOffset(extra.node);21255 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
21061 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };21256 const ok = if (src_info.flags.size == .Slice and dest_info.flags.size == .Slice) ok: {
21062 const operand = try sema.resolveInst(extra.operand);21257 const len = try sema.analyzeSliceLen(block, operand_src, ptr);
21063 const operand_ty = sema.typeOf(operand);21258 const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);
21064 try sema.checkPtrOperand(block, operand_src, operand_ty);21259 break :ok try block.addBinOp(.bit_or, len_zero, is_aligned);
21260 } else is_aligned;
21261 try sema.addSafetyCheck(block, ok, .incorrect_alignment);
21262 }
2106521263
21066 var ptr_info = operand_ty.ptrInfo(mod);21264 // If we're going from an array pointer to a slice, this will only be the pointer part!
21067 ptr_info.flags.is_const = false;21265 const result_ptr = if (flags.addrspace_cast) ptr: {
21068 const dest_ty = try mod.ptrType(ptr_info);21266 // We can't change address spaces with a bitcast, so this requires two instructions
21267 var intermediate_info = src_info;
21268 intermediate_info.flags.address_space = dest_info.flags.address_space;
21269 const intermediate_ptr_ty = try mod.ptrType(intermediate_info);
21270 const intermediate_ty = if (dest_ptr_ty.zigTypeTag(mod) == .Optional) blk: {
21271 break :blk try mod.optionalType(intermediate_ptr_ty.toIntern());
21272 } else intermediate_ptr_ty;
21273 const intermediate = try block.addInst(.{
21274 .tag = .addrspace_cast,
21275 .data = .{ .ty_op = .{
21276 .ty = try sema.addType(intermediate_ty),
21277 .operand = ptr,
21278 } },
21279 });
21280 if (intermediate_ty.eql(dest_ptr_ty, mod)) {
21281 // We only changed the address space, so no need for a bitcast
21282 break :ptr intermediate;
21283 }
21284 break :ptr try block.addBitCast(dest_ptr_ty, intermediate);
21285 } else ptr: {
21286 break :ptr try block.addBitCast(dest_ptr_ty, ptr);
21287 };
2106921288
21070 if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {21289 if (dest_info.flags.size == .Slice and src_info.flags.size != .Slice) {
21071 return sema.addConstant(try mod.getCoerced(operand_val, dest_ty));21290 // We have to construct a slice using the operand's child's array length
21291 // Note that we know from the check at the start of the function that operand_ty is slice-like
21292 const arr_len = try sema.addConstant(
21293 try mod.intValue(Type.usize, src_info.child.toType().arrayLen(mod)),
21294 );
21295 return block.addInst(.{
21296 .tag = .slice,
21297 .data = .{ .ty_pl = .{
21298 .ty = try sema.addType(dest_ty),
21299 .payload = try sema.addExtra(Air.Bin{
21300 .lhs = result_ptr,
21301 .rhs = arr_len,
21302 }),
21303 } },
21304 });
21305 } else {
21306 assert(dest_ptr_ty.eql(dest_ty, mod));
21307 return result_ptr;
21072 }21308 }
21073
21074 try sema.requireRuntimeBlock(block, src, null);
21075 return block.addBitCast(dest_ty, operand);
21076}21309}
2107721310
21078fn zirVolatileCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {21311fn zirPtrCastNoDest(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
21079 const mod = sema.mod;21312 const mod = sema.mod;
21313 const flags = @bitCast(Zir.Inst.FullPtrCastFlags, @truncate(u5, extended.small));
21080 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;21314 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
21081 const src = LazySrcLoc.nodeOffset(extra.node);21315 const src = LazySrcLoc.nodeOffset(extra.node);
21082 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };21316 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
...@@ -21085,11 +21319,12 @@ fn zirVolatileCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD...@@ -21085,11 +21319,12 @@ fn zirVolatileCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
21085 try sema.checkPtrOperand(block, operand_src, operand_ty);21319 try sema.checkPtrOperand(block, operand_src, operand_ty);
2108621320
21087 var ptr_info = operand_ty.ptrInfo(mod);21321 var ptr_info = operand_ty.ptrInfo(mod);
21088 ptr_info.flags.is_volatile = false;21322 if (flags.const_cast) ptr_info.flags.is_const = false;
21323 if (flags.volatile_cast) ptr_info.flags.is_volatile = false;
21089 const dest_ty = try mod.ptrType(ptr_info);21324 const dest_ty = try mod.ptrType(ptr_info);
2109021325
21091 if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {21326 if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
21092 return sema.addConstant(operand_val);21327 return sema.addConstant(try mod.getCoerced(operand_val, dest_ty));
21093 }21328 }
2109421329
21095 try sema.requireRuntimeBlock(block, src, null);21330 try sema.requireRuntimeBlock(block, src, null);
...@@ -21100,24 +21335,21 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -21100,24 +21335,21 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
21100 const mod = sema.mod;21335 const mod = sema.mod;
21101 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;21336 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
21102 const src = inst_data.src();21337 const src = inst_data.src();
21103 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };21338 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
21104 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
21105 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;21339 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
21106 const dest_scalar_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);21340 const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, "@truncate");
21341 const dest_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, dest_ty, src);
21107 const operand = try sema.resolveInst(extra.rhs);21342 const operand = try sema.resolveInst(extra.rhs);
21108 const dest_is_comptime_int = try sema.checkIntType(block, dest_ty_src, dest_scalar_ty);
21109 const operand_ty = sema.typeOf(operand);21343 const operand_ty = sema.typeOf(operand);
21110 const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src);21344 const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src);
21111 const is_vector = operand_ty.zigTypeTag(mod) == .Vector;
21112 const dest_ty = if (is_vector)
21113 try mod.vectorType(.{
21114 .len = operand_ty.vectorLen(mod),
21115 .child = dest_scalar_ty.toIntern(),
21116 })
21117 else
21118 dest_scalar_ty;
2111921345
21120 if (dest_is_comptime_int) {21346 const operand_is_vector = operand_ty.zigTypeTag(mod) == .Vector;
21347 const dest_is_vector = dest_ty.zigTypeTag(mod) == .Vector;
21348 if (operand_is_vector != dest_is_vector) {
21349 return sema.fail(block, operand_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(mod), operand_ty.fmt(mod) });
21350 }
21351
21352 if (dest_scalar_ty.zigTypeTag(mod) == .ComptimeInt) {
21121 return sema.coerce(block, dest_ty, operand, operand_src);21353 return sema.coerce(block, dest_ty, operand, operand_src);
21122 }21354 }
2112321355
...@@ -21147,7 +21379,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -21147,7 +21379,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
21147 .{ dest_ty.fmt(mod), operand_ty.fmt(mod) },21379 .{ dest_ty.fmt(mod), operand_ty.fmt(mod) },
21148 );21380 );
21149 errdefer msg.destroy(sema.gpa);21381 errdefer msg.destroy(sema.gpa);
21150 try sema.errNote(block, dest_ty_src, msg, "destination type has {d} bits", .{21382 try sema.errNote(block, src, msg, "destination type has {d} bits", .{
21151 dest_info.bits,21383 dest_info.bits,
21152 });21384 });
21153 try sema.errNote(block, operand_src, msg, "operand type has {d} bits", .{21385 try sema.errNote(block, operand_src, msg, "operand type has {d} bits", .{
...@@ -21161,7 +21393,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -21161,7 +21393,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
2116121393
21162 if (try sema.resolveMaybeUndefValIntable(operand)) |val| {21394 if (try sema.resolveMaybeUndefValIntable(operand)) |val| {
21163 if (val.isUndef(mod)) return sema.addConstUndef(dest_ty);21395 if (val.isUndef(mod)) return sema.addConstUndef(dest_ty);
21164 if (!is_vector) {21396 if (!dest_is_vector) {
21165 return sema.addConstant(try mod.getCoerced(21397 return sema.addConstant(try mod.getCoerced(
21166 try val.intTrunc(operand_ty, sema.arena, dest_info.signedness, dest_info.bits, mod),21398 try val.intTrunc(operand_ty, sema.arena, dest_info.signedness, dest_info.bits, mod),
21167 dest_ty,21399 dest_ty,
...@@ -21182,59 +21414,6 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -21182,59 +21414,6 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
21182 return block.addTyOp(.trunc, dest_ty, operand);21414 return block.addTyOp(.trunc, dest_ty, operand);
21183}21415}
2118421416
21185fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
21186 const mod = sema.mod;
21187 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
21188 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
21189 const align_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
21190 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
21191 const dest_align = try sema.resolveAlign(block, align_src, extra.lhs);
21192 const ptr = try sema.resolveInst(extra.rhs);
21193 const ptr_ty = sema.typeOf(ptr);
21194
21195 try sema.checkPtrOperand(block, ptr_src, ptr_ty);
21196
21197 var ptr_info = ptr_ty.ptrInfo(mod);
21198 ptr_info.flags.alignment = dest_align;
21199 var dest_ty = try mod.ptrType(ptr_info);
21200 if (ptr_ty.zigTypeTag(mod) == .Optional) {
21201 dest_ty = try mod.optionalType(dest_ty.toIntern());
21202 }
21203
21204 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |val| {
21205 if (try val.getUnsignedIntAdvanced(mod, null)) |addr| {
21206 const dest_align_bytes = dest_align.toByteUnitsOptional().?;
21207 if (addr % dest_align_bytes != 0) {
21208 return sema.fail(block, ptr_src, "pointer address 0x{X} is not aligned to {d} bytes", .{ addr, dest_align_bytes });
21209 }
21210 }
21211 return sema.addConstant(try mod.getCoerced(val, dest_ty));
21212 }
21213
21214 try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src);
21215 if (block.wantSafety() and dest_align.order(Alignment.fromNonzeroByteUnits(1)).compare(.gt) and
21216 try sema.typeHasRuntimeBits(ptr_info.child.toType()))
21217 {
21218 const align_minus_1 = try sema.addConstant(
21219 try mod.intValue(Type.usize, dest_align.toByteUnitsOptional().? - 1),
21220 );
21221 const actual_ptr = if (ptr_ty.isSlice(mod))
21222 try sema.analyzeSlicePtr(block, ptr_src, ptr, ptr_ty)
21223 else
21224 ptr;
21225 const ptr_int = try block.addUnOp(.int_from_ptr, actual_ptr);
21226 const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1);
21227 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
21228 const ok = if (ptr_ty.isSlice(mod)) ok: {
21229 const len = try sema.analyzeSliceLen(block, ptr_src, ptr);
21230 const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);
21231 break :ok try block.addBinOp(.bit_or, len_zero, is_aligned);
21232 } else is_aligned;
21233 try sema.addSafetyCheck(block, ok, .incorrect_alignment);
21234 }
21235 return sema.bitCast(block, dest_ty, ptr, ptr_src, null);
21236}
21237
21238fn zirBitCount(21417fn zirBitCount(
21239 sema: *Sema,21418 sema: *Sema,
21240 block: *Block,21419 block: *Block,
...@@ -21546,7 +21725,7 @@ fn checkPtrOperand(...@@ -21546,7 +21725,7 @@ fn checkPtrOperand(
21546 };21725 };
21547 return sema.failWithOwnedErrorMsg(msg);21726 return sema.failWithOwnedErrorMsg(msg);
21548 },21727 },
21549 .Optional => if (ty.isPtrLikeOptional(mod)) return,21728 .Optional => if (ty.childType(mod).zigTypeTag(mod) == .Pointer) return,
21550 else => {},21729 else => {},
21551 }21730 }
21552 return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(mod)});21731 return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(mod)});
...@@ -21577,7 +21756,7 @@ fn checkPtrType(...@@ -21577,7 +21756,7 @@ fn checkPtrType(
21577 };21756 };
21578 return sema.failWithOwnedErrorMsg(msg);21757 return sema.failWithOwnedErrorMsg(msg);
21579 },21758 },
21580 .Optional => if (ty.isPtrLikeOptional(mod)) return,21759 .Optional => if (ty.childType(mod).zigTypeTag(mod) == .Pointer) return,
21581 else => {},21760 else => {},
21582 }21761 }
21583 return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(mod)});21762 return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(mod)});
src/TypedValue.zig-5
...@@ -241,11 +241,6 @@ pub fn print(...@@ -241,11 +241,6 @@ pub fn print(
241 return;241 return;
242 }242 }
243 try writer.writeAll("@enumFromInt(");243 try writer.writeAll("@enumFromInt(");
244 try print(.{
245 .ty = Type.type,
246 .val = enum_tag.ty.toValue(),
247 }, writer, level - 1, mod);
248 try writer.writeAll(", ");
249 try print(.{244 try print(.{
250 .ty = ip.typeOf(enum_tag.int).toType(),245 .ty = ip.typeOf(enum_tag.int).toType(),
251 .val = enum_tag.int.toValue(),246 .val = enum_tag.int.toValue(),
src/Zir.zig+30-14
...@@ -230,6 +230,9 @@ pub const Inst = struct {...@@ -230,6 +230,9 @@ pub const Inst = struct {
230 /// Given an indexable type, returns the type of the element at given index.230 /// Given an indexable type, returns the type of the element at given index.
231 /// Uses the `bin` union field. lhs is the indexable type, rhs is the index.231 /// Uses the `bin` union field. lhs is the indexable type, rhs is the index.
232 elem_type_index,232 elem_type_index,
233 /// Given a pointer type, returns its element type.
234 /// Uses the `un_node` field.
235 elem_type,
233 /// Given a pointer to an indexable object, returns the len property. This is236 /// Given a pointer to an indexable object, returns the len property. This is
234 /// used by for loops. This instruction also emits a for-loop specific compile237 /// used by for loops. This instruction also emits a for-loop specific compile
235 /// error if the indexable object is not indexable.238 /// error if the indexable object is not indexable.
...@@ -838,13 +841,12 @@ pub const Inst = struct {...@@ -838,13 +841,12 @@ pub const Inst = struct {
838 int_cast,841 int_cast,
839 /// Implements the `@ptrCast` builtin.842 /// Implements the `@ptrCast` builtin.
840 /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.843 /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
844 /// Not every `@ptrCast` will correspond to this instruction - see also
845 /// `ptr_cast_full` in `Extended`.
841 ptr_cast,846 ptr_cast,
842 /// Implements the `@truncate` builtin.847 /// Implements the `@truncate` builtin.
843 /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.848 /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
844 truncate,849 truncate,
845 /// Implements the `@alignCast` builtin.
846 /// Uses `pl_node` with payload `Bin`. `lhs` is dest alignment, `rhs` is operand.
847 align_cast,
848850
849 /// Implements the `@hasDecl` builtin.851 /// Implements the `@hasDecl` builtin.
850 /// Uses the `pl_node` union field. Payload is `Bin`.852 /// Uses the `pl_node` union field. Payload is `Bin`.
...@@ -1005,6 +1007,7 @@ pub const Inst = struct {...@@ -1005,6 +1007,7 @@ pub const Inst = struct {
1005 .array_type_sentinel,1007 .array_type_sentinel,
1006 .vector_type,1008 .vector_type,
1007 .elem_type_index,1009 .elem_type_index,
1010 .elem_type,
1008 .indexable_ptr_len,1011 .indexable_ptr_len,
1009 .anyframe_type,1012 .anyframe_type,
1010 .as,1013 .as,
...@@ -1172,7 +1175,6 @@ pub const Inst = struct {...@@ -1172,7 +1175,6 @@ pub const Inst = struct {
1172 .int_cast,1175 .int_cast,
1173 .ptr_cast,1176 .ptr_cast,
1174 .truncate,1177 .truncate,
1175 .align_cast,
1176 .has_field,1178 .has_field,
1177 .clz,1179 .clz,
1178 .ctz,1180 .ctz,
...@@ -1309,6 +1311,7 @@ pub const Inst = struct {...@@ -1309,6 +1311,7 @@ pub const Inst = struct {
1309 .array_type_sentinel,1311 .array_type_sentinel,
1310 .vector_type,1312 .vector_type,
1311 .elem_type_index,1313 .elem_type_index,
1314 .elem_type,
1312 .indexable_ptr_len,1315 .indexable_ptr_len,
1313 .anyframe_type,1316 .anyframe_type,
1314 .as,1317 .as,
...@@ -1454,7 +1457,6 @@ pub const Inst = struct {...@@ -1454,7 +1457,6 @@ pub const Inst = struct {
1454 .int_cast,1457 .int_cast,
1455 .ptr_cast,1458 .ptr_cast,
1456 .truncate,1459 .truncate,
1457 .align_cast,
1458 .has_field,1460 .has_field,
1459 .clz,1461 .clz,
1460 .ctz,1462 .ctz,
...@@ -1539,6 +1541,7 @@ pub const Inst = struct {...@@ -1539,6 +1541,7 @@ pub const Inst = struct {
1539 .array_type_sentinel = .pl_node,1541 .array_type_sentinel = .pl_node,
1540 .vector_type = .pl_node,1542 .vector_type = .pl_node,
1541 .elem_type_index = .bin,1543 .elem_type_index = .bin,
1544 .elem_type = .un_node,
1542 .indexable_ptr_len = .un_node,1545 .indexable_ptr_len = .un_node,
1543 .anyframe_type = .un_node,1546 .anyframe_type = .un_node,
1544 .as = .bin,1547 .as = .bin,
...@@ -1717,7 +1720,6 @@ pub const Inst = struct {...@@ -1717,7 +1720,6 @@ pub const Inst = struct {
1717 .int_cast = .pl_node,1720 .int_cast = .pl_node,
1718 .ptr_cast = .pl_node,1721 .ptr_cast = .pl_node,
1719 .truncate = .pl_node,1722 .truncate = .pl_node,
1720 .align_cast = .pl_node,
1721 .typeof_builtin = .pl_node,1723 .typeof_builtin = .pl_node,
17221724
1723 .has_decl = .pl_node,1725 .has_decl = .pl_node,
...@@ -1948,9 +1950,6 @@ pub const Inst = struct {...@@ -1948,9 +1950,6 @@ pub const Inst = struct {
1948 /// `small` 0=>weak 1=>strong1950 /// `small` 0=>weak 1=>strong
1949 /// `operand` is payload index to `Cmpxchg`.1951 /// `operand` is payload index to `Cmpxchg`.
1950 cmpxchg,1952 cmpxchg,
1951 /// Implement the builtin `@addrSpaceCast`
1952 /// `operand` is payload index to `BinNode`. `lhs` is dest type, `rhs` is operand.
1953 addrspace_cast,
1954 /// Implement builtin `@cVaArg`.1953 /// Implement builtin `@cVaArg`.
1955 /// `operand` is payload index to `BinNode`.1954 /// `operand` is payload index to `BinNode`.
1956 c_va_arg,1955 c_va_arg,
...@@ -1963,12 +1962,21 @@ pub const Inst = struct {...@@ -1963,12 +1962,21 @@ pub const Inst = struct {
1963 /// Implement builtin `@cVaStart`.1962 /// Implement builtin `@cVaStart`.
1964 /// `operand` is `src_node: i32`.1963 /// `operand` is `src_node: i32`.
1965 c_va_start,1964 c_va_start,
1966 /// Implements the `@constCast` builtin.1965 /// Implements the following builtins:
1967 /// `operand` is payload index to `UnNode`.1966 /// `@ptrCast`, `@alignCast`, `@addrSpaceCast`, `@constCast`, `@volatileCast`.
1968 const_cast,1967 /// Represents an arbitrary nesting of the above builtins. Such a nesting is treated as a
1969 /// Implements the `@volatileCast` builtin.1968 /// single operation which can modify multiple components of a pointer type.
1969 /// `operand` is payload index to `BinNode`.
1970 /// `small` contains `FullPtrCastFlags`.
1971 /// AST node is the root of the nested casts.
1972 /// `lhs` is dest type, `rhs` is operand.
1973 ptr_cast_full,
1970 /// `operand` is payload index to `UnNode`.1974 /// `operand` is payload index to `UnNode`.
1971 volatile_cast,1975 /// `small` contains `FullPtrCastFlags`.
1976 /// Guaranteed to only have flags where no explicit destination type is
1977 /// required (const_cast and volatile_cast).
1978 /// AST node is the root of the nested casts.
1979 ptr_cast_no_dest,
1972 /// Implements the `@workItemId` builtin.1980 /// Implements the `@workItemId` builtin.
1973 /// `operand` is payload index to `UnNode`.1981 /// `operand` is payload index to `UnNode`.
1974 work_item_id,1982 work_item_id,
...@@ -2806,6 +2814,14 @@ pub const Inst = struct {...@@ -2806,6 +2814,14 @@ pub const Inst = struct {
2806 dbg_var,2814 dbg_var,
2807 };2815 };
28082816
2817 pub const FullPtrCastFlags = packed struct(u5) {
2818 ptr_cast: bool = false,
2819 align_cast: bool = false,
2820 addrspace_cast: bool = false,
2821 const_cast: bool = false,
2822 volatile_cast: bool = false,
2823 };
2824
2809 /// Trailing:2825 /// Trailing:
2810 /// 0. src_node: i32, // if has_src_node2826 /// 0. src_node: i32, // if has_src_node
2811 /// 1. tag_type: Ref, // if has_tag_type2827 /// 1. tag_type: Ref, // if has_tag_type
src/print_zir.zig+30-4
...@@ -154,6 +154,7 @@ const Writer = struct {...@@ -154,6 +154,7 @@ const Writer = struct {
154 .alloc,154 .alloc,
155 .alloc_mut,155 .alloc_mut,
156 .alloc_comptime_mut,156 .alloc_comptime_mut,
157 .elem_type,
157 .indexable_ptr_len,158 .indexable_ptr_len,
158 .anyframe_type,159 .anyframe_type,
159 .bit_not,160 .bit_not,
...@@ -329,7 +330,6 @@ const Writer = struct {...@@ -329,7 +330,6 @@ const Writer = struct {
329 .int_cast,330 .int_cast,
330 .ptr_cast,331 .ptr_cast,
331 .truncate,332 .truncate,
332 .align_cast,
333 .div_exact,333 .div_exact,
334 .div_floor,334 .div_floor,
335 .div_trunc,335 .div_trunc,
...@@ -507,8 +507,6 @@ const Writer = struct {...@@ -507,8 +507,6 @@ const Writer = struct {
507 .reify,507 .reify,
508 .c_va_copy,508 .c_va_copy,
509 .c_va_end,509 .c_va_end,
510 .const_cast,
511 .volatile_cast,
512 .work_item_id,510 .work_item_id,
513 .work_group_size,511 .work_group_size,
514 .work_group_id,512 .work_group_id,
...@@ -525,7 +523,6 @@ const Writer = struct {...@@ -525,7 +523,6 @@ const Writer = struct {
525 .err_set_cast,523 .err_set_cast,
526 .wasm_memory_grow,524 .wasm_memory_grow,
527 .prefetch,525 .prefetch,
528 .addrspace_cast,
529 .c_va_arg,526 .c_va_arg,
530 => {527 => {
531 const inst_data = self.code.extraData(Zir.Inst.BinNode, extended.operand).data;528 const inst_data = self.code.extraData(Zir.Inst.BinNode, extended.operand).data;
...@@ -539,6 +536,8 @@ const Writer = struct {...@@ -539,6 +536,8 @@ const Writer = struct {
539536
540 .builtin_async_call => try self.writeBuiltinAsyncCall(stream, extended),537 .builtin_async_call => try self.writeBuiltinAsyncCall(stream, extended),
541 .cmpxchg => try self.writeCmpxchg(stream, extended),538 .cmpxchg => try self.writeCmpxchg(stream, extended),
539 .ptr_cast_full => try self.writePtrCastFull(stream, extended),
540 .ptr_cast_no_dest => try self.writePtrCastNoDest(stream, extended),
542 }541 }
543 }542 }
544543
...@@ -964,6 +963,33 @@ const Writer = struct {...@@ -964,6 +963,33 @@ const Writer = struct {
964 try self.writeSrc(stream, src);963 try self.writeSrc(stream, src);
965 }964 }
966965
966 fn writePtrCastFull(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
967 const flags = @bitCast(Zir.Inst.FullPtrCastFlags, @truncate(u5, extended.small));
968 const extra = self.code.extraData(Zir.Inst.BinNode, extended.operand).data;
969 const src = LazySrcLoc.nodeOffset(extra.node);
970 if (flags.ptr_cast) try stream.writeAll("ptr_cast, ");
971 if (flags.align_cast) try stream.writeAll("align_cast, ");
972 if (flags.addrspace_cast) try stream.writeAll("addrspace_cast, ");
973 if (flags.const_cast) try stream.writeAll("const_cast, ");
974 if (flags.volatile_cast) try stream.writeAll("volatile_cast, ");
975 try self.writeInstRef(stream, extra.lhs);
976 try stream.writeAll(", ");
977 try self.writeInstRef(stream, extra.rhs);
978 try stream.writeAll(")) ");
979 try self.writeSrc(stream, src);
980 }
981
982 fn writePtrCastNoDest(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
983 const flags = @bitCast(Zir.Inst.FullPtrCastFlags, @truncate(u5, extended.small));
984 const extra = self.code.extraData(Zir.Inst.UnNode, extended.operand).data;
985 const src = LazySrcLoc.nodeOffset(extra.node);
986 if (flags.const_cast) try stream.writeAll("const_cast, ");
987 if (flags.volatile_cast) try stream.writeAll("volatile_cast, ");
988 try self.writeInstRef(stream, extra.operand);
989 try stream.writeAll(")) ");
990 try self.writeSrc(stream, src);
991 }
992
967 fn writeAtomicLoad(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {993 fn writeAtomicLoad(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
968 const inst_data = self.code.instructions.items(.data)[inst].pl_node;994 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
969 const extra = self.code.extraData(Zir.Inst.AtomicLoad, inst_data.payload_index).data;995 const extra = self.code.extraData(Zir.Inst.AtomicLoad, inst_data.payload_index).data;