authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-26 19:59:39-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-26 20:02:01-07:00
log82bd0ac572f14d1e3a13737f4daf00a1ee8041a2
tree38efbcea86e28b16a65d36c8866f4870085f9e44
parentdb55f469c12c01831bd393c6701c26c15ffe726c

Sema: implement struct init is_ref=true

Takes advantage of the pattern already established with array_init_anon. Also upgrades array_init (non-anon) to the pattern. Implements comptime struct value equality and pointer value hashing.

9 files changed, 704 insertions(+), 589 deletions(-)

src/Sema.zig+94-54
......@@ -10433,7 +10433,13 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
1043310433 }
1043410434}
1043510435
10436fn structInitEmpty(sema: *Sema, block: *Block, obj_ty: Type, dest_src: LazySrcLoc, init_src: LazySrcLoc) CompileError!Air.Inst.Ref {
10436fn structInitEmpty(
10437 sema: *Sema,
10438 block: *Block,
10439 obj_ty: Type,
10440 dest_src: LazySrcLoc,
10441 init_src: LazySrcLoc,
10442) CompileError!Air.Inst.Ref {
1043710443 const gpa = sema.gpa;
1043810444 // This logic must be synchronized with that in `zirStructInit`.
1043910445 const struct_ty = try sema.resolveTypeFields(block, dest_src, obj_ty);
......@@ -10477,7 +10483,12 @@ fn zirUnionInitPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
1047710483 return sema.fail(block, src, "TODO: Sema.zirUnionInitPtr", .{});
1047810484}
1047910485
10480fn zirStructInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: bool) CompileError!Air.Inst.Ref {
10486fn zirStructInit(
10487 sema: *Sema,
10488 block: *Block,
10489 inst: Zir.Inst.Index,
10490 is_ref: bool,
10491) CompileError!Air.Inst.Ref {
1048110492 const gpa = sema.gpa;
1048210493 const zir_datas = sema.code.instructions.items(.data);
1048310494 const inst_data = zir_datas[inst].pl_node;
......@@ -10612,10 +10623,6 @@ fn finishStructInit(
1061210623 return sema.failWithOwnedErrorMsg(msg);
1061310624 }
1061410625
10615 if (is_ref) {
10616 return sema.fail(block, src, "TODO: Sema.zirStructInit is_ref=true", .{});
10617 }
10618
1061910626 const is_comptime = for (field_inits) |field_init| {
1062010627 if (!(try sema.isComptimeKnown(block, src, field_init))) {
1062110628 break false;
......@@ -10627,10 +10634,24 @@ fn finishStructInit(
1062710634 for (field_inits) |field_init, i| {
1062810635 values[i] = (sema.resolveMaybeUndefVal(block, src, field_init) catch unreachable).?;
1062910636 }
10630 return sema.addConstant(struct_ty, try Value.Tag.@"struct".create(sema.arena, values));
10637 const struct_val = try Value.Tag.@"struct".create(sema.arena, values);
10638 return sema.addConstantMaybeRef(block, src, struct_ty, struct_val, is_ref);
10639 }
10640
10641 if (is_ref) {
10642 const alloc = try block.addTy(.alloc, struct_ty);
10643 for (field_inits) |field_init, i_usize| {
10644 const i = @intCast(u32, i_usize);
10645 const field_src = src;
10646 const field_ptr = try sema.structFieldPtrByIndex(block, src, alloc, i, struct_obj, field_src);
10647 try sema.storePtr(block, src, field_ptr, field_init);
10648 }
10649
10650 return alloc;
1063110651 }
1063210652
10633 return sema.fail(block, src, "TODO: Sema.zirStructInit for runtime-known struct values", .{});
10653 try sema.requireRuntimeBlock(block, src);
10654 return block.addVectorInit(struct_ty, field_inits);
1063410655}
1063510656
1063610657fn zirStructInitAnon(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: bool) CompileError!Air.Inst.Ref {
......@@ -10674,51 +10695,43 @@ fn zirArrayInit(
1067410695 } else null;
1067510696
1067610697 const runtime_src = opt_runtime_src orelse {
10677 var anon_decl = try block.startAnonDecl(src);
10678 defer anon_decl.deinit();
10698 const elem_vals = try sema.arena.alloc(Value, resolved_args.len);
1067910699
10680 const elem_vals = try anon_decl.arena().alloc(Value, resolved_args.len);
1068110700 for (resolved_args) |arg, i| {
1068210701 // We checked that all args are comptime above.
10683 const arg_val = (sema.resolveMaybeUndefVal(block, src, arg) catch unreachable).?;
10684 elem_vals[i] = try arg_val.copy(anon_decl.arena());
10702 elem_vals[i] = (sema.resolveMaybeUndefVal(block, src, arg) catch unreachable).?;
1068510703 }
1068610704
10687 const val = try Value.Tag.array.create(anon_decl.arena(), elem_vals);
10688 const decl = try anon_decl.finish(try array_ty.copy(anon_decl.arena()), val);
10689 if (is_ref) {
10690 return sema.analyzeDeclRef(decl);
10691 } else {
10692 return sema.analyzeDeclVal(block, .unneeded, decl);
10693 }
10705 const array_val = try Value.Tag.array.create(sema.arena, elem_vals);
10706 return sema.addConstantMaybeRef(block, src, array_ty, array_val, is_ref);
1069410707 };
1069510708
1069610709 try sema.requireRuntimeBlock(block, runtime_src);
1069710710 try sema.resolveTypeLayout(block, src, elem_ty);
1069810711
10699 const alloc_ty = try Type.ptr(sema.arena, .{
10700 .pointee_type = array_ty,
10701 .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
10702 });
10703 const alloc = try block.addTy(.alloc, alloc_ty);
10712 if (is_ref) {
10713 const alloc_ty = try Type.ptr(sema.arena, .{
10714 .pointee_type = array_ty,
10715 .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
10716 });
10717 const alloc = try block.addTy(.alloc, alloc_ty);
1070410718
10705 const elem_ptr_ty = try Type.ptr(sema.arena, .{
10706 .mutable = true,
10707 .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
10708 .pointee_type = elem_ty,
10709 });
10710 const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty);
10719 const elem_ptr_ty = try Type.ptr(sema.arena, .{
10720 .mutable = true,
10721 .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
10722 .pointee_type = elem_ty,
10723 });
10724 const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty);
1071110725
10712 for (resolved_args) |arg, i| {
10713 const index = try sema.addIntUnsigned(Type.u64, i);
10714 const elem_ptr = try block.addPtrElemPtrTypeRef(alloc, index, elem_ptr_ty_ref);
10715 _ = try block.addBinOp(.store, elem_ptr, arg);
10716 }
10717 if (is_ref) {
10726 for (resolved_args) |arg, i| {
10727 const index = try sema.addIntUnsigned(Type.u64, i);
10728 const elem_ptr = try block.addPtrElemPtrTypeRef(alloc, index, elem_ptr_ty_ref);
10729 _ = try block.addBinOp(.store, elem_ptr, arg);
10730 }
1071810731 return alloc;
10719 } else {
10720 return sema.analyzeLoad(block, .unneeded, alloc, .unneeded);
1072110732 }
10733
10734 return block.addVectorInit(array_ty, resolved_args);
1072210735}
1072310736
1072410737fn zirArrayInitAnon(
......@@ -10758,17 +10771,11 @@ fn zirArrayInitAnon(
1075810771
1075910772 const runtime_src = opt_runtime_src orelse {
1076010773 const tuple_val = try Value.Tag.@"struct".create(sema.arena, values);
10761 if (!is_ref) return sema.addConstant(tuple_ty, tuple_val);
10762
10763 var anon_decl = try block.startAnonDecl(src);
10764 defer anon_decl.deinit();
10765 const decl = try anon_decl.finish(
10766 try tuple_ty.copy(anon_decl.arena()),
10767 try tuple_val.copy(anon_decl.arena()),
10768 );
10769 return sema.analyzeDeclRef(decl);
10774 return sema.addConstantMaybeRef(block, src, tuple_ty, tuple_val, is_ref);
1077010775 };
1077110776
10777 try sema.requireRuntimeBlock(block, runtime_src);
10778
1077210779 if (is_ref) {
1077310780 const alloc = try block.addTy(.alloc, tuple_ty);
1077410781 for (operands) |operand, i_usize| {
......@@ -10790,10 +10797,28 @@ fn zirArrayInitAnon(
1079010797 element_refs[i] = sema.resolveInst(operand);
1079110798 }
1079210799
10793 try sema.requireRuntimeBlock(block, runtime_src);
1079410800 return block.addVectorInit(tuple_ty, element_refs);
1079510801}
1079610802
10803fn addConstantMaybeRef(
10804 sema: *Sema,
10805 block: *Block,
10806 src: LazySrcLoc,
10807 ty: Type,
10808 val: Value,
10809 is_ref: bool,
10810) !Air.Inst.Ref {
10811 if (!is_ref) return sema.addConstant(ty, val);
10812
10813 var anon_decl = try block.startAnonDecl(src);
10814 defer anon_decl.deinit();
10815 const decl = try anon_decl.finish(
10816 try ty.copy(anon_decl.arena()),
10817 try val.copy(anon_decl.arena()),
10818 );
10819 return sema.analyzeDeclRef(decl);
10820}
10821
1079710822fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
1079810823 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1079910824 const src = inst_data.src();
......@@ -13444,18 +13469,30 @@ fn structFieldPtr(
1344413469 field_name_src: LazySrcLoc,
1344513470 unresolved_struct_ty: Type,
1344613471) CompileError!Air.Inst.Ref {
13447 const arena = sema.arena;
1344813472 assert(unresolved_struct_ty.zigTypeTag() == .Struct);
1344913473
13450 const struct_ptr_ty = sema.typeOf(struct_ptr);
1345113474 const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_ty);
1345213475 const struct_obj = struct_ty.castTag(.@"struct").?.data;
1345313476
1345413477 const field_index_big = struct_obj.fields.getIndex(field_name) orelse
1345513478 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name);
1345613479 const field_index = @intCast(u32, field_index_big);
13480
13481 return sema.structFieldPtrByIndex(block, src, struct_ptr, field_index, struct_obj, field_name_src);
13482}
13483
13484fn structFieldPtrByIndex(
13485 sema: *Sema,
13486 block: *Block,
13487 src: LazySrcLoc,
13488 struct_ptr: Air.Inst.Ref,
13489 field_index: u32,
13490 struct_obj: *Module.Struct,
13491 field_src: LazySrcLoc,
13492) CompileError!Air.Inst.Ref {
1345713493 const field = struct_obj.fields.values()[field_index];
1345813494
13495 const struct_ptr_ty = sema.typeOf(struct_ptr);
1345913496 var ptr_ty_data: Type.Payload.Pointer.Data = .{
1346013497 .pointee_type = field.ty,
1346113498 .mutable = struct_ptr_ty.ptrIsMutable(),
......@@ -13470,7 +13507,7 @@ fn structFieldPtr(
1347013507 var offset: u64 = 0;
1347113508 var running_bits: u16 = 0;
1347213509 for (struct_obj.fields.values()) |f, i| {
13473 if (!(try sema.typeHasRuntimeBits(block, field_name_src, f.ty))) continue;
13510 if (!(try sema.typeHasRuntimeBits(block, field_src, f.ty))) continue;
1347413511
1347513512 const field_align = f.packedAlignment();
1347613513 if (field_align == 0) {
......@@ -13509,12 +13546,12 @@ fn structFieldPtr(
1350913546 const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
1351013547 ptr_ty_data.host_size = @intCast(u16, int_ty.abiSize(target));
1351113548 }
13512 const ptr_field_ty = try Type.ptr(arena, ptr_ty_data);
13549 const ptr_field_ty = try Type.ptr(sema.arena, ptr_ty_data);
1351313550
1351413551 if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| {
1351513552 return sema.addConstant(
1351613553 ptr_field_ty,
13517 try Value.Tag.field_ptr.create(arena, .{
13554 try Value.Tag.field_ptr.create(sema.arena, .{
1351813555 .container_ptr = struct_ptr_val,
1351913556 .field_index = field_index,
1352013557 }),
......@@ -13546,6 +13583,9 @@ fn structFieldVal(
1354613583
1354713584 if (try sema.resolveMaybeUndefVal(block, src, struct_byval)) |struct_val| {
1354813585 if (struct_val.isUndef()) return sema.addConstUndef(field.ty);
13586 if ((try sema.typeHasOnePossibleValue(block, src, field.ty))) |opv| {
13587 return sema.addConstant(field.ty, opv);
13588 }
1354913589
1355013590 const field_values = struct_val.castTag(.@"struct").?.data;
1355113591 return sema.addConstant(field.ty, field_values[field_index]);
src/value.zig+138-98
......@@ -1530,60 +1530,69 @@ pub const Value = extern union {
15301530 const b_tag = b.tag();
15311531 assert(a_tag != .undef);
15321532 assert(b_tag != .undef);
1533 if (a_tag == b_tag) {
1534 switch (a_tag) {
1535 .void_value, .null_value, .the_only_possible_value => return true,
1536 .enum_literal => {
1537 const a_name = a.castTag(.enum_literal).?.data;
1538 const b_name = b.castTag(.enum_literal).?.data;
1539 return std.mem.eql(u8, a_name, b_name);
1540 },
1541 .enum_field_index => {
1542 const a_field_index = a.castTag(.enum_field_index).?.data;
1543 const b_field_index = b.castTag(.enum_field_index).?.data;
1544 return a_field_index == b_field_index;
1545 },
1546 .opt_payload => {
1547 const a_payload = a.castTag(.opt_payload).?.data;
1548 const b_payload = b.castTag(.opt_payload).?.data;
1549 var buffer: Type.Payload.ElemType = undefined;
1550 return eql(a_payload, b_payload, ty.optionalChild(&buffer));
1551 },
1552 .slice => {
1553 const a_payload = a.castTag(.slice).?.data;
1554 const b_payload = b.castTag(.slice).?.data;
1555 if (!eql(a_payload.len, b_payload.len, Type.usize)) return false;
1533 if (a_tag == b_tag) switch (a_tag) {
1534 .void_value, .null_value, .the_only_possible_value => return true,
1535 .enum_literal => {
1536 const a_name = a.castTag(.enum_literal).?.data;
1537 const b_name = b.castTag(.enum_literal).?.data;
1538 return std.mem.eql(u8, a_name, b_name);
1539 },
1540 .enum_field_index => {
1541 const a_field_index = a.castTag(.enum_field_index).?.data;
1542 const b_field_index = b.castTag(.enum_field_index).?.data;
1543 return a_field_index == b_field_index;
1544 },
1545 .opt_payload => {
1546 const a_payload = a.castTag(.opt_payload).?.data;
1547 const b_payload = b.castTag(.opt_payload).?.data;
1548 var buffer: Type.Payload.ElemType = undefined;
1549 return eql(a_payload, b_payload, ty.optionalChild(&buffer));
1550 },
1551 .slice => {
1552 const a_payload = a.castTag(.slice).?.data;
1553 const b_payload = b.castTag(.slice).?.data;
1554 if (!eql(a_payload.len, b_payload.len, Type.usize)) return false;
15561555
1557 var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined;
1558 const ptr_ty = ty.slicePtrFieldType(&ptr_buf);
1556 var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined;
1557 const ptr_ty = ty.slicePtrFieldType(&ptr_buf);
15591558
1560 return eql(a_payload.ptr, b_payload.ptr, ptr_ty);
1561 },
1562 .elem_ptr => @panic("TODO: Implement more pointer eql cases"),
1563 .field_ptr => @panic("TODO: Implement more pointer eql cases"),
1564 .eu_payload_ptr => @panic("TODO: Implement more pointer eql cases"),
1565 .opt_payload_ptr => @panic("TODO: Implement more pointer eql cases"),
1566 .array => {
1567 const a_array = a.castTag(.array).?.data;
1568 const b_array = b.castTag(.array).?.data;
1569
1570 if (a_array.len != b_array.len) return false;
1571
1572 const elem_ty = ty.childType();
1573 for (a_array) |a_elem, i| {
1574 const b_elem = b_array[i];
1575
1576 if (!eql(a_elem, b_elem, elem_ty)) return false;
1577 }
1578 return true;
1579 },
1580 .function => {
1581 const a_payload = a.castTag(.function).?.data;
1582 const b_payload = b.castTag(.function).?.data;
1583 return a_payload == b_payload;
1584 },
1585 else => {},
1586 }
1559 return eql(a_payload.ptr, b_payload.ptr, ptr_ty);
1560 },
1561 .elem_ptr => @panic("TODO: Implement more pointer eql cases"),
1562 .field_ptr => @panic("TODO: Implement more pointer eql cases"),
1563 .eu_payload_ptr => @panic("TODO: Implement more pointer eql cases"),
1564 .opt_payload_ptr => @panic("TODO: Implement more pointer eql cases"),
1565 .array => {
1566 const a_array = a.castTag(.array).?.data;
1567 const b_array = b.castTag(.array).?.data;
1568
1569 if (a_array.len != b_array.len) return false;
1570
1571 const elem_ty = ty.childType();
1572 for (a_array) |a_elem, i| {
1573 const b_elem = b_array[i];
1574
1575 if (!eql(a_elem, b_elem, elem_ty)) return false;
1576 }
1577 return true;
1578 },
1579 .function => {
1580 const a_payload = a.castTag(.function).?.data;
1581 const b_payload = b.castTag(.function).?.data;
1582 return a_payload == b_payload;
1583 },
1584 .@"struct" => {
1585 const fields = ty.structFields().values();
1586 const a_field_vals = a.castTag(.@"struct").?.data;
1587 const b_field_vals = b.castTag(.@"struct").?.data;
1588 assert(a_field_vals.len == b_field_vals.len);
1589 assert(fields.len == a_field_vals.len);
1590 for (fields) |field, i| {
1591 if (!eql(a_field_vals[i], b_field_vals[i], field.ty)) return false;
1592 }
1593 return true;
1594 },
1595 else => {},
15871596 } else if (a_tag == .null_value or b_tag == .null_value) {
15881597 return false;
15891598 }
......@@ -1628,6 +1637,13 @@ pub const Value = extern union {
16281637 }
16291638 return true;
16301639 },
1640 .Struct => {
1641 // must be a struct with no fields since we checked for if
1642 // both have the struct tag above.
1643 const fields = ty.structFields().values();
1644 assert(fields.len == 0);
1645 return true;
1646 },
16311647 else => return order(a, b).compare(.eq),
16321648 }
16331649 }
......@@ -1651,31 +1667,13 @@ pub const Value = extern union {
16511667 var buf: ToTypeBuffer = undefined;
16521668 return val.toType(&buf).hashWithHasher(hasher);
16531669 },
1654 .Bool => {
1655 std.hash.autoHash(hasher, val.toBool());
1656 },
1657 .Int, .ComptimeInt => {
1658 var space: BigIntSpace = undefined;
1659 const big = val.toBigInt(&space);
1660 std.hash.autoHash(hasher, big.positive);
1661 for (big.limbs) |limb| {
1662 std.hash.autoHash(hasher, limb);
1663 }
1664 },
16651670 .Float, .ComptimeFloat => {
16661671 // TODO double check the lang spec. should we to bitwise hashing here,
16671672 // or a hash that normalizes the float value?
16681673 const float = val.toFloat(f128);
16691674 std.hash.autoHash(hasher, @bitCast(u128, float));
16701675 },
1671 .Pointer => switch (val.tag()) {
1672 .decl_ref_mut,
1673 .extern_fn,
1674 .decl_ref,
1675 .function,
1676 .variable,
1677 => std.hash.autoHash(hasher, val.pointerDecl().?),
1678
1676 .Bool, .Int, .ComptimeInt, .Pointer => switch (val.tag()) {
16791677 .slice => {
16801678 const slice = val.castTag(.slice).?.data;
16811679 var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined;
......@@ -1684,22 +1682,7 @@ pub const Value = extern union {
16841682 hash(slice.len, Type.usize, hasher);
16851683 },
16861684
1687 // For these, hash them as hash of a pointer to the decl,
1688 // combined with a hash of the byte offset from the decl.
1689 .elem_ptr => @panic("TODO: Implement more pointer hashing cases"),
1690 .field_ptr => @panic("TODO: Implement more pointer hashing cases"),
1691 .eu_payload_ptr => @panic("TODO: Implement more pointer hashing cases"),
1692 .opt_payload_ptr => @panic("TODO: Implement more pointer hashing cases"),
1693
1694 .zero,
1695 .one,
1696 .int_u64,
1697 .int_i64,
1698 .int_big_positive,
1699 .int_big_negative,
1700 => @panic("TODO: Implement pointer hashing for int pointers"),
1701
1702 else => unreachable,
1685 else => return hashPtr(val, hasher),
17031686 },
17041687 .Array, .Vector => {
17051688 const len = ty.arrayLen();
......@@ -1739,14 +1722,7 @@ pub const Value = extern union {
17391722 .Enum => {
17401723 var enum_space: Payload.U64 = undefined;
17411724 const int_val = val.enumToInt(ty, &enum_space);
1742
1743 var space: BigIntSpace = undefined;
1744 const big = int_val.toBigInt(&space);
1745
1746 std.hash.autoHash(hasher, big.positive);
1747 for (big.limbs) |limb| {
1748 std.hash.autoHash(hasher, limb);
1749 }
1725 hashInt(int_val, hasher);
17501726 },
17511727 .Union => {
17521728 const union_obj = val.cast(Payload.Union).?.data;
......@@ -1757,8 +1733,12 @@ pub const Value = extern union {
17571733 union_obj.val.hash(active_field_ty, hasher);
17581734 },
17591735 .Fn => {
1760 const func = val.castTag(.function).?.data;
1761 return std.hash.autoHash(hasher, func.owner_decl);
1736 const func: *Module.Fn = val.castTag(.function).?.data;
1737 // Note that his hashes the *Fn rather than the *Decl. This is
1738 // to differentiate function bodies from function pointers.
1739 // This is currently redundant since we already hash the zig type tag
1740 // at the top of this function.
1741 std.hash.autoHash(hasher, func);
17621742 },
17631743 .Frame => {
17641744 @panic("TODO implement hashing frame values");
......@@ -1824,6 +1804,65 @@ pub const Value = extern union {
18241804 };
18251805 }
18261806
1807 fn hashInt(int_val: Value, hasher: *std.hash.Wyhash) void {
1808 var buffer: BigIntSpace = undefined;
1809 const big = int_val.toBigInt(&buffer);
1810 std.hash.autoHash(hasher, big.positive);
1811 for (big.limbs) |limb| {
1812 std.hash.autoHash(hasher, limb);
1813 }
1814 }
1815
1816 fn hashPtr(ptr_val: Value, hasher: *std.hash.Wyhash) void {
1817 switch (ptr_val.tag()) {
1818 .decl_ref,
1819 .decl_ref_mut,
1820 .extern_fn,
1821 .function,
1822 .variable,
1823 => {
1824 const decl: *Module.Decl = ptr_val.pointerDecl().?;
1825 std.hash.autoHash(hasher, decl);
1826 },
1827
1828 .elem_ptr => {
1829 const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;
1830 hashPtr(elem_ptr.array_ptr, hasher);
1831 std.hash.autoHash(hasher, Value.Tag.elem_ptr);
1832 std.hash.autoHash(hasher, elem_ptr.index);
1833 },
1834 .field_ptr => {
1835 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
1836 std.hash.autoHash(hasher, Value.Tag.field_ptr);
1837 hashPtr(field_ptr.container_ptr, hasher);
1838 std.hash.autoHash(hasher, field_ptr.field_index);
1839 },
1840 .eu_payload_ptr => {
1841 const err_union_ptr = ptr_val.castTag(.eu_payload_ptr).?.data;
1842 std.hash.autoHash(hasher, Value.Tag.eu_payload_ptr);
1843 hashPtr(err_union_ptr, hasher);
1844 },
1845 .opt_payload_ptr => {
1846 const opt_ptr = ptr_val.castTag(.opt_payload_ptr).?.data;
1847 std.hash.autoHash(hasher, Value.Tag.opt_payload_ptr);
1848 hashPtr(opt_ptr, hasher);
1849 },
1850
1851 .zero,
1852 .one,
1853 .int_u64,
1854 .int_i64,
1855 .int_big_positive,
1856 .int_big_negative,
1857 .bool_false,
1858 .bool_true,
1859 .the_only_possible_value,
1860 => return hashInt(ptr_val, hasher),
1861
1862 else => unreachable,
1863 }
1864 }
1865
18271866 pub fn markReferencedDeclsAlive(val: Value) void {
18281867 switch (val.tag()) {
18291868 .decl_ref_mut => return val.castTag(.decl_ref_mut).?.data.decl.markAlive(),
......@@ -1876,7 +1915,8 @@ pub const Value = extern union {
18761915 pub fn slicePtr(val: Value) Value {
18771916 return switch (val.tag()) {
18781917 .slice => val.castTag(.slice).?.data.ptr,
1879 .decl_ref, .decl_ref_mut => val,
1918 // TODO this should require being a slice tag, and not allow decl_ref, field_ptr, etc.
1919 .decl_ref, .decl_ref_mut, .field_ptr, .elem_ptr => val,
18801920 else => unreachable,
18811921 };
18821922 }
test/behavior.zig-3
......@@ -98,7 +98,6 @@ test {
9898 _ = @import("behavior/bugs/3007.zig");
9999 _ = @import("behavior/bugs/9584.zig");
100100 _ = @import("behavior/cast_llvm.zig");
101 _ = @import("behavior/enum_llvm.zig");
102101 _ = @import("behavior/error_llvm.zig");
103102 _ = @import("behavior/eval.zig");
104103 _ = @import("behavior/floatop.zig");
......@@ -163,9 +162,7 @@ test {
163162 _ = @import("behavior/muladd.zig");
164163 _ = @import("behavior/null_stage1.zig");
165164 _ = @import("behavior/optional_stage1.zig");
166 _ = @import("behavior/pointers_stage1.zig");
167165 _ = @import("behavior/popcount_stage1.zig");
168 _ = @import("behavior/ptrcast_stage1.zig");
169166 _ = @import("behavior/reflection.zig");
170167 _ = @import("behavior/saturating_arithmetic_stage1.zig");
171168 _ = @import("behavior/select.zig");
test/behavior/enum.zig+113
......@@ -972,3 +972,116 @@ fn test3_2(f: Test3Foo) !void {
972972 else => unreachable,
973973 }
974974}
975
976test "@tagName" {
977 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
978 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
979
980 try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
981 comptime try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
982}
983
984fn testEnumTagNameBare(n: anytype) []const u8 {
985 return @tagName(n);
986}
987
988const BareNumber = enum { One, Two, Three };
989
990test "@tagName non-exhaustive enum" {
991 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
992 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
993
994 try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
995 comptime try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
996}
997const NonExhaustive = enum(u8) { A, B, _ };
998
999test "@tagName is null-terminated" {
1000 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1001 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1002
1003 const S = struct {
1004 fn doTheTest(n: BareNumber) !void {
1005 try expect(@tagName(n)[3] == 0);
1006 }
1007 };
1008 try S.doTheTest(.Two);
1009 try comptime S.doTheTest(.Two);
1010}
1011
1012test "tag name with assigned enum values" {
1013 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1014 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1015
1016 const LocalFoo = enum(u8) {
1017 A = 1,
1018 B = 0,
1019 };
1020 var b = LocalFoo.B;
1021 try expect(mem.eql(u8, @tagName(b), "B"));
1022}
1023
1024test "@tagName on enum literals" {
1025 try expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));
1026 comptime try expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));
1027}
1028
1029test "enum literal casting to optional" {
1030 var bar: ?Bar = undefined;
1031 bar = .B;
1032
1033 try expect(bar.? == Bar.B);
1034}
1035
1036const A = enum(u3) { One, Two, Three, Four, One2, Two2, Three2, Four2 };
1037const B = enum(u3) { One3, Two3, Three3, Four3, One23, Two23, Three23, Four23 };
1038const C = enum(u2) { One4, Two4, Three4, Four4 };
1039
1040const BitFieldOfEnums = packed struct {
1041 a: A,
1042 b: B,
1043 c: C,
1044};
1045
1046const bit_field_1 = BitFieldOfEnums{
1047 .a = A.Two,
1048 .b = B.Three3,
1049 .c = C.Four4,
1050};
1051
1052test "bit field access with enum fields" {
1053 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1054
1055 var data = bit_field_1;
1056 try expect(getA(&data) == A.Two);
1057 try expect(getB(&data) == B.Three3);
1058 try expect(getC(&data) == C.Four4);
1059 comptime try expect(@sizeOf(BitFieldOfEnums) == 1);
1060
1061 data.b = B.Four3;
1062 try expect(data.b == B.Four3);
1063
1064 data.a = A.Three;
1065 try expect(data.a == A.Three);
1066 try expect(data.b == B.Four3);
1067}
1068
1069fn getA(data: *const BitFieldOfEnums) A {
1070 return data.a;
1071}
1072
1073fn getB(data: *const BitFieldOfEnums) B {
1074 return data.b;
1075}
1076
1077fn getC(data: *const BitFieldOfEnums) C {
1078 return data.c;
1079}
1080
1081test "enum literal in array literal" {
1082 const Items = enum { one, two };
1083 const array = [_]Items{ .one, .two };
1084
1085 try expect(array[0] == .one);
1086 try expect(array[1] == .two);
1087}
test/behavior/enum_llvm.zig deleted-105
......@@ -1,105 +0,0 @@
1const std = @import("std");
2const expect = std.testing.expect;
3const mem = std.mem;
4const Tag = std.meta.Tag;
5
6test "@tagName" {
7 try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
8 comptime try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
9}
10
11fn testEnumTagNameBare(n: anytype) []const u8 {
12 return @tagName(n);
13}
14
15const BareNumber = enum { One, Two, Three };
16
17test "@tagName non-exhaustive enum" {
18 try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
19 comptime try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
20}
21const NonExhaustive = enum(u8) { A, B, _ };
22
23test "@tagName is null-terminated" {
24 const S = struct {
25 fn doTheTest(n: BareNumber) !void {
26 try expect(@tagName(n)[3] == 0);
27 }
28 };
29 try S.doTheTest(.Two);
30 try comptime S.doTheTest(.Two);
31}
32
33test "tag name with assigned enum values" {
34 const LocalFoo = enum(u8) {
35 A = 1,
36 B = 0,
37 };
38 var b = LocalFoo.B;
39 try expect(mem.eql(u8, @tagName(b), "B"));
40}
41
42test "@tagName on enum literals" {
43 try expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));
44 comptime try expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));
45}
46
47const Bar = enum { A, B, C, D };
48
49test "enum literal casting to optional" {
50 var bar: ?Bar = undefined;
51 bar = .B;
52
53 try expect(bar.? == Bar.B);
54}
55
56const A = enum(u3) { One, Two, Three, Four, One2, Two2, Three2, Four2 };
57const B = enum(u3) { One3, Two3, Three3, Four3, One23, Two23, Three23, Four23 };
58const C = enum(u2) { One4, Two4, Three4, Four4 };
59
60const BitFieldOfEnums = packed struct {
61 a: A,
62 b: B,
63 c: C,
64};
65
66const bit_field_1 = BitFieldOfEnums{
67 .a = A.Two,
68 .b = B.Three3,
69 .c = C.Four4,
70};
71
72test "bit field access with enum fields" {
73 var data = bit_field_1;
74 try expect(getA(&data) == A.Two);
75 try expect(getB(&data) == B.Three3);
76 try expect(getC(&data) == C.Four4);
77 comptime try expect(@sizeOf(BitFieldOfEnums) == 1);
78
79 data.b = B.Four3;
80 try expect(data.b == B.Four3);
81
82 data.a = A.Three;
83 try expect(data.a == A.Three);
84 try expect(data.b == B.Four3);
85}
86
87fn getA(data: *const BitFieldOfEnums) A {
88 return data.a;
89}
90
91fn getB(data: *const BitFieldOfEnums) B {
92 return data.b;
93}
94
95fn getC(data: *const BitFieldOfEnums) C {
96 return data.c;
97}
98
99test "enum literal in array literal" {
100 const Items = enum { one, two };
101 const array = [_]Items{ .one, .two };
102
103 try expect(array[0] == .one);
104 try expect(array[1] == .two);
105}
test/behavior/pointers.zig+282
......@@ -1,3 +1,4 @@
1const builtin = @import("builtin");
12const std = @import("std");
23const testing = std.testing;
34const expect = testing.expect;
......@@ -97,3 +98,284 @@ test "C pointer comparison and arithmetic" {
9798 try S.doTheTest();
9899 comptime try S.doTheTest();
99100}
101
102test "dereference pointer again" {
103 try testDerefPtrOneVal();
104 comptime try testDerefPtrOneVal();
105}
106
107const Foo1 = struct {
108 x: void,
109};
110
111fn testDerefPtrOneVal() !void {
112 // Foo1 satisfies the OnePossibleValueYes criteria
113 const x = &Foo1{ .x = {} };
114 const y = x.*;
115 try expect(@TypeOf(y.x) == void);
116}
117
118test "peer type resolution with C pointers" {
119 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
120
121 var ptr_one: *u8 = undefined;
122 var ptr_many: [*]u8 = undefined;
123 var ptr_c: [*c]u8 = undefined;
124 var t = true;
125 var x1 = if (t) ptr_one else ptr_c;
126 var x2 = if (t) ptr_many else ptr_c;
127 var x3 = if (t) ptr_c else ptr_one;
128 var x4 = if (t) ptr_c else ptr_many;
129 try expect(@TypeOf(x1) == [*c]u8);
130 try expect(@TypeOf(x2) == [*c]u8);
131 try expect(@TypeOf(x3) == [*c]u8);
132 try expect(@TypeOf(x4) == [*c]u8);
133}
134
135test "implicit casting between C pointer and optional non-C pointer" {
136 var slice: []const u8 = "aoeu";
137 const opt_many_ptr: ?[*]const u8 = slice.ptr;
138 var ptr_opt_many_ptr = &opt_many_ptr;
139 var c_ptr: [*c]const [*c]const u8 = ptr_opt_many_ptr;
140 try expect(c_ptr.*.* == 'a');
141 ptr_opt_many_ptr = c_ptr;
142 try expect(ptr_opt_many_ptr.*.?[1] == 'o');
143}
144
145test "implicit cast error unions with non-optional to optional pointer" {
146 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
147
148 const S = struct {
149 fn doTheTest() !void {
150 try expectError(error.Fail, foo());
151 }
152 fn foo() anyerror!?*u8 {
153 return bar() orelse error.Fail;
154 }
155 fn bar() ?*u8 {
156 return null;
157 }
158 };
159 try S.doTheTest();
160 comptime try S.doTheTest();
161}
162
163test "compare equality of optional and non-optional pointer" {
164 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
165
166 const a = @intToPtr(*const usize, 0x12345678);
167 const b = @intToPtr(?*usize, 0x12345678);
168 try expect(a == b);
169 try expect(b == a);
170}
171
172test "allowzero pointer and slice" {
173 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
174 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
175
176 var ptr = @intToPtr([*]allowzero i32, 0);
177 var opt_ptr: ?[*]allowzero i32 = ptr;
178 try expect(opt_ptr != null);
179 try expect(@ptrToInt(ptr) == 0);
180 var runtime_zero: usize = 0;
181 var slice = ptr[runtime_zero..10];
182 comptime try expect(@TypeOf(slice) == []allowzero i32);
183 try expect(@ptrToInt(&slice[5]) == 20);
184
185 comptime try expect(@typeInfo(@TypeOf(ptr)).Pointer.is_allowzero);
186 comptime try expect(@typeInfo(@TypeOf(slice)).Pointer.is_allowzero);
187}
188
189test "assign null directly to C pointer and test null equality" {
190 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
191
192 var x: [*c]i32 = null;
193 try expect(x == null);
194 try expect(null == x);
195 try expect(!(x != null));
196 try expect(!(null != x));
197 if (x) |same_x| {
198 _ = same_x;
199 @panic("fail");
200 }
201 var otherx: i32 = undefined;
202 try expect((x orelse &otherx) == &otherx);
203
204 const y: [*c]i32 = null;
205 comptime try expect(y == null);
206 comptime try expect(null == y);
207 comptime try expect(!(y != null));
208 comptime try expect(!(null != y));
209 if (y) |same_y| {
210 _ = same_y;
211 @panic("fail");
212 }
213 const othery: i32 = undefined;
214 comptime try expect((y orelse &othery) == &othery);
215
216 var n: i32 = 1234;
217 var x1: [*c]i32 = &n;
218 try expect(!(x1 == null));
219 try expect(!(null == x1));
220 try expect(x1 != null);
221 try expect(null != x1);
222 try expect(x1.?.* == 1234);
223 if (x1) |same_x1| {
224 try expect(same_x1.* == 1234);
225 } else {
226 @panic("fail");
227 }
228 try expect((x1 orelse &otherx) == x1);
229
230 const nc: i32 = 1234;
231 const y1: [*c]const i32 = &nc;
232 comptime try expect(!(y1 == null));
233 comptime try expect(!(null == y1));
234 comptime try expect(y1 != null);
235 comptime try expect(null != y1);
236 comptime try expect(y1.?.* == 1234);
237 if (y1) |same_y1| {
238 try expect(same_y1.* == 1234);
239 } else {
240 @compileError("fail");
241 }
242 comptime try expect((y1 orelse &othery) == y1);
243}
244
245test "null terminated pointer" {
246 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
247
248 const S = struct {
249 fn doTheTest() !void {
250 var array_with_zero = [_:0]u8{ 'h', 'e', 'l', 'l', 'o' };
251 var zero_ptr: [*:0]const u8 = @ptrCast([*:0]const u8, &array_with_zero);
252 var no_zero_ptr: [*]const u8 = zero_ptr;
253 var zero_ptr_again = @ptrCast([*:0]const u8, no_zero_ptr);
254 try expect(std.mem.eql(u8, std.mem.sliceTo(zero_ptr_again, 0), "hello"));
255 }
256 };
257 try S.doTheTest();
258 comptime try S.doTheTest();
259}
260
261test "allow any sentinel" {
262 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
263
264 const S = struct {
265 fn doTheTest() !void {
266 var array = [_:std.math.minInt(i32)]i32{ 1, 2, 3, 4 };
267 var ptr: [*:std.math.minInt(i32)]i32 = &array;
268 try expect(ptr[4] == std.math.minInt(i32));
269 }
270 };
271 try S.doTheTest();
272 comptime try S.doTheTest();
273}
274
275test "pointer sentinel with enums" {
276 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
277
278 const S = struct {
279 const Number = enum {
280 one,
281 two,
282 sentinel,
283 };
284
285 fn doTheTest() !void {
286 var ptr: [*:.sentinel]const Number = &[_:.sentinel]Number{ .one, .two, .two, .one };
287 try expect(ptr[4] == .sentinel); // TODO this should be comptime try expect, see #3731
288 }
289 };
290 try S.doTheTest();
291 comptime try S.doTheTest();
292}
293
294test "pointer sentinel with optional element" {
295 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
296
297 const S = struct {
298 fn doTheTest() !void {
299 var ptr: [*:null]const ?i32 = &[_:null]?i32{ 1, 2, 3, 4 };
300 try expect(ptr[4] == null); // TODO this should be comptime try expect, see #3731
301 }
302 };
303 try S.doTheTest();
304 comptime try S.doTheTest();
305}
306
307test "pointer sentinel with +inf" {
308 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
309
310 const S = struct {
311 fn doTheTest() !void {
312 const inf = std.math.inf_f32;
313 var ptr: [*:inf]const f32 = &[_:inf]f32{ 1.1, 2.2, 3.3, 4.4 };
314 try expect(ptr[4] == inf); // TODO this should be comptime try expect, see #3731
315 }
316 };
317 try S.doTheTest();
318 comptime try S.doTheTest();
319}
320
321test "pointer to array at fixed address" {
322 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
323
324 const array = @intToPtr(*volatile [1]u32, 0x10);
325 // Silly check just to reference `array`
326 try expect(@ptrToInt(&array[0]) == 0x10);
327}
328
329test "pointer arithmetic affects the alignment" {
330 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
331
332 {
333 var ptr: [*]align(8) u32 = undefined;
334 var x: usize = 1;
335
336 try expect(@typeInfo(@TypeOf(ptr)).Pointer.alignment == 8);
337 const ptr1 = ptr + 1; // 1 * 4 = 4 -> lcd(4,8) = 4
338 try expect(@typeInfo(@TypeOf(ptr1)).Pointer.alignment == 4);
339 const ptr2 = ptr + 4; // 4 * 4 = 16 -> lcd(16,8) = 8
340 try expect(@typeInfo(@TypeOf(ptr2)).Pointer.alignment == 8);
341 const ptr3 = ptr + 0; // no-op
342 try expect(@typeInfo(@TypeOf(ptr3)).Pointer.alignment == 8);
343 const ptr4 = ptr + x; // runtime-known addend
344 try expect(@typeInfo(@TypeOf(ptr4)).Pointer.alignment == 4);
345 }
346 {
347 var ptr: [*]align(8) [3]u8 = undefined;
348 var x: usize = 1;
349
350 const ptr1 = ptr + 17; // 3 * 17 = 51
351 try expect(@typeInfo(@TypeOf(ptr1)).Pointer.alignment == 1);
352 const ptr2 = ptr + x; // runtime-known addend
353 try expect(@typeInfo(@TypeOf(ptr2)).Pointer.alignment == 1);
354 const ptr3 = ptr + 8; // 3 * 8 = 24 -> lcd(8,24) = 8
355 try expect(@typeInfo(@TypeOf(ptr3)).Pointer.alignment == 8);
356 const ptr4 = ptr + 4; // 3 * 4 = 12 -> lcd(8,12) = 4
357 try expect(@typeInfo(@TypeOf(ptr4)).Pointer.alignment == 4);
358 }
359}
360
361test "@ptrToInt on null optional at comptime" {
362 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
363
364 {
365 const pointer = @intToPtr(?*u8, 0x000);
366 const x = @ptrToInt(pointer);
367 _ = x;
368 comptime try expect(0 == @ptrToInt(pointer));
369 }
370 {
371 const pointer = @intToPtr(?*u8, 0xf00);
372 comptime try expect(0xf00 == @ptrToInt(pointer));
373 }
374}
375
376test "indexing array with sentinel returns correct type" {
377 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
378
379 var s: [:0]const u8 = "abc";
380 try testing.expectEqualSlices(u8, "*const u8", @typeName(@TypeOf(&s[0])));
381}
test/behavior/pointers_stage1.zig deleted-256
......@@ -1,256 +0,0 @@
1const std = @import("std");
2const testing = std.testing;
3const expect = testing.expect;
4const expectError = testing.expectError;
5
6const Foo1 = struct {
7 x: void,
8};
9
10test "dereference pointer again" {
11 try testDerefPtrOneVal();
12 comptime try testDerefPtrOneVal();
13}
14
15fn testDerefPtrOneVal() !void {
16 // Foo1 satisfies the OnePossibleValueYes criteria
17 const x = &Foo1{ .x = {} };
18 const y = x.*;
19 try expect(@TypeOf(y.x) == void);
20}
21
22test "peer type resolution with C pointers" {
23 var ptr_one: *u8 = undefined;
24 var ptr_many: [*]u8 = undefined;
25 var ptr_c: [*c]u8 = undefined;
26 var t = true;
27 var x1 = if (t) ptr_one else ptr_c;
28 var x2 = if (t) ptr_many else ptr_c;
29 var x3 = if (t) ptr_c else ptr_one;
30 var x4 = if (t) ptr_c else ptr_many;
31 try expect(@TypeOf(x1) == [*c]u8);
32 try expect(@TypeOf(x2) == [*c]u8);
33 try expect(@TypeOf(x3) == [*c]u8);
34 try expect(@TypeOf(x4) == [*c]u8);
35}
36
37test "implicit casting between C pointer and optional non-C pointer" {
38 var slice: []const u8 = "aoeu";
39 const opt_many_ptr: ?[*]const u8 = slice.ptr;
40 var ptr_opt_many_ptr = &opt_many_ptr;
41 var c_ptr: [*c]const [*c]const u8 = ptr_opt_many_ptr;
42 try expect(c_ptr.*.* == 'a');
43 ptr_opt_many_ptr = c_ptr;
44 try expect(ptr_opt_many_ptr.*.?[1] == 'o');
45}
46
47test "implicit cast error unions with non-optional to optional pointer" {
48 const S = struct {
49 fn doTheTest() !void {
50 try expectError(error.Fail, foo());
51 }
52 fn foo() anyerror!?*u8 {
53 return bar() orelse error.Fail;
54 }
55 fn bar() ?*u8 {
56 return null;
57 }
58 };
59 try S.doTheTest();
60 comptime try S.doTheTest();
61}
62
63test "compare equality of optional and non-optional pointer" {
64 const a = @intToPtr(*const usize, 0x12345678);
65 const b = @intToPtr(?*usize, 0x12345678);
66 try expect(a == b);
67 try expect(b == a);
68}
69
70test "allowzero pointer and slice" {
71 var ptr = @intToPtr([*]allowzero i32, 0);
72 var opt_ptr: ?[*]allowzero i32 = ptr;
73 try expect(opt_ptr != null);
74 try expect(@ptrToInt(ptr) == 0);
75 var runtime_zero: usize = 0;
76 var slice = ptr[runtime_zero..10];
77 comptime try expect(@TypeOf(slice) == []allowzero i32);
78 try expect(@ptrToInt(&slice[5]) == 20);
79
80 comptime try expect(@typeInfo(@TypeOf(ptr)).Pointer.is_allowzero);
81 comptime try expect(@typeInfo(@TypeOf(slice)).Pointer.is_allowzero);
82}
83
84test "assign null directly to C pointer and test null equality" {
85 var x: [*c]i32 = null;
86 try expect(x == null);
87 try expect(null == x);
88 try expect(!(x != null));
89 try expect(!(null != x));
90 if (x) |same_x| {
91 _ = same_x;
92 @panic("fail");
93 }
94 var otherx: i32 = undefined;
95 try expect((x orelse &otherx) == &otherx);
96
97 const y: [*c]i32 = null;
98 comptime try expect(y == null);
99 comptime try expect(null == y);
100 comptime try expect(!(y != null));
101 comptime try expect(!(null != y));
102 if (y) |same_y| {
103 _ = same_y;
104 @panic("fail");
105 }
106 const othery: i32 = undefined;
107 comptime try expect((y orelse &othery) == &othery);
108
109 var n: i32 = 1234;
110 var x1: [*c]i32 = &n;
111 try expect(!(x1 == null));
112 try expect(!(null == x1));
113 try expect(x1 != null);
114 try expect(null != x1);
115 try expect(x1.?.* == 1234);
116 if (x1) |same_x1| {
117 try expect(same_x1.* == 1234);
118 } else {
119 @panic("fail");
120 }
121 try expect((x1 orelse &otherx) == x1);
122
123 const nc: i32 = 1234;
124 const y1: [*c]const i32 = &nc;
125 comptime try expect(!(y1 == null));
126 comptime try expect(!(null == y1));
127 comptime try expect(y1 != null);
128 comptime try expect(null != y1);
129 comptime try expect(y1.?.* == 1234);
130 if (y1) |same_y1| {
131 try expect(same_y1.* == 1234);
132 } else {
133 @compileError("fail");
134 }
135 comptime try expect((y1 orelse &othery) == y1);
136}
137
138test "null terminated pointer" {
139 const S = struct {
140 fn doTheTest() !void {
141 var array_with_zero = [_:0]u8{ 'h', 'e', 'l', 'l', 'o' };
142 var zero_ptr: [*:0]const u8 = @ptrCast([*:0]const u8, &array_with_zero);
143 var no_zero_ptr: [*]const u8 = zero_ptr;
144 var zero_ptr_again = @ptrCast([*:0]const u8, no_zero_ptr);
145 try expect(std.mem.eql(u8, std.mem.sliceTo(zero_ptr_again, 0), "hello"));
146 }
147 };
148 try S.doTheTest();
149 comptime try S.doTheTest();
150}
151
152test "allow any sentinel" {
153 const S = struct {
154 fn doTheTest() !void {
155 var array = [_:std.math.minInt(i32)]i32{ 1, 2, 3, 4 };
156 var ptr: [*:std.math.minInt(i32)]i32 = &array;
157 try expect(ptr[4] == std.math.minInt(i32));
158 }
159 };
160 try S.doTheTest();
161 comptime try S.doTheTest();
162}
163
164test "pointer sentinel with enums" {
165 const S = struct {
166 const Number = enum {
167 one,
168 two,
169 sentinel,
170 };
171
172 fn doTheTest() !void {
173 var ptr: [*:.sentinel]const Number = &[_:.sentinel]Number{ .one, .two, .two, .one };
174 try expect(ptr[4] == .sentinel); // TODO this should be comptime try expect, see #3731
175 }
176 };
177 try S.doTheTest();
178 comptime try S.doTheTest();
179}
180
181test "pointer sentinel with optional element" {
182 const S = struct {
183 fn doTheTest() !void {
184 var ptr: [*:null]const ?i32 = &[_:null]?i32{ 1, 2, 3, 4 };
185 try expect(ptr[4] == null); // TODO this should be comptime try expect, see #3731
186 }
187 };
188 try S.doTheTest();
189 comptime try S.doTheTest();
190}
191
192test "pointer sentinel with +inf" {
193 const S = struct {
194 fn doTheTest() !void {
195 const inf = std.math.inf_f32;
196 var ptr: [*:inf]const f32 = &[_:inf]f32{ 1.1, 2.2, 3.3, 4.4 };
197 try expect(ptr[4] == inf); // TODO this should be comptime try expect, see #3731
198 }
199 };
200 try S.doTheTest();
201 comptime try S.doTheTest();
202}
203
204test "pointer to array at fixed address" {
205 const array = @intToPtr(*volatile [1]u32, 0x10);
206 // Silly check just to reference `array`
207 try expect(@ptrToInt(&array[0]) == 0x10);
208}
209
210test "pointer arithmetic affects the alignment" {
211 {
212 var ptr: [*]align(8) u32 = undefined;
213 var x: usize = 1;
214
215 try expect(@typeInfo(@TypeOf(ptr)).Pointer.alignment == 8);
216 const ptr1 = ptr + 1; // 1 * 4 = 4 -> lcd(4,8) = 4
217 try expect(@typeInfo(@TypeOf(ptr1)).Pointer.alignment == 4);
218 const ptr2 = ptr + 4; // 4 * 4 = 16 -> lcd(16,8) = 8
219 try expect(@typeInfo(@TypeOf(ptr2)).Pointer.alignment == 8);
220 const ptr3 = ptr + 0; // no-op
221 try expect(@typeInfo(@TypeOf(ptr3)).Pointer.alignment == 8);
222 const ptr4 = ptr + x; // runtime-known addend
223 try expect(@typeInfo(@TypeOf(ptr4)).Pointer.alignment == 4);
224 }
225 {
226 var ptr: [*]align(8) [3]u8 = undefined;
227 var x: usize = 1;
228
229 const ptr1 = ptr + 17; // 3 * 17 = 51
230 try expect(@typeInfo(@TypeOf(ptr1)).Pointer.alignment == 1);
231 const ptr2 = ptr + x; // runtime-known addend
232 try expect(@typeInfo(@TypeOf(ptr2)).Pointer.alignment == 1);
233 const ptr3 = ptr + 8; // 3 * 8 = 24 -> lcd(8,24) = 8
234 try expect(@typeInfo(@TypeOf(ptr3)).Pointer.alignment == 8);
235 const ptr4 = ptr + 4; // 3 * 4 = 12 -> lcd(8,12) = 4
236 try expect(@typeInfo(@TypeOf(ptr4)).Pointer.alignment == 4);
237 }
238}
239
240test "@ptrToInt on null optional at comptime" {
241 {
242 const pointer = @intToPtr(?*u8, 0x000);
243 const x = @ptrToInt(pointer);
244 _ = x;
245 comptime try expect(0 == @ptrToInt(pointer));
246 }
247 {
248 const pointer = @intToPtr(?*u8, 0xf00);
249 comptime try expect(0xf00 == @ptrToInt(pointer));
250 }
251}
252
253test "indexing array with sentinel returns correct type" {
254 var s: [:0]const u8 = "abc";
255 try testing.expectEqualSlices(u8, "*const u8", @typeName(@TypeOf(&s[0])));
256}
test/behavior/ptrcast.zig+77
......@@ -2,3 +2,80 @@ const std = @import("std");
22const builtin = @import("builtin");
33const expect = std.testing.expect;
44const native_endian = builtin.target.cpu.arch.endian();
5
6test "reinterpret bytes as integer with nonzero offset" {
7 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
8
9 try testReinterpretBytesAsInteger();
10 comptime try testReinterpretBytesAsInteger();
11}
12
13fn testReinterpretBytesAsInteger() !void {
14 const bytes = "\x12\x34\x56\x78\xab";
15 const expected = switch (native_endian) {
16 .Little => 0xab785634,
17 .Big => 0x345678ab,
18 };
19 try expect(@ptrCast(*align(1) const u32, bytes[1..5]).* == expected);
20}
21
22test "reinterpret bytes of an array into an extern struct" {
23 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
24
25 try testReinterpretBytesAsExternStruct();
26 comptime try testReinterpretBytesAsExternStruct();
27}
28
29fn testReinterpretBytesAsExternStruct() !void {
30 var bytes align(2) = [_]u8{ 1, 2, 3, 4, 5, 6 };
31
32 const S = extern struct {
33 a: u8,
34 b: u16,
35 c: u8,
36 };
37
38 var ptr = @ptrCast(*const S, &bytes);
39 var val = ptr.c;
40 try expect(val == 5);
41}
42
43test "reinterpret struct field at comptime" {
44 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
45
46 const numNative = comptime Bytes.init(0x12345678);
47 if (native_endian != .Little) {
48 try expect(std.mem.eql(u8, &[_]u8{ 0x12, 0x34, 0x56, 0x78 }, &numNative.bytes));
49 } else {
50 try expect(std.mem.eql(u8, &[_]u8{ 0x78, 0x56, 0x34, 0x12 }, &numNative.bytes));
51 }
52}
53
54const Bytes = struct {
55 bytes: [4]u8,
56
57 pub fn init(v: u32) Bytes {
58 var res: Bytes = undefined;
59 @ptrCast(*align(1) u32, &res.bytes).* = v;
60
61 return res;
62 }
63};
64
65test "comptime ptrcast keeps larger alignment" {
66 comptime {
67 const a: u32 = 1234;
68 const p = @ptrCast([*]const u8, &a);
69 try expect(@TypeOf(p) == [*]align(@alignOf(u32)) const u8);
70 }
71}
72
73test "implicit optional pointer to optional anyopaque pointer" {
74 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
75
76 var buf: [4]u8 = "aoeu".*;
77 var x: ?[*]u8 = &buf;
78 var y: ?*anyopaque = x;
79 var z = @ptrCast(*[4]u8, y);
80 try expect(std.mem.eql(u8, z, "aoeu"));
81}
test/behavior/ptrcast_stage1.zig deleted-73
......@@ -1,73 +0,0 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const expect = std.testing.expect;
4const native_endian = builtin.target.cpu.arch.endian();
5
6test "reinterpret bytes as integer with nonzero offset" {
7 try testReinterpretBytesAsInteger();
8 comptime try testReinterpretBytesAsInteger();
9}
10
11fn testReinterpretBytesAsInteger() !void {
12 const bytes = "\x12\x34\x56\x78\xab";
13 const expected = switch (native_endian) {
14 .Little => 0xab785634,
15 .Big => 0x345678ab,
16 };
17 try expect(@ptrCast(*align(1) const u32, bytes[1..5]).* == expected);
18}
19
20test "reinterpret bytes of an array into an extern struct" {
21 try testReinterpretBytesAsExternStruct();
22 comptime try testReinterpretBytesAsExternStruct();
23}
24
25fn testReinterpretBytesAsExternStruct() !void {
26 var bytes align(2) = [_]u8{ 1, 2, 3, 4, 5, 6 };
27
28 const S = extern struct {
29 a: u8,
30 b: u16,
31 c: u8,
32 };
33
34 var ptr = @ptrCast(*const S, &bytes);
35 var val = ptr.c;
36 try expect(val == 5);
37}
38
39test "reinterpret struct field at comptime" {
40 const numNative = comptime Bytes.init(0x12345678);
41 if (native_endian != .Little) {
42 try expect(std.mem.eql(u8, &[_]u8{ 0x12, 0x34, 0x56, 0x78 }, &numNative.bytes));
43 } else {
44 try expect(std.mem.eql(u8, &[_]u8{ 0x78, 0x56, 0x34, 0x12 }, &numNative.bytes));
45 }
46}
47
48const Bytes = struct {
49 bytes: [4]u8,
50
51 pub fn init(v: u32) Bytes {
52 var res: Bytes = undefined;
53 @ptrCast(*align(1) u32, &res.bytes).* = v;
54
55 return res;
56 }
57};
58
59test "comptime ptrcast keeps larger alignment" {
60 comptime {
61 const a: u32 = 1234;
62 const p = @ptrCast([*]const u8, &a);
63 try expect(@TypeOf(p) == [*]align(@alignOf(u32)) const u8);
64 }
65}
66
67test "implicit optional pointer to optional anyopaque pointer" {
68 var buf: [4]u8 = "aoeu".*;
69 var x: ?[*]u8 = &buf;
70 var y: ?*anyopaque = x;
71 var z = @ptrCast(*[4]u8, y);
72 try expect(std.mem.eql(u8, z, "aoeu"));
73}