authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-09-20 22:02:36-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-09-20 22:02:36-04:00
log62ecc154d9ad065aee57d81afd3a478dd8360fb7
tree52f17b58d87a2ef83f2a1607f0aecbee31c33661
parent521c753fda3cd5ebb79752287ef3c87d84f8d5c3
parenteef653904916dc19540458199366807f8837bf98
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #12904 from Vexu/ptrcast

stage2: pointer casting fixes and improvements

34 files changed, 357 insertions(+), 227 deletions(-)

lib/std/json.zig+3-3
...@@ -1560,7 +1560,7 @@ fn parseInternal(...@@ -1560,7 +1560,7 @@ fn parseInternal(
1560 }1560 }
1561 }1561 }
1562 if (field.is_comptime) {1562 if (field.is_comptime) {
1563 if (!try parsesTo(field.field_type, @ptrCast(*const field.field_type, field.default_value.?).*, tokens, child_options)) {1563 if (!try parsesTo(field.field_type, @ptrCast(*align(1) const field.field_type, field.default_value.?).*, tokens, child_options)) {
1564 return error.UnexpectedValue;1564 return error.UnexpectedValue;
1565 }1565 }
1566 } else {1566 } else {
...@@ -1587,7 +1587,7 @@ fn parseInternal(...@@ -1587,7 +1587,7 @@ fn parseInternal(
1587 if (!fields_seen[i]) {1587 if (!fields_seen[i]) {
1588 if (field.default_value) |default_ptr| {1588 if (field.default_value) |default_ptr| {
1589 if (!field.is_comptime) {1589 if (!field.is_comptime) {
1590 const default = @ptrCast(*const field.field_type, default_ptr).*;1590 const default = @ptrCast(*align(1) const field.field_type, default_ptr).*;
1591 @field(r, field.name) = default;1591 @field(r, field.name) = default;
1592 }1592 }
1593 } else {1593 } else {
...@@ -1667,7 +1667,7 @@ fn parseInternal(...@@ -1667,7 +1667,7 @@ fn parseInternal(
1667 }1667 }
16681668
1669 if (ptrInfo.sentinel) |some| {1669 if (ptrInfo.sentinel) |some| {
1670 const sentinel_value = @ptrCast(*const ptrInfo.child, some).*;1670 const sentinel_value = @ptrCast(*align(1) const ptrInfo.child, some).*;
1671 try arraylist.append(sentinel_value);1671 try arraylist.append(sentinel_value);
1672 const output = arraylist.toOwnedSlice();1672 const output = arraylist.toOwnedSlice();
1673 return output[0 .. output.len - 1 :sentinel_value];1673 return output[0 .. output.len - 1 :sentinel_value];
lib/std/mem.zig+12-11
...@@ -297,7 +297,7 @@ pub fn zeroes(comptime T: type) T {...@@ -297,7 +297,7 @@ pub fn zeroes(comptime T: type) T {
297 },297 },
298 .Array => |info| {298 .Array => |info| {
299 if (info.sentinel) |sentinel_ptr| {299 if (info.sentinel) |sentinel_ptr| {
300 const sentinel = @ptrCast(*const info.child, sentinel_ptr).*;300 const sentinel = @ptrCast(*align(1) const info.child, sentinel_ptr).*;
301 return [_:sentinel]info.child{zeroes(info.child)} ** info.len;301 return [_:sentinel]info.child{zeroes(info.child)} ** info.len;
302 }302 }
303 return [_]info.child{zeroes(info.child)} ** info.len;303 return [_]info.child{zeroes(info.child)} ** info.len;
...@@ -443,7 +443,7 @@ pub fn zeroInit(comptime T: type, init: anytype) T {...@@ -443,7 +443,7 @@ pub fn zeroInit(comptime T: type, init: anytype) T {
443443
444 inline for (struct_info.fields) |field| {444 inline for (struct_info.fields) |field| {
445 if (field.default_value) |default_value_ptr| {445 if (field.default_value) |default_value_ptr| {
446 const default_value = @ptrCast(*const field.field_type, default_value_ptr).*;446 const default_value = @ptrCast(*align(1) const field.field_type, default_value_ptr).*;
447 @field(value, field.name) = default_value;447 @field(value, field.name) = default_value;
448 }448 }
449 }449 }
...@@ -687,7 +687,7 @@ pub fn span(ptr: anytype) Span(@TypeOf(ptr)) {...@@ -687,7 +687,7 @@ pub fn span(ptr: anytype) Span(@TypeOf(ptr)) {
687 const l = len(ptr);687 const l = len(ptr);
688 const ptr_info = @typeInfo(Result).Pointer;688 const ptr_info = @typeInfo(Result).Pointer;
689 if (ptr_info.sentinel) |s_ptr| {689 if (ptr_info.sentinel) |s_ptr| {
690 const s = @ptrCast(*const ptr_info.child, s_ptr).*;690 const s = @ptrCast(*align(1) const ptr_info.child, s_ptr).*;
691 return ptr[0..l :s];691 return ptr[0..l :s];
692 } else {692 } else {
693 return ptr[0..l];693 return ptr[0..l];
...@@ -719,7 +719,7 @@ fn SliceTo(comptime T: type, comptime end: meta.Elem(T)) type {...@@ -719,7 +719,7 @@ fn SliceTo(comptime T: type, comptime end: meta.Elem(T)) type {
719 // to find the value searched for, which is only the case if it matches719 // to find the value searched for, which is only the case if it matches
720 // the sentinel of the type passed.720 // the sentinel of the type passed.
721 if (array_info.sentinel) |sentinel_ptr| {721 if (array_info.sentinel) |sentinel_ptr| {
722 const sentinel = @ptrCast(*const array_info.child, sentinel_ptr).*;722 const sentinel = @ptrCast(*align(1) const array_info.child, sentinel_ptr).*;
723 if (end == sentinel) {723 if (end == sentinel) {
724 new_ptr_info.sentinel = &end;724 new_ptr_info.sentinel = &end;
725 } else {725 } else {
...@@ -734,7 +734,7 @@ fn SliceTo(comptime T: type, comptime end: meta.Elem(T)) type {...@@ -734,7 +734,7 @@ fn SliceTo(comptime T: type, comptime end: meta.Elem(T)) type {
734 // to find the value searched for, which is only the case if it matches734 // to find the value searched for, which is only the case if it matches
735 // the sentinel of the type passed.735 // the sentinel of the type passed.
736 if (ptr_info.sentinel) |sentinel_ptr| {736 if (ptr_info.sentinel) |sentinel_ptr| {
737 const sentinel = @ptrCast(*const ptr_info.child, sentinel_ptr).*;737 const sentinel = @ptrCast(*align(1) const ptr_info.child, sentinel_ptr).*;
738 if (end == sentinel) {738 if (end == sentinel) {
739 new_ptr_info.sentinel = &end;739 new_ptr_info.sentinel = &end;
740 } else {740 } else {
...@@ -772,7 +772,7 @@ pub fn sliceTo(ptr: anytype, comptime end: meta.Elem(@TypeOf(ptr))) SliceTo(@Typ...@@ -772,7 +772,7 @@ pub fn sliceTo(ptr: anytype, comptime end: meta.Elem(@TypeOf(ptr))) SliceTo(@Typ
772 const length = lenSliceTo(ptr, end);772 const length = lenSliceTo(ptr, end);
773 const ptr_info = @typeInfo(Result).Pointer;773 const ptr_info = @typeInfo(Result).Pointer;
774 if (ptr_info.sentinel) |s_ptr| {774 if (ptr_info.sentinel) |s_ptr| {
775 const s = @ptrCast(*const ptr_info.child, s_ptr).*;775 const s = @ptrCast(*align(1) const ptr_info.child, s_ptr).*;
776 return ptr[0..length :s];776 return ptr[0..length :s];
777 } else {777 } else {
778 return ptr[0..length];778 return ptr[0..length];
...@@ -825,7 +825,7 @@ fn lenSliceTo(ptr: anytype, comptime end: meta.Elem(@TypeOf(ptr))) usize {...@@ -825,7 +825,7 @@ fn lenSliceTo(ptr: anytype, comptime end: meta.Elem(@TypeOf(ptr))) usize {
825 .One => switch (@typeInfo(ptr_info.child)) {825 .One => switch (@typeInfo(ptr_info.child)) {
826 .Array => |array_info| {826 .Array => |array_info| {
827 if (array_info.sentinel) |sentinel_ptr| {827 if (array_info.sentinel) |sentinel_ptr| {
828 const sentinel = @ptrCast(*const array_info.child, sentinel_ptr).*;828 const sentinel = @ptrCast(*align(1) const array_info.child, sentinel_ptr).*;
829 if (sentinel == end) {829 if (sentinel == end) {
830 return indexOfSentinel(array_info.child, end, ptr);830 return indexOfSentinel(array_info.child, end, ptr);
831 }831 }
...@@ -835,7 +835,7 @@ fn lenSliceTo(ptr: anytype, comptime end: meta.Elem(@TypeOf(ptr))) usize {...@@ -835,7 +835,7 @@ fn lenSliceTo(ptr: anytype, comptime end: meta.Elem(@TypeOf(ptr))) usize {
835 else => {},835 else => {},
836 },836 },
837 .Many => if (ptr_info.sentinel) |sentinel_ptr| {837 .Many => if (ptr_info.sentinel) |sentinel_ptr| {
838 const sentinel = @ptrCast(*const ptr_info.child, sentinel_ptr).*;838 const sentinel = @ptrCast(*align(1) const ptr_info.child, sentinel_ptr).*;
839 // We may be looking for something other than the sentinel,839 // We may be looking for something other than the sentinel,
840 // but iterating past the sentinel would be a bug so we need840 // but iterating past the sentinel would be a bug so we need
841 // to check for both.841 // to check for both.
...@@ -849,7 +849,7 @@ fn lenSliceTo(ptr: anytype, comptime end: meta.Elem(@TypeOf(ptr))) usize {...@@ -849,7 +849,7 @@ fn lenSliceTo(ptr: anytype, comptime end: meta.Elem(@TypeOf(ptr))) usize {
849 },849 },
850 .Slice => {850 .Slice => {
851 if (ptr_info.sentinel) |sentinel_ptr| {851 if (ptr_info.sentinel) |sentinel_ptr| {
852 const sentinel = @ptrCast(*const ptr_info.child, sentinel_ptr).*;852 const sentinel = @ptrCast(*align(1) const ptr_info.child, sentinel_ptr).*;
853 if (sentinel == end) {853 if (sentinel == end) {
854 return indexOfSentinel(ptr_info.child, sentinel, ptr);854 return indexOfSentinel(ptr_info.child, sentinel, ptr);
855 }855 }
...@@ -911,7 +911,7 @@ pub fn len(value: anytype) usize {...@@ -911,7 +911,7 @@ pub fn len(value: anytype) usize {
911 .Many => {911 .Many => {
912 const sentinel_ptr = info.sentinel orelse912 const sentinel_ptr = info.sentinel orelse
913 @compileError("length of pointer with no sentinel");913 @compileError("length of pointer with no sentinel");
914 const sentinel = @ptrCast(*const info.child, sentinel_ptr).*;914 const sentinel = @ptrCast(*align(1) const info.child, sentinel_ptr).*;
915 return indexOfSentinel(info.child, sentinel, value);915 return indexOfSentinel(info.child, sentinel, value);
916 },916 },
917 .C => {917 .C => {
...@@ -2882,7 +2882,8 @@ fn AsBytesReturnType(comptime P: type) type {...@@ -2882,7 +2882,8 @@ fn AsBytesReturnType(comptime P: type) type {
2882/// Given a pointer to a single item, returns a slice of the underlying bytes, preserving pointer attributes.2882/// Given a pointer to a single item, returns a slice of the underlying bytes, preserving pointer attributes.
2883pub fn asBytes(ptr: anytype) AsBytesReturnType(@TypeOf(ptr)) {2883pub fn asBytes(ptr: anytype) AsBytesReturnType(@TypeOf(ptr)) {
2884 const P = @TypeOf(ptr);2884 const P = @TypeOf(ptr);
2885 return @ptrCast(AsBytesReturnType(P), ptr);2885 const T = AsBytesReturnType(P);
2886 return @ptrCast(T, @alignCast(meta.alignment(T), ptr));
2886}2887}
28872888
2888test "asBytes" {2889test "asBytes" {
lib/std/meta.zig+2-2
...@@ -204,12 +204,12 @@ pub fn sentinel(comptime T: type) ?Elem(T) {...@@ -204,12 +204,12 @@ pub fn sentinel(comptime T: type) ?Elem(T) {
204 switch (info.size) {204 switch (info.size) {
205 .Many, .Slice => {205 .Many, .Slice => {
206 const sentinel_ptr = info.sentinel orelse return null;206 const sentinel_ptr = info.sentinel orelse return null;
207 return @ptrCast(*const info.child, sentinel_ptr).*;207 return @ptrCast(*align(1) const info.child, sentinel_ptr).*;
208 },208 },
209 .One => switch (@typeInfo(info.child)) {209 .One => switch (@typeInfo(info.child)) {
210 .Array => |array_info| {210 .Array => |array_info| {
211 const sentinel_ptr = array_info.sentinel orelse return null;211 const sentinel_ptr = array_info.sentinel orelse return null;
212 return @ptrCast(*const array_info.child, sentinel_ptr).*;212 return @ptrCast(*align(1) const array_info.child, sentinel_ptr).*;
213 },213 },
214 else => {},214 else => {},
215 },215 },
lib/std/os/linux.zig+1-1
...@@ -888,7 +888,7 @@ else...@@ -888,7 +888,7 @@ else
888const vdso_clock_gettime_ty = if (builtin.zig_backend == .stage1)888const vdso_clock_gettime_ty = if (builtin.zig_backend == .stage1)
889 fn (i32, *timespec) callconv(.C) usize889 fn (i32, *timespec) callconv(.C) usize
890else890else
891 *const fn (i32, *timespec) callconv(.C) usize;891 *align(1) const fn (i32, *timespec) callconv(.C) usize;
892892
893pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {893pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
894 if (@hasDecl(VDSO, "CGT_SYM")) {894 if (@hasDecl(VDSO, "CGT_SYM")) {
lib/std/zig/c_translation.zig+1-1
...@@ -193,7 +193,7 @@ pub fn sizeof(target: anytype) usize {...@@ -193,7 +193,7 @@ pub fn sizeof(target: anytype) usize {
193 const array_info = @typeInfo(ptr.child).Array;193 const array_info = @typeInfo(ptr.child).Array;
194 if ((array_info.child == u8 or array_info.child == u16) and194 if ((array_info.child == u8 or array_info.child == u16) and
195 array_info.sentinel != null and195 array_info.sentinel != null and
196 @ptrCast(*const array_info.child, array_info.sentinel.?).* == 0)196 @ptrCast(*align(1) const array_info.child, array_info.sentinel.?).* == 0)
197 {197 {
198 // length of the string plus one for the null terminator.198 // length of the string plus one for the null terminator.
199 return (array_info.len + 1) * @sizeOf(array_info.child);199 return (array_info.len + 1) * @sizeOf(array_info.child);
src/Sema.zig+132-45
...@@ -16492,6 +16492,9 @@ fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -16492,6 +16492,9 @@ fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
16492 const inst_data = sema.code.instructions.items(.data)[inst].un_node;16492 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
16493 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };16493 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
16494 const ty = try sema.resolveType(block, operand_src, inst_data.operand);16494 const ty = try sema.resolveType(block, operand_src, inst_data.operand);
16495 if (ty.isNoReturn()) {
16496 return sema.fail(block, operand_src, "no align available for type '{}'", .{ty.fmt(sema.mod)});
16497 }
16495 const target = sema.mod.getTarget();16498 const target = sema.mod.getTarget();
16496 const val = try ty.lazyAbiAlignment(target, sema.arena);16499 const val = try ty.lazyAbiAlignment(target, sema.arena);
16497 if (val.tag() == .lazy_align) {16500 if (val.tag() == .lazy_align) {
...@@ -17772,6 +17775,7 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat...@@ -17772,6 +17775,7 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
1777217775
17773fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {17776fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
17774 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;17777 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
17778 const src = inst_data.src();
17775 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };17779 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
17776 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };17780 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
17777 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;17781 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
...@@ -17783,6 +17787,15 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -17783,6 +17787,15 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
17783 try sema.checkPtrType(block, dest_ty_src, dest_ty);17787 try sema.checkPtrType(block, dest_ty_src, dest_ty);
17784 try sema.checkPtrOperand(block, operand_src, operand_ty);17788 try sema.checkPtrOperand(block, operand_src, operand_ty);
1778517789
17790 const operand_info = operand_ty.ptrInfo().data;
17791 const dest_info = dest_ty.ptrInfo().data;
17792 if (!operand_info.mutable and dest_info.mutable) {
17793 return sema.fail(block, src, "cast discards const qualifier", .{});
17794 }
17795 if (operand_info.@"volatile" and !dest_info.@"volatile") {
17796 return sema.fail(block, src, "cast discards volatile qualifier", .{});
17797 }
17798
17786 const dest_is_slice = dest_ty.isSlice();17799 const dest_is_slice = dest_ty.isSlice();
17787 const operand_is_slice = operand_ty.isSlice();17800 const operand_is_slice = operand_ty.isSlice();
17788 if (dest_is_slice and !operand_is_slice) {17801 if (dest_is_slice and !operand_is_slice) {
...@@ -17793,15 +17806,6 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -17793,15 +17806,6 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
17793 else17806 else
17794 operand;17807 operand;
1779517808
17796 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |operand_val| {
17797 if (!dest_ty.ptrAllowsZero() and operand_val.isUndef()) {
17798 return sema.failWithUseOfUndef(block, operand_src);
17799 }
17800 if (!dest_ty.ptrAllowsZero() and operand_val.isNull()) {
17801 return sema.fail(block, operand_src, "null pointer casted to type {}", .{dest_ty.fmt(sema.mod)});
17802 }
17803 }
17804
17805 const dest_elem_ty = dest_ty.elemType2();17809 const dest_elem_ty = dest_ty.elemType2();
17806 try sema.resolveTypeLayout(block, dest_ty_src, dest_elem_ty);17810 try sema.resolveTypeLayout(block, dest_ty_src, dest_elem_ty);
17807 const dest_align = dest_ty.ptrAlignment(target);17811 const dest_align = dest_ty.ptrAlignment(target);
...@@ -17835,7 +17839,47 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -17835,7 +17839,47 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
17835 }17839 }
17836 }17840 }
1783717841
17838 return sema.coerceCompatiblePtrs(block, aligned_dest_ty, ptr, operand_src);17842 if (dest_align > operand_align) {
17843 const msg = msg: {
17844 const msg = try sema.errMsg(block, src, "cast increases pointer alignment", .{});
17845 errdefer msg.destroy(sema.gpa);
17846
17847 try sema.errNote(block, operand_src, msg, "'{}' has alignment '{d}'", .{
17848 operand_ty.fmt(sema.mod), operand_align,
17849 });
17850 try sema.errNote(block, dest_ty_src, msg, "'{}' has alignment '{d}'", .{
17851 dest_ty.fmt(sema.mod), dest_align,
17852 });
17853 break :msg msg;
17854 };
17855 return sema.failWithOwnedErrorMsg(msg);
17856 }
17857
17858 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |operand_val| {
17859 if (!dest_ty.ptrAllowsZero() and operand_val.isUndef()) {
17860 return sema.failWithUseOfUndef(block, operand_src);
17861 }
17862 if (!dest_ty.ptrAllowsZero() and operand_val.isNull()) {
17863 return sema.fail(block, operand_src, "null pointer casted to type {}", .{dest_ty.fmt(sema.mod)});
17864 }
17865 return sema.addConstant(aligned_dest_ty, operand_val);
17866 }
17867
17868 try sema.requireRuntimeBlock(block, src, null);
17869 if (block.wantSafety() and operand_ty.ptrAllowsZero() and !dest_ty.ptrAllowsZero() and
17870 try sema.typeHasRuntimeBits(block, sema.src, dest_ty.elemType2()))
17871 {
17872 const ptr_int = try block.addUnOp(.ptrtoint, ptr);
17873 const is_non_zero = try block.addBinOp(.cmp_neq, ptr_int, .zero_usize);
17874 const ok = if (operand_is_slice) ok: {
17875 const len = try sema.analyzeSliceLen(block, operand_src, operand);
17876 const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);
17877 break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero);
17878 } else is_non_zero;
17879 try sema.addSafetyCheck(block, ok, .cast_to_null);
17880 }
17881
17882 return block.addBitCast(aligned_dest_ty, ptr);
17839}17883}
1784017884
17841fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {17885fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -17931,23 +17975,14 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -17931,23 +17975,14 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
17931 const ptr = try sema.resolveInst(extra.rhs);17975 const ptr = try sema.resolveInst(extra.rhs);
17932 const ptr_ty = sema.typeOf(ptr);17976 const ptr_ty = sema.typeOf(ptr);
1793317977
17934 // TODO in addition to pointers, this instruction is supposed to work for
17935 // pointer-like optionals and slices.
17936 try sema.checkPtrOperand(block, ptr_src, ptr_ty);17978 try sema.checkPtrOperand(block, ptr_src, ptr_ty);
1793717979
17938 // TODO compile error if the result pointer is comptime known and would have an17980 var ptr_info = ptr_ty.ptrInfo().data;
17939 // alignment that disagrees with the Decl's alignment.17981 ptr_info.@"align" = dest_align;
1794017982 var dest_ty = try Type.ptr(sema.arena, sema.mod, ptr_info);
17941 const ptr_info = ptr_ty.ptrInfo().data;17983 if (ptr_ty.zigTypeTag() == .Optional) {
17942 const dest_ty = try Type.ptr(sema.arena, sema.mod, .{17984 dest_ty = try Type.Tag.optional.create(sema.arena, dest_ty);
17943 .pointee_type = ptr_info.pointee_type,17985 }
17944 .@"align" = dest_align,
17945 .@"addrspace" = ptr_info.@"addrspace",
17946 .mutable = ptr_info.mutable,
17947 .@"allowzero" = ptr_info.@"allowzero",
17948 .@"volatile" = ptr_info.@"volatile",
17949 .size = ptr_info.size,
17950 });
1795117986
17952 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |val| {17987 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |val| {
17953 if (try val.getUnsignedIntAdvanced(sema.mod.getTarget(), null)) |addr| {17988 if (try val.getUnsignedIntAdvanced(sema.mod.getTarget(), null)) |addr| {
...@@ -17960,7 +17995,7 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -17960,7 +17995,7 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1796017995
17961 try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src);17996 try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src);
17962 if (block.wantSafety() and dest_align > 1 and17997 if (block.wantSafety() and dest_align > 1 and
17963 try sema.typeHasRuntimeBits(block, sema.src, dest_ty.elemType2()))17998 try sema.typeHasRuntimeBits(block, sema.src, ptr_info.pointee_type))
17964 {17999 {
17965 const val_payload = try sema.arena.create(Value.Payload.U64);18000 const val_payload = try sema.arena.create(Value.Payload.U64);
17966 val_payload.* = .{18001 val_payload.* = .{
...@@ -17985,7 +18020,7 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -17985,7 +18020,7 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
17985 } else is_aligned;18020 } else is_aligned;
17986 try sema.addSafetyCheck(block, ok, .incorrect_alignment);18021 try sema.addSafetyCheck(block, ok, .incorrect_alignment);
17987 }18022 }
17988 return sema.coerceCompatiblePtrs(block, dest_ty, ptr, ptr_src);18023 return sema.bitCast(block, dest_ty, ptr, ptr_src);
17989}18024}
1799018025
17991fn zirBitCount(18026fn zirBitCount(
...@@ -22660,7 +22695,7 @@ fn elemPtrSlice(...@@ -22660,7 +22695,7 @@ fn elemPtrSlice(
22660 break :o index;22695 break :o index;
22661 } else null;22696 } else null;
2266222697
22663 const elem_ptr_ty = try sema.elemPtrType(slice_ty, null);22698 const elem_ptr_ty = try sema.elemPtrType(slice_ty, offset);
2266422699
22665 if (maybe_undef_slice_val) |slice_val| {22700 if (maybe_undef_slice_val) |slice_val| {
22666 if (slice_val.isUndef()) {22701 if (slice_val.isUndef()) {
...@@ -22779,6 +22814,7 @@ fn coerceExtra(...@@ -22779,6 +22814,7 @@ fn coerceExtra(
22779 if (dest_ty.isPtrLikeOptional() and dest_ty.elemType2().tag() == .anyopaque and22814 if (dest_ty.isPtrLikeOptional() and dest_ty.elemType2().tag() == .anyopaque and
22780 inst_ty.isPtrLikeOptional() and inst_ty.elemType2().zigTypeTag() != .Pointer)22815 inst_ty.isPtrLikeOptional() and inst_ty.elemType2().zigTypeTag() != .Pointer)
22781 {22816 {
22817 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :optional;
22782 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);22818 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
22783 }22819 }
2278422820
...@@ -22811,14 +22847,12 @@ fn coerceExtra(...@@ -22811,14 +22847,12 @@ fn coerceExtra(
22811 single_item: {22847 single_item: {
22812 if (dest_info.size != .One) break :single_item;22848 if (dest_info.size != .One) break :single_item;
22813 if (!inst_ty.isSinglePointer()) break :single_item;22849 if (!inst_ty.isSinglePointer()) break :single_item;
22850 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer;
22814 const ptr_elem_ty = inst_ty.childType();22851 const ptr_elem_ty = inst_ty.childType();
22815 const array_ty = dest_info.pointee_type;22852 const array_ty = dest_info.pointee_type;
22816 if (array_ty.zigTypeTag() != .Array) break :single_item;22853 if (array_ty.zigTypeTag() != .Array) break :single_item;
22817 const array_elem_ty = array_ty.childType();22854 const array_elem_ty = array_ty.childType();
22818 const dest_is_mut = dest_info.mutable;22855 const dest_is_mut = dest_info.mutable;
22819 if (inst_ty.isConstPtr() and dest_is_mut) break :single_item;
22820 if (inst_ty.isVolatilePtr() and !dest_info.@"volatile") break :single_item;
22821 if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :single_item;
22822 switch (try sema.coerceInMemoryAllowed(block, array_elem_ty, ptr_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) {22856 switch (try sema.coerceInMemoryAllowed(block, array_elem_ty, ptr_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) {
22823 .ok => {},22857 .ok => {},
22824 else => break :single_item,22858 else => break :single_item,
...@@ -22829,14 +22863,11 @@ fn coerceExtra(...@@ -22829,14 +22863,11 @@ fn coerceExtra(
22829 // Coercions where the source is a single pointer to an array.22863 // Coercions where the source is a single pointer to an array.
22830 src_array_ptr: {22864 src_array_ptr: {
22831 if (!inst_ty.isSinglePointer()) break :src_array_ptr;22865 if (!inst_ty.isSinglePointer()) break :src_array_ptr;
22866 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer;
22832 const array_ty = inst_ty.childType();22867 const array_ty = inst_ty.childType();
22833 if (array_ty.zigTypeTag() != .Array) break :src_array_ptr;22868 if (array_ty.zigTypeTag() != .Array) break :src_array_ptr;
22834 const len0 = array_ty.arrayLen() == 0;
22835 const array_elem_type = array_ty.childType();22869 const array_elem_type = array_ty.childType();
22836 const dest_is_mut = dest_info.mutable;22870 const dest_is_mut = dest_info.mutable;
22837 if (inst_ty.isConstPtr() and dest_is_mut and !len0) break :src_array_ptr;
22838 if (inst_ty.isVolatilePtr() and !dest_info.@"volatile") break :src_array_ptr;
22839 if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :src_array_ptr;
2284022871
22841 const dst_elem_type = dest_info.pointee_type;22872 const dst_elem_type = dest_info.pointee_type;
22842 switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, array_elem_type, dest_is_mut, target, dest_ty_src, inst_src)) {22873 switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, array_elem_type, dest_is_mut, target, dest_ty_src, inst_src)) {
...@@ -22873,6 +22904,7 @@ fn coerceExtra(...@@ -22873,6 +22904,7 @@ fn coerceExtra(
2287322904
22874 // coercion from C pointer22905 // coercion from C pointer
22875 if (inst_ty.isCPtr()) src_c_ptr: {22906 if (inst_ty.isCPtr()) src_c_ptr: {
22907 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :src_c_ptr;
22876 // In this case we must add a safety check because the C pointer22908 // In this case we must add a safety check because the C pointer
22877 // could be null.22909 // could be null.
22878 const src_elem_ty = inst_ty.childType();22910 const src_elem_ty = inst_ty.childType();
...@@ -22888,7 +22920,7 @@ fn coerceExtra(...@@ -22888,7 +22920,7 @@ fn coerceExtra(
22888 // cast from *T and [*]T to *anyopaque22920 // cast from *T and [*]T to *anyopaque
22889 // but don't do it if the source type is a double pointer22921 // but don't do it if the source type is a double pointer
22890 if (dest_info.pointee_type.tag() == .anyopaque and inst_ty.zigTypeTag() == .Pointer and22922 if (dest_info.pointee_type.tag() == .anyopaque and inst_ty.zigTypeTag() == .Pointer and
22891 inst_ty.childType().zigTypeTag() != .Pointer)22923 inst_ty.childType().zigTypeTag() != .Pointer and sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
22892 {22924 {
22893 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);22925 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
22894 }22926 }
...@@ -22922,6 +22954,7 @@ fn coerceExtra(...@@ -22922,6 +22954,7 @@ fn coerceExtra(
22922 return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);22954 return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);
22923 },22955 },
22924 .Pointer => p: {22956 .Pointer => p: {
22957 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :p;
22925 const inst_info = inst_ty.ptrInfo().data;22958 const inst_info = inst_ty.ptrInfo().data;
22926 switch (try sema.coerceInMemoryAllowed(22959 switch (try sema.coerceInMemoryAllowed(
22927 block,22960 block,
...@@ -22952,7 +22985,7 @@ fn coerceExtra(...@@ -22952,7 +22985,7 @@ fn coerceExtra(
22952 // pointer to anonymous struct to pointer to union22985 // pointer to anonymous struct to pointer to union
22953 if (inst_ty.isSinglePointer() and22986 if (inst_ty.isSinglePointer() and
22954 inst_ty.childType().isAnonStruct() and22987 inst_ty.childType().isAnonStruct() and
22955 !dest_info.mutable)22988 sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
22956 {22989 {
22957 return sema.coerceAnonStructToUnionPtrs(block, dest_ty, dest_ty_src, inst, inst_src);22990 return sema.coerceAnonStructToUnionPtrs(block, dest_ty, dest_ty_src, inst, inst_src);
22958 }22991 }
...@@ -22961,7 +22994,7 @@ fn coerceExtra(...@@ -22961,7 +22994,7 @@ fn coerceExtra(
22961 // pointer to anonymous struct to pointer to struct22994 // pointer to anonymous struct to pointer to struct
22962 if (inst_ty.isSinglePointer() and22995 if (inst_ty.isSinglePointer() and
22963 inst_ty.childType().isAnonStruct() and22996 inst_ty.childType().isAnonStruct() and
22964 !dest_info.mutable)22997 sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
22965 {22998 {
22966 return sema.coerceAnonStructToStructPtrs(block, dest_ty, dest_ty_src, inst, inst_src);22999 return sema.coerceAnonStructToStructPtrs(block, dest_ty, dest_ty_src, inst, inst_src);
22967 }23000 }
...@@ -22970,7 +23003,7 @@ fn coerceExtra(...@@ -22970,7 +23003,7 @@ fn coerceExtra(
22970 // pointer to tuple to pointer to array23003 // pointer to tuple to pointer to array
22971 if (inst_ty.isSinglePointer() and23004 if (inst_ty.isSinglePointer() and
22972 inst_ty.childType().isTuple() and23005 inst_ty.childType().isTuple() and
22973 !dest_info.mutable)23006 sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
22974 {23007 {
22975 return sema.coerceTupleToArrayPtrs(block, dest_ty, dest_ty_src, inst, inst_src);23008 return sema.coerceTupleToArrayPtrs(block, dest_ty, dest_ty_src, inst, inst_src);
22976 }23009 }
...@@ -22979,10 +23012,8 @@ fn coerceExtra(...@@ -22979,10 +23012,8 @@ fn coerceExtra(
22979 },23012 },
22980 .Slice => {23013 .Slice => {
22981 // pointer to tuple to slice23014 // pointer to tuple to slice
22982 if (inst_ty.isSinglePointer() and23015 if (inst_ty.isSinglePointer() and inst_ty.childType().isTuple() and dest_info.size == .Slice and
22983 inst_ty.childType().isTuple() and23016 sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
22984 (!dest_info.mutable or inst_ty.ptrIsMutable() or inst_ty.childType().tupleFields().types.len == 0) and
22985 dest_info.size == .Slice)
22986 {23017 {
22987 return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src);23018 return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src);
22988 }23019 }
...@@ -23011,6 +23042,7 @@ fn coerceExtra(...@@ -23011,6 +23042,7 @@ fn coerceExtra(
23011 },23042 },
23012 .Many => p: {23043 .Many => p: {
23013 if (!inst_ty.isSlice()) break :p;23044 if (!inst_ty.isSlice()) break :p;
23045 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :p;
23014 const inst_info = inst_ty.ptrInfo().data;23046 const inst_info = inst_ty.ptrInfo().data;
2301523047
23016 switch (try sema.coerceInMemoryAllowed(23048 switch (try sema.coerceInMemoryAllowed(
...@@ -25158,6 +25190,11 @@ fn beginComptimePtrLoad(...@@ -25158,6 +25190,11 @@ fn beginComptimePtrLoad(
25158 break :blk deref;25190 break :blk deref;
25159 },25191 },
2516025192
25193 .slice => blk: {
25194 const slice = ptr_val.castTag(.slice).?.data;
25195 break :blk try beginComptimePtrLoad(sema, block, src, slice.ptr, null);
25196 },
25197
25161 .field_ptr => blk: {25198 .field_ptr => blk: {
25162 const field_ptr = ptr_val.castTag(.field_ptr).?.data;25199 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
25163 const field_index = @intCast(u32, field_ptr.field_index);25200 const field_index = @intCast(u32, field_ptr.field_index);
...@@ -25406,6 +25443,57 @@ fn coerceArrayPtrToSlice(...@@ -25406,6 +25443,57 @@ fn coerceArrayPtrToSlice(
25406 return block.addTyOp(.array_to_slice, dest_ty, inst);25443 return block.addTyOp(.array_to_slice, dest_ty, inst);
25407}25444}
2540825445
25446fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_result: *InMemoryCoercionResult) bool {
25447 const dest_info = dest_ty.ptrInfo().data;
25448 const inst_info = inst_ty.ptrInfo().data;
25449 const len0 = (inst_info.pointee_type.zigTypeTag() == .Array and (inst_info.pointee_type.arrayLenIncludingSentinel() == 0 or
25450 (inst_info.pointee_type.arrayLen() == 0 and dest_info.sentinel == null and dest_info.size != .C and dest_info.size != .Many))) or
25451 (inst_info.pointee_type.isTuple() and inst_info.pointee_type.tupleFields().types.len == 0);
25452
25453 const ok_cv_qualifiers =
25454 ((inst_info.mutable or !dest_info.mutable) or len0) and
25455 (!inst_info.@"volatile" or dest_info.@"volatile");
25456
25457 if (!ok_cv_qualifiers) {
25458 in_memory_result.* = .{ .ptr_qualifiers = .{
25459 .actual_const = !inst_info.mutable,
25460 .wanted_const = !dest_info.mutable,
25461 .actual_volatile = inst_info.@"volatile",
25462 .wanted_volatile = dest_info.@"volatile",
25463 } };
25464 return false;
25465 }
25466 if (dest_info.@"addrspace" != inst_info.@"addrspace") {
25467 in_memory_result.* = .{ .ptr_addrspace = .{
25468 .actual = inst_info.@"addrspace",
25469 .wanted = dest_info.@"addrspace",
25470 } };
25471 return false;
25472 }
25473 if (inst_info.@"align" == 0 and dest_info.@"align" == 0) return true;
25474 if (len0) return true;
25475 const target = sema.mod.getTarget();
25476
25477 const inst_align = if (inst_info.@"align" != 0)
25478 inst_info.@"align"
25479 else
25480 inst_info.pointee_type.abiAlignment(target);
25481
25482 const dest_align = if (dest_info.@"align" != 0)
25483 dest_info.@"align"
25484 else
25485 dest_info.pointee_type.abiAlignment(target);
25486
25487 if (dest_align > inst_align) {
25488 in_memory_result.* = .{ .ptr_alignment = .{
25489 .actual = inst_align,
25490 .wanted = dest_align,
25491 } };
25492 return false;
25493 }
25494 return true;
25495}
25496
25409fn coerceCompatiblePtrs(25497fn coerceCompatiblePtrs(
25410 sema: *Sema,25498 sema: *Sema,
25411 block: *Block,25499 block: *Block,
...@@ -25413,13 +25501,12 @@ fn coerceCompatiblePtrs(...@@ -25413,13 +25501,12 @@ fn coerceCompatiblePtrs(
25413 inst: Air.Inst.Ref,25501 inst: Air.Inst.Ref,
25414 inst_src: LazySrcLoc,25502 inst_src: LazySrcLoc,
25415) !Air.Inst.Ref {25503) !Air.Inst.Ref {
25416 // TODO check const/volatile/alignment25504 const inst_ty = sema.typeOf(inst);
25417 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {25505 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
25418 // The comptime Value representation is compatible with both types.25506 // The comptime Value representation is compatible with both types.
25419 return sema.addConstant(dest_ty, val);25507 return sema.addConstant(dest_ty, val);
25420 }25508 }
25421 try sema.requireRuntimeBlock(block, inst_src, null);25509 try sema.requireRuntimeBlock(block, inst_src, null);
25422 const inst_ty = sema.typeOf(inst);
25423 const inst_allows_zero = (inst_ty.zigTypeTag() == .Pointer and inst_ty.ptrAllowsZero()) or true;25510 const inst_allows_zero = (inst_ty.zigTypeTag() == .Pointer and inst_ty.ptrAllowsZero()) or true;
25424 if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero() and25511 if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero() and
25425 try sema.typeHasRuntimeBits(block, sema.src, dest_ty.elemType2()))25512 try sema.typeHasRuntimeBits(block, sema.src, dest_ty.elemType2()))
test/behavior/align.zig+13
...@@ -556,3 +556,16 @@ test "comptime alloc alignment" {...@@ -556,3 +556,16 @@ test "comptime alloc alignment" {
556 var bytes2_addr = @ptrToInt(&bytes2);556 var bytes2_addr = @ptrToInt(&bytes2);
557 try expect(bytes2_addr & 0xff == 0);557 try expect(bytes2_addr & 0xff == 0);
558}558}
559
560test "@alignCast null" {
561 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
562
563 var ptr: ?*anyopaque = null;
564 const aligned: ?*anyopaque = @alignCast(@alignOf(?*anyopaque), ptr);
565 try expect(aligned == null);
566}
567
568test "alignment of slice element" {
569 const a: []align(1024) const u8 = undefined;
570 try expect(@TypeOf(&a[0]) == *align(1024) const u8);
571}
test/behavior/bugs/4328.zig+1-1
...@@ -13,7 +13,7 @@ extern fn fopen([*c]const u8, [*c]const u8) [*c]FILE;...@@ -13,7 +13,7 @@ extern fn fopen([*c]const u8, [*c]const u8) [*c]FILE;
13const S = extern struct {13const S = extern struct {
14 state: c_short,14 state: c_short,
1515
16 extern fn s_do_thing([*c]S, b: c_int) c_short;16 extern fn s_do_thing([*c]const S, b: c_int) c_short;
17};17};
1818
19test "Extern function calls in @TypeOf" {19test "Extern function calls in @TypeOf" {
test/behavior/cast.zig+2-2
...@@ -1242,13 +1242,13 @@ test "implicit cast *[0]T to E![]const u8" {...@@ -1242,13 +1242,13 @@ test "implicit cast *[0]T to E![]const u8" {
12421242
1243var global_array: [4]u8 = undefined;1243var global_array: [4]u8 = undefined;
1244test "cast from array reference to fn: comptime fn ptr" {1244test "cast from array reference to fn: comptime fn ptr" {
1245 const f = @ptrCast(*const fn () callconv(.C) void, &global_array);1245 const f = @ptrCast(*align(1) const fn () callconv(.C) void, &global_array);
1246 try expect(@ptrToInt(f) == @ptrToInt(&global_array));1246 try expect(@ptrToInt(f) == @ptrToInt(&global_array));
1247}1247}
1248test "cast from array reference to fn: runtime fn ptr" {1248test "cast from array reference to fn: runtime fn ptr" {
1249 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO1249 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
12501250
1251 var f = @ptrCast(*const fn () callconv(.C) void, &global_array);1251 var f = @ptrCast(*align(1) const fn () callconv(.C) void, &global_array);
1252 try expect(@ptrToInt(f) == @ptrToInt(&global_array));1252 try expect(@ptrToInt(f) == @ptrToInt(&global_array));
1253}1253}
12541254
test/behavior/slice.zig+2-1
...@@ -322,11 +322,12 @@ test "empty array to slice" {...@@ -322,11 +322,12 @@ test "empty array to slice" {
322322
323test "@ptrCast slice to pointer" {323test "@ptrCast slice to pointer" {
324 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;324 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
325 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
325326
326 const S = struct {327 const S = struct {
327 fn doTheTest() !void {328 fn doTheTest() !void {
328 var array align(@alignOf(u16)) = [5]u8{ 0xff, 0xff, 0xff, 0xff, 0xff };329 var array align(@alignOf(u16)) = [5]u8{ 0xff, 0xff, 0xff, 0xff, 0xff };
329 var slice: []u8 = &array;330 var slice: []align(@alignOf(u16)) u8 = &array;
330 var ptr = @ptrCast(*u16, slice);331 var ptr = @ptrCast(*u16, slice);
331 try expect(ptr.* == 65535);332 try expect(ptr.* == 65535);
332 }333 }
test/behavior/struct.zig+1-1
...@@ -521,7 +521,7 @@ test "packed struct fields are ordered from LSB to MSB" {...@@ -521,7 +521,7 @@ test "packed struct fields are ordered from LSB to MSB" {
521 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO521 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
522522
523 var all: u64 = 0x7765443322221111;523 var all: u64 = 0x7765443322221111;
524 var bytes: [8]u8 = undefined;524 var bytes: [8]u8 align(@alignOf(Bitfields)) = undefined;
525 @memcpy(&bytes, @ptrCast([*]u8, &all), 8);525 @memcpy(&bytes, @ptrCast([*]u8, &all), 8);
526 var bitfields = @ptrCast(*Bitfields, &bytes).*;526 var bitfields = @ptrCast(*Bitfields, &bytes).*;
527527
test/behavior/type.zig+2-2
...@@ -293,7 +293,7 @@ test "Type.Struct" {...@@ -293,7 +293,7 @@ test "Type.Struct" {
293 try testing.expectEqual(@as(?*const anyopaque, null), infoB.fields[0].default_value);293 try testing.expectEqual(@as(?*const anyopaque, null), infoB.fields[0].default_value);
294 try testing.expectEqualSlices(u8, "y", infoB.fields[1].name);294 try testing.expectEqualSlices(u8, "y", infoB.fields[1].name);
295 try testing.expectEqual(u32, infoB.fields[1].field_type);295 try testing.expectEqual(u32, infoB.fields[1].field_type);
296 try testing.expectEqual(@as(u32, 5), @ptrCast(*const u32, infoB.fields[1].default_value.?).*);296 try testing.expectEqual(@as(u32, 5), @ptrCast(*align(1) const u32, infoB.fields[1].default_value.?).*);
297 try testing.expectEqual(@as(usize, 0), infoB.decls.len);297 try testing.expectEqual(@as(usize, 0), infoB.decls.len);
298 try testing.expectEqual(@as(bool, false), infoB.is_tuple);298 try testing.expectEqual(@as(bool, false), infoB.is_tuple);
299299
...@@ -305,7 +305,7 @@ test "Type.Struct" {...@@ -305,7 +305,7 @@ test "Type.Struct" {
305 try testing.expectEqual(@as(u8, 3), @ptrCast(*const u8, infoC.fields[0].default_value.?).*);305 try testing.expectEqual(@as(u8, 3), @ptrCast(*const u8, infoC.fields[0].default_value.?).*);
306 try testing.expectEqualSlices(u8, "y", infoC.fields[1].name);306 try testing.expectEqualSlices(u8, "y", infoC.fields[1].name);
307 try testing.expectEqual(u32, infoC.fields[1].field_type);307 try testing.expectEqual(u32, infoC.fields[1].field_type);
308 try testing.expectEqual(@as(u32, 5), @ptrCast(*const u32, infoC.fields[1].default_value.?).*);308 try testing.expectEqual(@as(u32, 5), @ptrCast(*align(1) const u32, infoC.fields[1].default_value.?).*);
309 try testing.expectEqual(@as(usize, 0), infoC.decls.len);309 try testing.expectEqual(@as(usize, 0), infoC.decls.len);
310 try testing.expectEqual(@as(bool, false), infoC.is_tuple);310 try testing.expectEqual(@as(bool, false), infoC.is_tuple);
311311
test/behavior/type_info.zig+3-3
...@@ -295,8 +295,8 @@ fn testStruct() !void {...@@ -295,8 +295,8 @@ fn testStruct() !void {
295 try expect(unpacked_struct_info.Struct.is_tuple == false);295 try expect(unpacked_struct_info.Struct.is_tuple == false);
296 try expect(unpacked_struct_info.Struct.backing_integer == null);296 try expect(unpacked_struct_info.Struct.backing_integer == null);
297 try expect(unpacked_struct_info.Struct.fields[0].alignment == @alignOf(u32));297 try expect(unpacked_struct_info.Struct.fields[0].alignment == @alignOf(u32));
298 try expect(@ptrCast(*const u32, unpacked_struct_info.Struct.fields[0].default_value.?).* == 4);298 try expect(@ptrCast(*align(1) const u32, unpacked_struct_info.Struct.fields[0].default_value.?).* == 4);
299 try expect(mem.eql(u8, "foobar", @ptrCast(*const *const [6:0]u8, unpacked_struct_info.Struct.fields[1].default_value.?).*));299 try expect(mem.eql(u8, "foobar", @ptrCast(*align(1) const *const [6:0]u8, unpacked_struct_info.Struct.fields[1].default_value.?).*));
300}300}
301301
302const TestStruct = struct {302const TestStruct = struct {
...@@ -321,7 +321,7 @@ fn testPackedStruct() !void {...@@ -321,7 +321,7 @@ fn testPackedStruct() !void {
321 try expect(struct_info.Struct.fields[0].alignment == 0);321 try expect(struct_info.Struct.fields[0].alignment == 0);
322 try expect(struct_info.Struct.fields[2].field_type == f32);322 try expect(struct_info.Struct.fields[2].field_type == f32);
323 try expect(struct_info.Struct.fields[2].default_value == null);323 try expect(struct_info.Struct.fields[2].default_value == null);
324 try expect(@ptrCast(*const u32, struct_info.Struct.fields[3].default_value.?).* == 4);324 try expect(@ptrCast(*align(1) const u32, struct_info.Struct.fields[3].default_value.?).* == 4);
325 try expect(struct_info.Struct.fields[3].alignment == 0);325 try expect(struct_info.Struct.fields[3].alignment == 0);
326 try expect(struct_info.Struct.decls.len == 2);326 try expect(struct_info.Struct.decls.len == 2);
327 try expect(struct_info.Struct.decls[0].is_pub);327 try expect(struct_info.Struct.decls[0].is_pub);
test/cases/compile_errors/alignOf_bad_type.zig created+9
...@@ -0,0 +1,9 @@
1export fn entry() usize {
2 return @alignOf(noreturn);
3}
4
5// error
6// backend=stage2
7// target=native
8//
9// :2:21: error: no align available for type 'noreturn'
test/cases/compile_errors/attempted_implicit_cast_from_const_T_to_sliceT.zig+1
...@@ -9,3 +9,4 @@ export fn entry() void {...@@ -9,3 +9,4 @@ export fn entry() void {
9// target=native9// target=native
10//10//
11// :3:22: error: expected type '[]u32', found '*const u32'11// :3:22: error: expected type '[]u32', found '*const u32'
12// :3:22: note: cast discards const qualifier
test/cases/compile_errors/implicit_cast_between_C_pointer_and_Zig_pointer-bad_const-align-child.zig created+47
...@@ -0,0 +1,47 @@
1export fn a() void {
2 var x: [*c]u8 = undefined;
3 var y: *align(4) u8 = x;
4 _ = y;
5}
6export fn b() void {
7 var x: [*c]const u8 = undefined;
8 var y: *u8 = x;
9 _ = y;
10}
11export fn c() void {
12 var x: [*c]u8 = undefined;
13 var y: *u32 = x;
14 _ = y;
15}
16export fn d() void {
17 var y: *align(1) u32 = undefined;
18 var x: [*c]u32 = y;
19 _ = x;
20}
21export fn e() void {
22 var y: *const u8 = undefined;
23 var x: [*c]u8 = y;
24 _ = x;
25}
26export fn f() void {
27 var y: *u8 = undefined;
28 var x: [*c]u32 = y;
29 _ = x;
30}
31
32// error
33// backend=stage2
34// target=native
35//
36// :3:27: error: expected type '*align(4) u8', found '[*c]u8'
37// :3:27: note: pointer alignment '1' cannot cast into pointer alignment '4'
38// :8:18: error: expected type '*u8', found '[*c]const u8'
39// :8:18: note: cast discards const qualifier
40// :13:19: error: expected type '*u32', found '[*c]u8'
41// :13:19: note: pointer type child 'u8' cannot cast into pointer type child 'u32'
42// :18:22: error: expected type '[*c]u32', found '*align(1) u32'
43// :18:22: note: pointer alignment '1' cannot cast into pointer alignment '4'
44// :23:21: error: expected type '[*c]u8', found '*const u8'
45// :23:21: note: cast discards const qualifier
46// :28:22: error: expected type '[*c]u32', found '*u8'
47// :28:22: note: pointer type child 'u8' cannot cast into pointer type child 'u32'
test/cases/compile_errors/implicit_cast_const_array_to_mutable_slice.zig created+26
...@@ -0,0 +1,26 @@
1export fn entry() void {
2 const buffer: [1]u8 = [_]u8{8};
3 const sliceA: []u8 = &buffer;
4 _ = sliceA;
5}
6export fn entry1() void {
7 const str: *const [0:0]u8 = "";
8 const slice: [:0]u8 = str;
9 _ = slice;
10}
11export fn entry2() void {
12 const str: *const [0:0]u8 = "";
13 const many: [*]u8 = str;
14 _ = many;
15}
16
17// error
18// backend=stage2
19// target=native
20//
21// :3:26: error: expected type '[]u8', found '*const [1]u8'
22// :3:26: note: cast discards const qualifier
23// :8:27: error: expected type '[:0]u8', found '*const [0:0]u8'
24// :8:27: note: cast discards const qualifier
25// :13:25: error: expected type '[*]u8', found '*const [0:0]u8'
26// :13:25: note: cast discards const qualifier
test/cases/compile_errors/implicitly_increasing_slice_alignment.zig created+21
...@@ -0,0 +1,21 @@
1const Foo = packed struct {
2 a: u8,
3 b: u32,
4};
5
6export fn entry() void {
7 var foo = Foo { .a = 1, .b = 10 };
8 foo.b += 1;
9 bar(@as(*[1]u32, &foo.b)[0..]);
10}
11
12fn bar(x: []u32) void {
13 x[0] += 1;
14}
15
16// error
17// backend=stage2
18// target=native
19//
20// :9:22: error: expected type '*[1]u32', found '*align(1) u32'
21// :9:22: note: pointer alignment '1' cannot cast into pointer alignment '4'
test/cases/compile_errors/increase_pointer_alignment_in_ptrCast.zig created+13
...@@ -0,0 +1,13 @@
1export fn entry() u32 {
2 var bytes: [4]u8 = [_]u8{0x01, 0x02, 0x03, 0x04};
3 const ptr = @ptrCast(*u32, &bytes[0]);
4 return ptr.*;
5}
6
7// error
8// backend=stage2
9// target=native
10//
11// :3:17: error: cast increases pointer alignment
12// :3:32: note: '*u8' has alignment '1'
13// :3:26: note: '*u32' has alignment '4'
test/cases/compile_errors/issue_5221_invalid_struct_init_type_referenced_by_typeInfo_and_passed_into_function.zig created+16
...@@ -0,0 +1,16 @@
1fn ignore(comptime param: anytype) void {_ = param;}
2
3export fn foo() void {
4 const MyStruct = struct {
5 wrong_type: []u8 = "foo",
6 };
7
8 comptime ignore(@typeInfo(MyStruct).Struct.fields[0]);
9}
10
11// error
12// backend=stage2
13// target=native
14//
15// :4:22: error: expected type '[]u8', found '*const [3:0]u8'
16// :4:22: note: cast discards const qualifier
test/cases/compile_errors/load_too_many_bytes_from_comptime_reinterpreted_pointer.zig+1-1
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1export fn entry() void {1export fn entry() void {
2 const float: f32 = 5.99999999999994648725e-01;2 const float: f32 align(@alignOf(i64)) = 5.99999999999994648725e-01;
3 const float_ptr = &float;3 const float_ptr = &float;
4 const int_ptr = @ptrCast(*const i64, float_ptr);4 const int_ptr = @ptrCast(*const i64, float_ptr);
5 const int_val = int_ptr.*;5 const int_val = int_ptr.*;
test/cases/compile_errors/peer_cast_then_implicit_cast_const_pointer_to_mutable_C_pointer.zig created+11
...@@ -0,0 +1,11 @@
1export fn func() void {
2 var strValue: [*c]u8 = undefined;
3 strValue = strValue orelse "";
4}
5
6// error
7// backend=stage2
8// target=native
9//
10// :3:32: error: expected type '[*c]u8', found '*const [0:0]u8'
11// :3:32: note: cast discards const qualifier
test/cases/compile_errors/pointer_attributes_checked_when_coercing_pointer_to_anon_literal.zig created+24
...@@ -0,0 +1,24 @@
1comptime {
2 const c: [][]const u8 = &.{ "hello", "world" };
3 _ = c;
4}
5comptime {
6 const c: *[2][]const u8 = &.{ "hello", "world" };
7 _ = c;
8}
9const S = struct { a: u8 = 1, b: u32 = 2 };
10comptime {
11 const c: *S = &.{ .a = 2 };
12 _ = c;
13}
14
15// error
16// backend=stage2
17// target=native
18//
19// :2:29: error: expected type '[][]const u8', found '*const tuple{comptime *const [5:0]u8 = "hello", comptime *const [5:0]u8 = "world"}'
20// :2:29: note: cast discards const qualifier
21// :6:31: error: expected type '*[2][]const u8', found '*const tuple{comptime *const [5:0]u8 = "hello", comptime *const [5:0]u8 = "world"}'
22// :6:31: note: cast discards const qualifier
23// :11:19: error: expected type '*tmp.S', found '*const struct{comptime a: comptime_int = 2}'
24// :11:19: note: cast discards const qualifier
test/cases/compile_errors/ptrCast_discards_const_qualifier.zig created+11
...@@ -0,0 +1,11 @@
1export fn entry() void {
2 const x: i32 = 1234;
3 const y = @ptrCast(*i32, &x);
4 _ = y;
5}
6
7// error
8// backend=stage2
9// target=native
10//
11// :3:15: error: cast discards const qualifier
test/cases/compile_errors/reading_past_end_of_pointer_casted_array.zig+1-1
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1comptime {1comptime {
2 const array: [4]u8 = "aoeu".*;2 const array: [4]u8 = "aoeu".*;
3 const sub_array = array[1..];3 const sub_array = array[1..];
4 const int_ptr = @ptrCast(*const u24, sub_array);4 const int_ptr = @ptrCast(*const u24, @alignCast(@alignOf(u24), sub_array));
5 const deref = int_ptr.*;5 const deref = int_ptr.*;
6 _ = deref;6 _ = deref;
7}7}
test/cases/compile_errors/slice_cannot_have_its_bytes_reinterpreted.zig+1-1
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1export fn foo() void {1export fn foo() void {
2 const bytes = [1]u8{ 0xfa } ** 16;2 const bytes align(@alignOf([]const u8)) = [1]u8{0xfa} ** 16;
3 var value = @ptrCast(*const []const u8, &bytes).*;3 var value = @ptrCast(*const []const u8, &bytes).*;
4 _ = value;4 _ = value;
5}5}
test/cases/compile_errors/stage1/obj/implicit_cast_between_C_pointer_and_Zig_pointer-bad_const-align-child.zig deleted-42
...@@ -1,42 +0,0 @@
1export fn a() void {
2 var x: [*c]u8 = undefined;
3 var y: *align(4) u8 = x;
4 _ = y;
5}
6export fn b() void {
7 var x: [*c]const u8 = undefined;
8 var y: *u8 = x;
9 _ = y;
10}
11export fn c() void {
12 var x: [*c]u8 = undefined;
13 var y: *u32 = x;
14 _ = y;
15}
16export fn d() void {
17 var y: *align(1) u32 = undefined;
18 var x: [*c]u32 = y;
19 _ = x;
20}
21export fn e() void {
22 var y: *const u8 = undefined;
23 var x: [*c]u8 = y;
24 _ = x;
25}
26export fn f() void {
27 var y: *u8 = undefined;
28 var x: [*c]u32 = y;
29 _ = x;
30}
31
32// error
33// backend=stage1
34// target=native
35//
36// tmp.zig:3:27: error: cast increases pointer alignment
37// tmp.zig:8:18: error: cast discards const qualifier
38// tmp.zig:13:19: error: expected type '*u32', found '[*c]u8'
39// tmp.zig:13:19: note: pointer type child 'u8' cannot cast into pointer type child 'u32'
40// tmp.zig:18:22: error: cast increases pointer alignment
41// tmp.zig:23:21: error: cast discards const qualifier
42// tmp.zig:28:22: error: expected type '[*c]u32', found '*u8'
test/cases/compile_errors/stage1/obj/implicit_cast_const_array_to_mutable_slice.zig deleted-12
...@@ -1,12 +0,0 @@
1export fn entry() void {
2 const buffer: [1]u8 = [_]u8{8};
3 const sliceA: []u8 = &buffer;
4 _ = sliceA;
5}
6
7// error
8// backend=stage1
9// target=native
10//
11// tmp.zig:3:27: error: cannot cast pointer to array literal to slice type '[]u8'
12// tmp.zig:3:27: note: cast discards const qualifier
test/cases/compile_errors/stage1/obj/implicitly_increasing_slice_alignment.zig deleted-22
...@@ -1,22 +0,0 @@
1const Foo = packed struct {
2 a: u8,
3 b: u32,
4};
5
6export fn entry() void {
7 var foo = Foo { .a = 1, .b = 10 };
8 foo.b += 1;
9 bar(@as(*[1]u32, &foo.b)[0..]);
10}
11
12fn bar(x: []u32) void {
13 x[0] += 1;
14}
15
16// error
17// backend=stage1
18// target=native
19//
20// tmp.zig:9:26: error: cast increases pointer alignment
21// tmp.zig:9:26: note: '*align(1) u32' has alignment 1
22// tmp.zig:9:26: note: '*[1]u32' has alignment 4
test/cases/compile_errors/stage1/obj/increase_pointer_alignment_in_ptrCast.zig deleted-13
...@@ -1,13 +0,0 @@
1export fn entry() u32 {
2 var bytes: [4]u8 = [_]u8{0x01, 0x02, 0x03, 0x04};
3 const ptr = @ptrCast(*u32, &bytes[0]);
4 return ptr.*;
5}
6
7// error
8// backend=stage1
9// target=native
10//
11// tmp.zig:3:17: error: cast increases pointer alignment
12// tmp.zig:3:38: note: '*u8' has alignment 1
13// tmp.zig:3:26: note: '*u32' has alignment 4
test/cases/compile_errors/stage1/obj/issue_5221_invalid_struct_init_type_referenced_by_typeInfo_and_passed_into_function.zig deleted-16
...@@ -1,16 +0,0 @@
1fn ignore(comptime param: anytype) void {_ = param;}
2
3export fn foo() void {
4 const MyStruct = struct {
5 wrong_type: []u8 = "foo",
6 };
7
8 comptime ignore(@typeInfo(MyStruct).Struct.fields[0]);
9}
10
11// error
12// backend=stage1
13// target=native
14//
15// :5:28: error: cannot cast pointer to array literal to slice type '[]u8'
16// :5:28: note: cast discards const qualifier
test/cases/compile_errors/stage1/obj/peer_cast_then_implicit_cast_const_pointer_to_mutable_C_pointer.zig deleted-11
...@@ -1,11 +0,0 @@
1export fn func() void {
2 var strValue: [*c]u8 = undefined;
3 strValue = strValue orelse "";
4}
5
6// error
7// backend=stage1
8// target=native
9//
10// tmp.zig:3:32: error: expected type '[*c]u8', found '*const [0:0]u8'
11// tmp.zig:3:32: note: cast discards const qualifier
test/cases/compile_errors/stage1/obj/pointer_attributes_checked_when_coercing_pointer_to_anon_literal.zig deleted-24
...@@ -1,24 +0,0 @@
1comptime {
2 const c: [][]const u8 = &.{"hello", "world" };
3 _ = c;
4}
5comptime {
6 const c: *[2][]const u8 = &.{"hello", "world" };
7 _ = c;
8}
9const S = struct {a: u8 = 1, b: u32 = 2};
10comptime {
11 const c: *S = &.{};
12 _ = c;
13}
14
15// error
16// backend=stage1
17// target=native
18//
19// tmp.zig:2:31: error: cannot cast pointer to array literal to slice type '[][]const u8'
20// tmp.zig:2:31: note: cast discards const qualifier
21// tmp.zig:6:33: error: cannot cast pointer to array literal to '*[2][]const u8'
22// tmp.zig:6:33: note: cast discards const qualifier
23// tmp.zig:11:21: error: expected type '*S', found '*const struct:11:21'
24// tmp.zig:11:21: note: cast discards const qualifier
test/cases/compile_errors/stage1/obj/ptrCast_discards_const_qualifier.zig deleted-11
...@@ -1,11 +0,0 @@
1export fn entry() void {
2 const x: i32 = 1234;
3 const y = @ptrCast(*i32, &x);
4 _ = y;
5}
6
7// error
8// backend=stage1
9// target=native
10//
11// tmp.zig:3:15: error: cast discards const qualifier