authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-14 21:11:49-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-14 21:43:03-07:00
log2f92d1a0264b6827cb67a55726c4c9a082337508
treed6691a25a828b44cb4c17365fb8549d339046810
parent50a1ca24ca2a4311097132d660b8244f252da82f

stage2: fixups for topolarity-comptime-memory-reinterp branch

* don't store `has_well_defined_layout` in memory. * remove struct `hasWellDefinedLayout` logic. it's just `layout != .Auto`. This means we only need one implementation, in Type. * fix some of the cases being wrong in `hasWellDefinedLayout`, such as optional pointers. * move `tag_ty_inferred` field into a position that makes it more obvious how the struct layout will be done. Also we don't have a compiler that intelligently moves fields around so this layout is better. * Sema: don't `resolveTypeLayout` in `zirCoerceResultPtr` unless necessary. * Rename `ComptimePtrLoadKit` `target` field to `pointee` to avoid confusion with `target`.

8 files changed, 76 insertions(+), 271 deletions(-)

src/Module.zig+2-4
...@@ -885,7 +885,6 @@ pub const Struct = struct {...@@ -885,7 +885,6 @@ pub const Struct = struct {
885 /// one possible value.885 /// one possible value.
886 known_non_opv: bool,886 known_non_opv: bool,
887 requires_comptime: PropertyBoolean = .unknown,887 requires_comptime: PropertyBoolean = .unknown,
888 has_well_defined_layout: PropertyBoolean = .unknown,
889888
890 pub const Fields = std.StringArrayHashMapUnmanaged(Field);889 pub const Fields = std.StringArrayHashMapUnmanaged(Field);
891890
...@@ -1080,8 +1079,6 @@ pub const EnumFull = struct {...@@ -1080,8 +1079,6 @@ pub const EnumFull = struct {
1080 /// An integer type which is used for the numerical value of the enum.1079 /// An integer type which is used for the numerical value of the enum.
1081 /// Whether zig chooses this type or the user specifies it, it is stored here.1080 /// Whether zig chooses this type or the user specifies it, it is stored here.
1082 tag_ty: Type,1081 tag_ty: Type,
1083 /// true if zig inferred this tag type, false if user specified it
1084 tag_ty_inferred: bool,
1085 /// Set of field names in declaration order.1082 /// Set of field names in declaration order.
1086 fields: NameMap,1083 fields: NameMap,
1087 /// Maps integer tag value to field index.1084 /// Maps integer tag value to field index.
...@@ -1092,6 +1089,8 @@ pub const EnumFull = struct {...@@ -1092,6 +1089,8 @@ pub const EnumFull = struct {
1092 namespace: Namespace,1089 namespace: Namespace,
1093 /// Offset from `owner_decl`, points to the enum decl AST node.1090 /// Offset from `owner_decl`, points to the enum decl AST node.
1094 node_offset: i32,1091 node_offset: i32,
1092 /// true if zig inferred this tag type, false if user specified it
1093 tag_ty_inferred: bool,
10951094
1096 pub const NameMap = std.StringArrayHashMapUnmanaged(void);1095 pub const NameMap = std.StringArrayHashMapUnmanaged(void);
1097 pub const ValueMap = std.ArrayHashMapUnmanaged(Value, void, Value.ArrayHashContext, false);1096 pub const ValueMap = std.ArrayHashMapUnmanaged(Value, void, Value.ArrayHashContext, false);
...@@ -1136,7 +1135,6 @@ pub const Union = struct {...@@ -1136,7 +1135,6 @@ pub const Union = struct {
1136 fully_resolved,1135 fully_resolved,
1137 },1136 },
1138 requires_comptime: PropertyBoolean = .unknown,1137 requires_comptime: PropertyBoolean = .unknown,
1139 has_well_defined_layout: PropertyBoolean = .unknown,
11401138
1141 pub const Field = struct {1139 pub const Field = struct {
1142 /// undefined until `status` is `have_field_types` or `have_layout`.1140 /// undefined until `status` is `have_field_types` or `have_layout`.
src/Sema.zig+30-205
...@@ -1579,8 +1579,6 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -1579,8 +1579,6 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
1579 const target = sema.mod.getTarget();1579 const target = sema.mod.getTarget();
1580 const addr_space = target_util.defaultAddressSpace(target, .local);1580 const addr_space = target_util.defaultAddressSpace(target, .local);
15811581
1582 try sema.resolveTypeLayout(block, src, pointee_ty);
1583
1584 if (Air.refToIndex(ptr)) |ptr_inst| {1582 if (Air.refToIndex(ptr)) |ptr_inst| {
1585 if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) {1583 if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) {
1586 const air_datas = sema.air_instructions.items(.data);1584 const air_datas = sema.air_instructions.items(.data);
...@@ -1617,6 +1615,9 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -1617,6 +1615,9 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
1617 try pointee_ty.copy(anon_decl.arena()),1615 try pointee_ty.copy(anon_decl.arena()),
1618 Value.undef,1616 Value.undef,
1619 );1617 );
1618 if (iac.data.alignment != 0) {
1619 try sema.resolveTypeLayout(block, src, pointee_ty);
1620 }
1620 const ptr_ty = try Type.ptr(sema.arena, target, .{1621 const ptr_ty = try Type.ptr(sema.arena, target, .{
1621 .pointee_type = pointee_ty,1622 .pointee_type = pointee_ty,
1622 .@"align" = iac.data.alignment,1623 .@"align" = iac.data.alignment,
...@@ -1886,7 +1887,7 @@ fn zirEnumDecl(...@@ -1886,7 +1887,7 @@ fn zirEnumDecl(
18861887
1887 enum_obj.* = .{1888 enum_obj.* = .{
1888 .owner_decl = new_decl,1889 .owner_decl = new_decl,
1889 .tag_ty = Type.initTag(.@"null"),1890 .tag_ty = Type.@"null",
1890 .tag_ty_inferred = true,1891 .tag_ty_inferred = true,
1891 .fields = .{},1892 .fields = .{},
1892 .values = .{},1893 .values = .{},
...@@ -17867,13 +17868,13 @@ const TypedValueAndOffset = struct {...@@ -17867,13 +17868,13 @@ const TypedValueAndOffset = struct {
17867};17868};
1786817869
17869const ComptimePtrLoadKit = struct {17870const ComptimePtrLoadKit = struct {
17870 /// The Value and Type corresponding to the target of the provided pointer.17871 /// The Value and Type corresponding to the pointee of the provided pointer.
17871 /// If a direct dereference is not possible, this is null.17872 /// If a direct dereference is not possible, this is null.
17872 target: ?TypedValue,17873 pointee: ?TypedValue,
17873 /// The largest parent Value containing `target` and having a well-defined memory layout.17874 /// The largest parent Value containing `pointee` and having a well-defined memory layout.
17874 /// This is used for bitcasting, if direct dereferencing failed (i.e. `target` is null).17875 /// This is used for bitcasting, if direct dereferencing failed (i.e. `pointee` is null).
17875 parent: ?TypedValueAndOffset,17876 parent: ?TypedValueAndOffset,
17876 /// Whether the `target` could be mutated by further17877 /// Whether the `pointee` could be mutated by further
17877 /// semantic analysis and a copy must be performed.17878 /// semantic analysis and a copy must be performed.
17878 is_mutable: bool,17879 is_mutable: bool,
17879 /// If the root decl could not be used as `parent`, this is the type that17880 /// If the root decl could not be used as `parent`, this is the type that
...@@ -17885,7 +17886,7 @@ const ComptimePtrLoadError = CompileError || error{...@@ -17885,7 +17886,7 @@ const ComptimePtrLoadError = CompileError || error{
17885 RuntimeLoad,17886 RuntimeLoad,
17886};17887};
1788717888
17888/// If `maybe_array_ty` is provided, it will be used to directly dereference an 17889/// If `maybe_array_ty` is provided, it will be used to directly dereference an
17889/// .elem_ptr of type T to a value of [N]T, if necessary.17890/// .elem_ptr of type T to a value of [N]T, if necessary.
17890fn beginComptimePtrLoad(17891fn beginComptimePtrLoad(
17891 sema: *Sema,17892 sema: *Sema,
...@@ -17908,10 +17909,10 @@ fn beginComptimePtrLoad(...@@ -17908,10 +17909,10 @@ fn beginComptimePtrLoad(
17908 const decl_tv = try decl.typedValue();17909 const decl_tv = try decl.typedValue();
17909 if (decl_tv.val.tag() == .variable) return error.RuntimeLoad;17910 if (decl_tv.val.tag() == .variable) return error.RuntimeLoad;
1791017911
17911 const layout_defined = try sema.typeHasWellDefinedLayout(block, src, decl.ty);17912 const layout_defined = decl.ty.hasWellDefinedLayout();
17912 break :blk ComptimePtrLoadKit{17913 break :blk ComptimePtrLoadKit{
17913 .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null,17914 .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null,
17914 .target = decl_tv,17915 .pointee = decl_tv,
17915 .is_mutable = is_mutable,17916 .is_mutable = is_mutable,
17916 .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null,17917 .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null,
17917 };17918 };
...@@ -17923,7 +17924,7 @@ fn beginComptimePtrLoad(...@@ -17923,7 +17924,7 @@ fn beginComptimePtrLoad(
17923 var deref = try beginComptimePtrLoad(sema, block, src, elem_ptr.array_ptr, null);17924 var deref = try beginComptimePtrLoad(sema, block, src, elem_ptr.array_ptr, null);
1792417925
17925 if (elem_ptr.index != 0) {17926 if (elem_ptr.index != 0) {
17926 if (try sema.typeHasWellDefinedLayout(block, src, elem_ty)) {17927 if (elem_ty.hasWellDefinedLayout()) {
17927 if (deref.parent) |*parent| {17928 if (deref.parent) |*parent| {
17928 // Update the byte offset (in-place)17929 // Update the byte offset (in-place)
17929 const elem_size = try sema.typeAbiSize(block, src, elem_ty);17930 const elem_size = try sema.typeAbiSize(block, src, elem_ty);
...@@ -17938,17 +17939,17 @@ fn beginComptimePtrLoad(...@@ -17938,17 +17939,17 @@ fn beginComptimePtrLoad(
1793817939
17939 // If we're loading an elem_ptr that was derived from a different type17940 // If we're loading an elem_ptr that was derived from a different type
17940 // than the true type of the underlying decl, we cannot deref directly17941 // than the true type of the underlying decl, we cannot deref directly
17941 const ty_matches = if (deref.target != null and deref.target.?.ty.isArrayLike()) x: {17942 const ty_matches = if (deref.pointee != null and deref.pointee.?.ty.isArrayLike()) x: {
17942 const deref_elem_ty = deref.target.?.ty.childType();17943 const deref_elem_ty = deref.pointee.?.ty.childType();
17943 break :x (try sema.coerceInMemoryAllowed(block, deref_elem_ty, elem_ty, false, target, src, src)) == .ok or17944 break :x (try sema.coerceInMemoryAllowed(block, deref_elem_ty, elem_ty, false, target, src, src)) == .ok or
17944 (try sema.coerceInMemoryAllowed(block, elem_ty, deref_elem_ty, false, target, src, src)) == .ok;17945 (try sema.coerceInMemoryAllowed(block, elem_ty, deref_elem_ty, false, target, src, src)) == .ok;
17945 } else false;17946 } else false;
17946 if (!ty_matches) {17947 if (!ty_matches) {
17947 deref.target = null;17948 deref.pointee = null;
17948 break :blk deref;17949 break :blk deref;
17949 }17950 }
1795017951
17951 var array_tv = deref.target.?;17952 var array_tv = deref.pointee.?;
17952 const check_len = array_tv.ty.arrayLenIncludingSentinel();17953 const check_len = array_tv.ty.arrayLenIncludingSentinel();
17953 if (elem_ptr.index >= check_len) {17954 if (elem_ptr.index >= check_len) {
17954 // TODO have the deref include the decl so we can say "declared here"17955 // TODO have the deref include the decl so we can say "declared here"
...@@ -17959,10 +17960,10 @@ fn beginComptimePtrLoad(...@@ -17959,10 +17960,10 @@ fn beginComptimePtrLoad(
1795917960
17960 if (maybe_array_ty) |load_ty| {17961 if (maybe_array_ty) |load_ty| {
17961 // It's possible that we're loading a [N]T, in which case we'd like to slice17962 // It's possible that we're loading a [N]T, in which case we'd like to slice
17962 // the target array directly from our parent array.17963 // the pointee array directly from our parent array.
17963 if (load_ty.isArrayLike() and load_ty.childType().eql(elem_ty)) {17964 if (load_ty.isArrayLike() and load_ty.childType().eql(elem_ty)) {
17964 const N = try sema.usizeCast(block, src, load_ty.arrayLenIncludingSentinel());17965 const N = try sema.usizeCast(block, src, load_ty.arrayLenIncludingSentinel());
17965 deref.target = if (elem_ptr.index + N <= check_len) TypedValue{17966 deref.pointee = if (elem_ptr.index + N <= check_len) TypedValue{
17966 .ty = try Type.array(sema.arena, N, null, elem_ty),17967 .ty = try Type.array(sema.arena, N, null, elem_ty),
17967 .val = try array_tv.val.sliceArray(sema.arena, elem_ptr.index, elem_ptr.index + N),17968 .val = try array_tv.val.sliceArray(sema.arena, elem_ptr.index, elem_ptr.index + N),
17968 } else null;17969 } else null;
...@@ -17970,7 +17971,7 @@ fn beginComptimePtrLoad(...@@ -17970,7 +17971,7 @@ fn beginComptimePtrLoad(
17970 }17971 }
17971 }17972 }
1797217973
17973 deref.target = .{17974 deref.pointee = .{
17974 .ty = elem_ty,17975 .ty = elem_ty,
17975 .val = try array_tv.val.elemValue(sema.arena, elem_ptr.index),17976 .val = try array_tv.val.elemValue(sema.arena, elem_ptr.index),
17976 };17977 };
...@@ -17983,7 +17984,7 @@ fn beginComptimePtrLoad(...@@ -17983,7 +17984,7 @@ fn beginComptimePtrLoad(
17983 const field_ty = field_ptr.container_ty.structFieldType(field_index);17984 const field_ty = field_ptr.container_ty.structFieldType(field_index);
17984 var deref = try beginComptimePtrLoad(sema, block, src, field_ptr.container_ptr, field_ptr.container_ty);17985 var deref = try beginComptimePtrLoad(sema, block, src, field_ptr.container_ptr, field_ptr.container_ty);
1798517986
17986 if (try sema.typeHasWellDefinedLayout(block, src, field_ptr.container_ty)) {17987 if (field_ptr.container_ty.hasWellDefinedLayout()) {
17987 if (deref.parent) |*parent| {17988 if (deref.parent) |*parent| {
17988 // Update the byte offset (in-place)17989 // Update the byte offset (in-place)
17989 try sema.resolveTypeLayout(block, src, field_ptr.container_ty);17990 try sema.resolveTypeLayout(block, src, field_ptr.container_ty);
...@@ -17995,19 +17996,19 @@ fn beginComptimePtrLoad(...@@ -17995,19 +17996,19 @@ fn beginComptimePtrLoad(
17995 deref.ty_without_well_defined_layout = field_ptr.container_ty;17996 deref.ty_without_well_defined_layout = field_ptr.container_ty;
17996 }17997 }
1799717998
17998 if (deref.target) |*tv| {17999 if (deref.pointee) |*tv| {
17999 const coerce_in_mem_ok =18000 const coerce_in_mem_ok =
18000 (try sema.coerceInMemoryAllowed(block, field_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or18001 (try sema.coerceInMemoryAllowed(block, field_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or
18001 (try sema.coerceInMemoryAllowed(block, tv.ty, field_ptr.container_ty, false, target, src, src)) == .ok;18002 (try sema.coerceInMemoryAllowed(block, tv.ty, field_ptr.container_ty, false, target, src, src)) == .ok;
18002 if (coerce_in_mem_ok) {18003 if (coerce_in_mem_ok) {
18003 deref.target = TypedValue{18004 deref.pointee = TypedValue{
18004 .ty = field_ty,18005 .ty = field_ty,
18005 .val = try tv.val.fieldValue(sema.arena, field_index),18006 .val = try tv.val.fieldValue(sema.arena, field_index),
18006 };18007 };
18007 break :blk deref;18008 break :blk deref;
18008 }18009 }
18009 }18010 }
18010 deref.target = null;18011 deref.pointee = null;
18011 break :blk deref;18012 break :blk deref;
18012 },18013 },
1801318014
...@@ -18028,7 +18029,7 @@ fn beginComptimePtrLoad(...@@ -18028,7 +18029,7 @@ fn beginComptimePtrLoad(
18028 deref.ty_without_well_defined_layout = payload_ptr.container_ty;18029 deref.ty_without_well_defined_layout = payload_ptr.container_ty;
18029 }18030 }
1803018031
18031 if (deref.target) |*tv| {18032 if (deref.pointee) |*tv| {
18032 const coerce_in_mem_ok =18033 const coerce_in_mem_ok =
18033 (try sema.coerceInMemoryAllowed(block, payload_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or18034 (try sema.coerceInMemoryAllowed(block, payload_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or
18034 (try sema.coerceInMemoryAllowed(block, tv.ty, payload_ptr.container_ty, false, target, src, src)) == .ok;18035 (try sema.coerceInMemoryAllowed(block, tv.ty, payload_ptr.container_ty, false, target, src, src)) == .ok;
...@@ -18042,7 +18043,7 @@ fn beginComptimePtrLoad(...@@ -18042,7 +18043,7 @@ fn beginComptimePtrLoad(
18042 break :blk deref;18043 break :blk deref;
18043 }18044 }
18044 }18045 }
18045 deref.target = null;18046 deref.pointee = null;
18046 break :blk deref;18047 break :blk deref;
18047 },18048 },
1804818049
...@@ -18060,7 +18061,7 @@ fn beginComptimePtrLoad(...@@ -18060,7 +18061,7 @@ fn beginComptimePtrLoad(
18060 else => unreachable,18061 else => unreachable,
18061 };18062 };
1806218063
18063 if (deref.target) |tv| {18064 if (deref.pointee) |tv| {
18064 if (deref.parent == null and tv.ty.hasWellDefinedLayout()) {18065 if (deref.parent == null and tv.ty.hasWellDefinedLayout()) {
18065 deref.parent = .{ .tv = tv, .byte_offset = 0 };18066 deref.parent = .{ .tv = tv, .byte_offset = 0 };
18066 }18067 }
...@@ -21157,7 +21158,7 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr...@@ -21157,7 +21158,7 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr
21157 else => |e| return e,21158 else => |e| return e,
21158 };21159 };
2115921160
21160 if (deref.target) |tv| {21161 if (deref.pointee) |tv| {
21161 const coerce_in_mem_ok =21162 const coerce_in_mem_ok =
21162 (try sema.coerceInMemoryAllowed(block, load_ty, tv.ty, false, target, src, src)) == .ok or21163 (try sema.coerceInMemoryAllowed(block, load_ty, tv.ty, false, target, src, src)) == .ok or
21163 (try sema.coerceInMemoryAllowed(block, tv.ty, load_ty, false, target, src, src)) == .ok;21164 (try sema.coerceInMemoryAllowed(block, tv.ty, load_ty, false, target, src, src)) == .ok;
...@@ -21176,13 +21177,13 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr...@@ -21176,13 +21177,13 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr
2117621177
21177 // The type is not in-memory coercible or the direct dereference failed, so it must21178 // The type is not in-memory coercible or the direct dereference failed, so it must
21178 // be bitcast according to the pointer type we are performing the load through.21179 // be bitcast according to the pointer type we are performing the load through.
21179 if (!(try sema.typeHasWellDefinedLayout(block, src, load_ty)))21180 if (!load_ty.hasWellDefinedLayout())
21180 return sema.fail(block, src, "comptime dereference requires {} to have a well-defined layout, but it does not.", .{load_ty});21181 return sema.fail(block, src, "comptime dereference requires {} to have a well-defined layout, but it does not.", .{load_ty});
2118121182
21182 const load_sz = try sema.typeAbiSize(block, src, load_ty);21183 const load_sz = try sema.typeAbiSize(block, src, load_ty);
2118321184
21184 // Try the smaller bit-cast first, since that's more efficient than using the larger `parent`21185 // Try the smaller bit-cast first, since that's more efficient than using the larger `parent`
21185 if (deref.target) |tv| if (load_sz <= try sema.typeAbiSize(block, src, tv.ty))21186 if (deref.pointee) |tv| if (load_sz <= try sema.typeAbiSize(block, src, tv.ty))
21186 return try sema.bitCastVal(block, src, tv.val, tv.ty, load_ty, 0);21187 return try sema.bitCastVal(block, src, tv.val, tv.ty, load_ty, 0);
2118721188
21188 // If that fails, try to bit-cast from the largest parent value with a well-defined layout21189 // If that fails, try to bit-cast from the largest parent value with a well-defined layout
...@@ -21271,182 +21272,6 @@ fn typePtrOrOptionalPtrTy(...@@ -21271,182 +21272,6 @@ fn typePtrOrOptionalPtrTy(
21271 }21272 }
21272}21273}
2127321274
21274fn typeHasWellDefinedLayout(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
21275 return switch (ty.tag()) {
21276 .u1,
21277 .u8,
21278 .i8,
21279 .u16,
21280 .i16,
21281 .u32,
21282 .i32,
21283 .u64,
21284 .i64,
21285 .u128,
21286 .i128,
21287 .usize,
21288 .isize,
21289 .c_short,
21290 .c_ushort,
21291 .c_int,
21292 .c_uint,
21293 .c_long,
21294 .c_ulong,
21295 .c_longlong,
21296 .c_ulonglong,
21297 .c_longdouble,
21298 .f16,
21299 .f32,
21300 .f64,
21301 .f80,
21302 .f128,
21303 .bool,
21304 .void,
21305 .manyptr_u8,
21306 .manyptr_const_u8,
21307 .manyptr_const_u8_sentinel_0,
21308 .anyerror_void_error_union,
21309 .empty_struct_literal,
21310 .empty_struct,
21311 .array_u8,
21312 .array_u8_sentinel_0,
21313 .int_signed,
21314 .int_unsigned,
21315 .pointer,
21316 .single_const_pointer,
21317 .single_mut_pointer,
21318 .many_const_pointer,
21319 .many_mut_pointer,
21320 .c_const_pointer,
21321 .c_mut_pointer,
21322 .single_const_pointer_to_comptime_int,
21323 .enum_numbered,
21324 => true,
21325
21326 .anyopaque,
21327 .anyerror,
21328 .noreturn,
21329 .@"null",
21330 .@"anyframe",
21331 .@"undefined",
21332 .atomic_order,
21333 .atomic_rmw_op,
21334 .calling_convention,
21335 .address_space,
21336 .float_mode,
21337 .reduce_op,
21338 .call_options,
21339 .prefetch_options,
21340 .export_options,
21341 .extern_options,
21342 .error_set,
21343 .error_set_single,
21344 .error_set_inferred,
21345 .error_set_merged,
21346 .@"opaque",
21347 .generic_poison,
21348 .type,
21349 .comptime_int,
21350 .comptime_float,
21351 .enum_literal,
21352 .type_info,
21353 // These are function bodies, not function pointers.
21354 .fn_noreturn_no_args,
21355 .fn_void_no_args,
21356 .fn_naked_noreturn_no_args,
21357 .fn_ccc_void_no_args,
21358 .function,
21359 .const_slice_u8,
21360 .const_slice_u8_sentinel_0,
21361 .const_slice,
21362 .mut_slice,
21363 .enum_simple,
21364 .error_union,
21365 .anyframe_T,
21366 .tuple,
21367 .anon_struct,
21368 => false,
21369
21370 .enum_full,
21371 .enum_nonexhaustive,
21372 => !ty.cast(Type.Payload.EnumFull).?.data.tag_ty_inferred,
21373
21374 .var_args_param => unreachable,
21375 .inferred_alloc_mut => unreachable,
21376 .inferred_alloc_const => unreachable,
21377 .bound_fn => unreachable,
21378
21379 .array,
21380 .array_sentinel,
21381 .vector,
21382 => sema.typeHasWellDefinedLayout(block, src, ty.childType()),
21383
21384 .optional,
21385 .optional_single_mut_pointer,
21386 .optional_single_const_pointer,
21387 => blk: {
21388 var buf: Type.Payload.ElemType = undefined;
21389 break :blk sema.typeHasWellDefinedLayout(block, src, ty.optionalChild(&buf));
21390 },
21391
21392 .@"struct" => {
21393 const struct_obj = ty.castTag(.@"struct").?.data;
21394 if (struct_obj.layout == .Auto) {
21395 struct_obj.has_well_defined_layout = .no;
21396 return false;
21397 }
21398 switch (struct_obj.has_well_defined_layout) {
21399 .no => return false,
21400 .yes, .wip => return true,
21401 .unknown => {
21402 if (struct_obj.status == .field_types_wip)
21403 return true;
21404
21405 try sema.resolveTypeFieldsStruct(block, src, ty, struct_obj);
21406
21407 struct_obj.has_well_defined_layout = .wip;
21408 for (struct_obj.fields.values()) |field| {
21409 if (!(try sema.typeHasWellDefinedLayout(block, src, field.ty))) {
21410 struct_obj.has_well_defined_layout = .no;
21411 return false;
21412 }
21413 }
21414 struct_obj.has_well_defined_layout = .yes;
21415 return true;
21416 },
21417 }
21418 },
21419
21420 .@"union", .union_tagged => {
21421 const union_obj = ty.cast(Type.Payload.Union).?.data;
21422 if (union_obj.layout == .Auto) {
21423 union_obj.has_well_defined_layout = .no;
21424 return false;
21425 }
21426 switch (union_obj.has_well_defined_layout) {
21427 .no => return false,
21428 .yes, .wip => return true,
21429 .unknown => {
21430 if (union_obj.status == .field_types_wip)
21431 return true;
21432
21433 try sema.resolveTypeFieldsUnion(block, src, ty, union_obj);
21434
21435 union_obj.has_well_defined_layout = .wip;
21436 for (union_obj.fields.values()) |field| {
21437 if (!(try sema.typeHasWellDefinedLayout(block, src, field.ty))) {
21438 union_obj.has_well_defined_layout = .no;
21439 return false;
21440 }
21441 }
21442 union_obj.has_well_defined_layout = .yes;
21443 return true;
21444 },
21445 }
21446 },
21447 };
21448}
21449
21450/// `generic_poison` will return false.21275/// `generic_poison` will return false.
21451/// This function returns false negatives when structs and unions are having their21276/// This function returns false negatives when structs and unions are having their
21452/// field types resolved.21277/// field types resolved.
src/codegen/llvm.zig+4-1
...@@ -2829,7 +2829,10 @@ pub const DeclGen = struct {...@@ -2829,7 +2829,10 @@ pub const DeclGen = struct {
2829 // (void) payload is the same.2829 // (void) payload is the same.
2830 break :blk parent_llvm_ptr;2830 break :blk parent_llvm_ptr;
2831 }2831 }
2832 const llvm_pl_index = if (layout.tag_size == 0) 0 else @boolToInt(layout.tag_align >= layout.payload_align);2832 const llvm_pl_index = if (layout.tag_size == 0)
2833 0
2834 else
2835 @boolToInt(layout.tag_align >= layout.payload_align);
2833 const indices: [2]*const llvm.Value = .{2836 const indices: [2]*const llvm.Value = .{
2834 llvm_u32.constInt(0, .False),2837 llvm_u32.constInt(0, .False),
2835 llvm_u32.constInt(llvm_pl_index, .False),2838 llvm_u32.constInt(llvm_pl_index, .False),
src/type.zig+15-36
...@@ -2210,9 +2210,6 @@ pub const Type = extern union {...@@ -2210,9 +2210,6 @@ pub const Type = extern union {
2210 .manyptr_u8,2210 .manyptr_u8,
2211 .manyptr_const_u8,2211 .manyptr_const_u8,
2212 .manyptr_const_u8_sentinel_0,2212 .manyptr_const_u8_sentinel_0,
2213 .anyerror_void_error_union,
2214 .empty_struct_literal,
2215 .empty_struct,
2216 .array_u8,2213 .array_u8,
2217 .array_u8_sentinel_0,2214 .array_u8_sentinel_0,
2218 .int_signed,2215 .int_signed,
...@@ -2226,6 +2223,9 @@ pub const Type = extern union {...@@ -2226,6 +2223,9 @@ pub const Type = extern union {
2226 .c_mut_pointer,2223 .c_mut_pointer,
2227 .single_const_pointer_to_comptime_int,2224 .single_const_pointer_to_comptime_int,
2228 .enum_numbered,2225 .enum_numbered,
2226 .vector,
2227 .optional_single_mut_pointer,
2228 .optional_single_const_pointer,
2229 => true,2229 => true,
22302230
2231 .anyopaque,2231 .anyopaque,
...@@ -2267,9 +2267,12 @@ pub const Type = extern union {...@@ -2267,9 +2267,12 @@ pub const Type = extern union {
2267 .mut_slice,2267 .mut_slice,
2268 .enum_simple,2268 .enum_simple,
2269 .error_union,2269 .error_union,
2270 .anyerror_void_error_union,
2270 .anyframe_T,2271 .anyframe_T,
2271 .tuple,2272 .tuple,
2272 .anon_struct,2273 .anon_struct,
2274 .empty_struct_literal,
2275 .empty_struct,
2273 => false,2276 => false,
22742277
2275 .enum_full,2278 .enum_full,
...@@ -2283,36 +2286,12 @@ pub const Type = extern union {...@@ -2283,36 +2286,12 @@ pub const Type = extern union {
22832286
2284 .array,2287 .array,
2285 .array_sentinel,2288 .array_sentinel,
2286 .vector,
2287 => ty.childType().hasWellDefinedLayout(),2289 => ty.childType().hasWellDefinedLayout(),
22882290
2289 .optional,2291 .optional => ty.isPtrLikeOptional(),
2290 .optional_single_mut_pointer,2292 .@"struct" => ty.castTag(.@"struct").?.data.layout != .Auto,
2291 .optional_single_const_pointer,2293 .@"union" => ty.castTag(.@"union").?.data.layout != .Auto,
2292 => {2294 .union_tagged => false,
2293 var buf: Type.Payload.ElemType = undefined;
2294 return ty.optionalChild(&buf).hasWellDefinedLayout();
2295 },
2296
2297 .@"struct" => {
2298 const struct_obj = ty.castTag(.@"struct").?.data;
2299 if (struct_obj.layout == .Auto) return false;
2300 switch (struct_obj.has_well_defined_layout) {
2301 .wip, .unknown => unreachable, // This function asserts types already resolved.
2302 .no => return false,
2303 .yes => return true,
2304 }
2305 },
2306
2307 .@"union", .union_tagged => {
2308 const union_obj = ty.cast(Type.Payload.Union).?.data;
2309 if (union_obj.layout == .Auto) return false;
2310 switch (union_obj.has_well_defined_layout) {
2311 .wip, .unknown => unreachable, // This function asserts types already resolved.
2312 .no => return false,
2313 .yes => return true,
2314 }
2315 },
2316 };2295 };
2317 }2296 }
23182297
...@@ -3299,13 +3278,12 @@ pub const Type = extern union {...@@ -3299,13 +3278,12 @@ pub const Type = extern union {
3299 => return true,3278 => return true,
33003279
3301 .optional => {3280 .optional => {
3302 var buf: Payload.ElemType = undefined;3281 const child_ty = self.castTag(.optional).?.data;
3303 const child_type = self.optionalChild(&buf);
3304 // optionals of zero sized types behave like bools, not pointers3282 // optionals of zero sized types behave like bools, not pointers
3305 if (!child_type.hasRuntimeBits()) return false;3283 if (!child_ty.hasRuntimeBits()) return false;
3306 if (child_type.zigTypeTag() != .Pointer) return false;3284 if (child_ty.zigTypeTag() != .Pointer) return false;
33073285
3308 const info = child_type.ptrInfo().data;3286 const info = child_ty.ptrInfo().data;
3309 switch (info.size) {3287 switch (info.size) {
3310 .Slice, .C => return false,3288 .Slice, .C => return false,
3311 .Many, .One => return !info.@"allowzero",3289 .Many, .One => return !info.@"allowzero",
...@@ -5496,6 +5474,7 @@ pub const Type = extern union {...@@ -5496,6 +5474,7 @@ pub const Type = extern union {
5496 pub const @"type" = initTag(.type);5474 pub const @"type" = initTag(.type);
5497 pub const @"anyerror" = initTag(.anyerror);5475 pub const @"anyerror" = initTag(.anyerror);
5498 pub const @"anyopaque" = initTag(.anyopaque);5476 pub const @"anyopaque" = initTag(.anyopaque);
5477 pub const @"null" = initTag(.@"null");
54995478
5500 pub fn ptr(arena: Allocator, target: Target, data: Payload.Pointer.Data) !Type {5479 pub fn ptr(arena: Allocator, target: Target, data: Payload.Pointer.Data) !Type {
5501 var d = data;5480 var d = data;
src/value.zig+2-2
...@@ -2417,7 +2417,7 @@ pub const Value = extern union {...@@ -2417,7 +2417,7 @@ pub const Value = extern union {
2417 return switch (val.tag()) {2417 return switch (val.tag()) {
2418 .empty_array_sentinel => if (start == 0 and end == 1) val else Value.initTag(.empty_array),2418 .empty_array_sentinel => if (start == 0 and end == 1) val else Value.initTag(.empty_array),
2419 .bytes => Tag.bytes.create(arena, val.castTag(.bytes).?.data[start..end]),2419 .bytes => Tag.bytes.create(arena, val.castTag(.bytes).?.data[start..end]),
2420 .array => Tag.array.create(arena, val.castTag(.array).?.data[start..end]),2420 .aggregate => Tag.aggregate.create(arena, val.castTag(.aggregate).?.data[start..end]),
2421 .slice => sliceArray(val.castTag(.slice).?.data.ptr, arena, start, end),2421 .slice => sliceArray(val.castTag(.slice).?.data.ptr, arena, start, end),
24222422
2423 .decl_ref => sliceArray(val.castTag(.decl_ref).?.data.val, arena, start, end),2423 .decl_ref => sliceArray(val.castTag(.decl_ref).?.data.val, arena, start, end),
...@@ -2466,7 +2466,7 @@ pub const Value = extern union {...@@ -2466,7 +2466,7 @@ pub const Value = extern union {
2466 pub fn elemPtr(val: Value, ty: Type, arena: Allocator, index: usize) Allocator.Error!Value {2466 pub fn elemPtr(val: Value, ty: Type, arena: Allocator, index: usize) Allocator.Error!Value {
2467 const elem_ty = ty.elemType2();2467 const elem_ty = ty.elemType2();
2468 const ptr_val = switch (val.tag()) {2468 const ptr_val = switch (val.tag()) {
2469 .slice => val.slicePtr(),2469 .slice => val.castTag(.slice).?.data.ptr,
2470 else => val,2470 else => val,
2471 };2471 };
24722472
test/behavior/bugs/11139.zig+3-3
...@@ -3,9 +3,9 @@ const builtin = @import("builtin");...@@ -3,9 +3,9 @@ const builtin = @import("builtin");
3const expect = std.testing.expect;3const expect = std.testing.expect;
44
5test "store array of array of structs at comptime" {5test "store array of array of structs at comptime" {
6 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;6 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
99
10 try expect(storeArrayOfArrayOfStructs() == 15);10 try expect(storeArrayOfArrayOfStructs() == 15);
11 comptime try expect(storeArrayOfArrayOfStructs() == 15);11 comptime try expect(storeArrayOfArrayOfStructs() == 15);
test/behavior/cast.zig+4-4
...@@ -871,7 +871,7 @@ test "peer cast [N:x]T to [N]T" {...@@ -871,7 +871,7 @@ test "peer cast [N:x]T to [N]T" {
871}871}
872872
873test "peer cast *[N:x]T to *[N]T" {873test "peer cast *[N:x]T to *[N]T" {
874 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;874 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
875 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO875 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
876 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO876 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
877877
...@@ -887,9 +887,9 @@ test "peer cast *[N:x]T to *[N]T" {...@@ -887,9 +887,9 @@ test "peer cast *[N:x]T to *[N]T" {
887}887}
888888
889test "peer cast [*:x]T to [*]T" {889test "peer cast [*:x]T to [*]T" {
890 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;890 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
891 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;891 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
892 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;892 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
893893
894 const S = struct {894 const S = struct {
895 fn doTheTest() !void {895 fn doTheTest() !void {
test/behavior/ptrcast.zig+16-16
...@@ -23,9 +23,9 @@ fn testReinterpretBytesAsInteger() !void {...@@ -23,9 +23,9 @@ fn testReinterpretBytesAsInteger() !void {
2323
24test "reinterpret an array over multiple elements, with no well-defined layout" {24test "reinterpret an array over multiple elements, with no well-defined layout" {
25 if (builtin.zig_backend == .stage1) return error.SkipZigTest;25 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
26 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;26 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
27 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;27 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2929
30 try testReinterpretWithOffsetAndNoWellDefinedLayout();30 try testReinterpretWithOffsetAndNoWellDefinedLayout();
31 comptime try testReinterpretWithOffsetAndNoWellDefinedLayout();31 comptime try testReinterpretWithOffsetAndNoWellDefinedLayout();
...@@ -40,9 +40,9 @@ fn testReinterpretWithOffsetAndNoWellDefinedLayout() !void {...@@ -40,9 +40,9 @@ fn testReinterpretWithOffsetAndNoWellDefinedLayout() !void {
40}40}
4141
42test "reinterpret bytes inside auto-layout struct as integer with nonzero offset" {42test "reinterpret bytes inside auto-layout struct as integer with nonzero offset" {
43 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;43 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
44 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;44 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
45 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;45 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4646
47 try testReinterpretStructWrappedBytesAsInteger();47 try testReinterpretStructWrappedBytesAsInteger();
48 comptime try testReinterpretStructWrappedBytesAsInteger();48 comptime try testReinterpretStructWrappedBytesAsInteger();
...@@ -59,9 +59,9 @@ fn testReinterpretStructWrappedBytesAsInteger() !void {...@@ -59,9 +59,9 @@ fn testReinterpretStructWrappedBytesAsInteger() !void {
59}59}
6060
61test "reinterpret bytes of an array into an extern struct" {61test "reinterpret bytes of an array into an extern struct" {
62 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;62 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
63 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;63 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
64 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;64 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
6565
66 try testReinterpretBytesAsExternStruct();66 try testReinterpretBytesAsExternStruct();
67 comptime try testReinterpretBytesAsExternStruct();67 comptime try testReinterpretBytesAsExternStruct();
...@@ -83,8 +83,8 @@ fn testReinterpretBytesAsExternStruct() !void {...@@ -83,8 +83,8 @@ fn testReinterpretBytesAsExternStruct() !void {
8383
84test "reinterpret bytes of an extern struct into another" {84test "reinterpret bytes of an extern struct into another" {
85 if (builtin.zig_backend == .stage1) return error.SkipZigTest;85 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
86 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;86 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;87 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
8888
89 try testReinterpretExternStructAsExternStruct();89 try testReinterpretExternStructAsExternStruct();
90 comptime try testReinterpretExternStructAsExternStruct();90 comptime try testReinterpretExternStructAsExternStruct();
...@@ -109,11 +109,11 @@ fn testReinterpretExternStructAsExternStruct() !void {...@@ -109,11 +109,11 @@ fn testReinterpretExternStructAsExternStruct() !void {
109109
110test "lower reinterpreted comptime field ptr" {110test "lower reinterpreted comptime field ptr" {
111 if (builtin.zig_backend == .stage1) return error.SkipZigTest;111 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
112 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;112 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
114 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;114 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
115 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;115 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
116 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;116 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
117117
118 // Test lowering a field ptr118 // Test lowering a field ptr
119 comptime var bytes align(2) = [_]u8{ 1, 2, 3, 4, 5, 6 };119 comptime var bytes align(2) = [_]u8{ 1, 2, 3, 4, 5, 6 };