| ... | ... | @@ -1579,8 +1579,6 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 1579 | 1579 | const target = sema.mod.getTarget(); |
| 1580 | 1580 | const addr_space = target_util.defaultAddressSpace(target, .local); |
| 1581 | 1581 | |
| 1582 | | try sema.resolveTypeLayout(block, src, pointee_ty); |
| 1583 | | |
| 1584 | 1582 | if (Air.refToIndex(ptr)) |ptr_inst| { |
| 1585 | 1583 | if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) { |
| 1586 | 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 | 1615 | try pointee_ty.copy(anon_decl.arena()), |
| 1618 | 1616 | Value.undef, |
| 1619 | 1617 | ); |
| 1618 | if (iac.data.alignment != 0) { |
| 1619 | try sema.resolveTypeLayout(block, src, pointee_ty); |
| 1620 | } |
| 1620 | 1621 | const ptr_ty = try Type.ptr(sema.arena, target, .{ |
| 1621 | 1622 | .pointee_type = pointee_ty, |
| 1622 | 1623 | .@"align" = iac.data.alignment, |
| ... | ... | @@ -1886,7 +1887,7 @@ fn zirEnumDecl( |
| 1886 | 1887 | |
| 1887 | 1888 | enum_obj.* = .{ |
| 1888 | 1889 | .owner_decl = new_decl, |
| 1889 | | .tag_ty = Type.initTag(.@"null"), |
| 1890 | .tag_ty = Type.@"null", |
| 1890 | 1891 | .tag_ty_inferred = true, |
| 1891 | 1892 | .fields = .{}, |
| 1892 | 1893 | .values = .{}, |
| ... | ... | @@ -17867,13 +17868,13 @@ const TypedValueAndOffset = struct { |
| 17867 | 17868 | }; |
| 17868 | 17869 | |
| 17869 | 17870 | const 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 | 17872 | /// If a direct dereference is not possible, this is null. |
| 17872 | | target: ?TypedValue, |
| 17873 | | /// The largest parent Value containing `target` and having a well-defined memory layout. |
| 17874 | | /// This is used for bitcasting, if direct dereferencing failed (i.e. `target` is null). |
| 17873 | pointee: ?TypedValue, |
| 17874 | /// The largest parent Value containing `pointee` and having a well-defined memory layout. |
| 17875 | /// This is used for bitcasting, if direct dereferencing failed (i.e. `pointee` is null). |
| 17875 | 17876 | parent: ?TypedValueAndOffset, |
| 17876 | | /// Whether the `target` could be mutated by further |
| 17877 | /// Whether the `pointee` could be mutated by further |
| 17877 | 17878 | /// semantic analysis and a copy must be performed. |
| 17878 | 17879 | is_mutable: bool, |
| 17879 | 17880 | /// If the root decl could not be used as `parent`, this is the type that |
| ... | ... | @@ -17885,7 +17886,7 @@ const ComptimePtrLoadError = CompileError || error{ |
| 17885 | 17886 | RuntimeLoad, |
| 17886 | 17887 | }; |
| 17887 | 17888 | |
| 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 | 17890 | /// .elem_ptr of type T to a value of [N]T, if necessary. |
| 17890 | 17891 | fn beginComptimePtrLoad( |
| 17891 | 17892 | sema: *Sema, |
| ... | ... | @@ -17908,10 +17909,10 @@ fn beginComptimePtrLoad( |
| 17908 | 17909 | const decl_tv = try decl.typedValue(); |
| 17909 | 17910 | if (decl_tv.val.tag() == .variable) return error.RuntimeLoad; |
| 17910 | 17911 | |
| 17911 | | const layout_defined = try sema.typeHasWellDefinedLayout(block, src, decl.ty); |
| 17912 | const layout_defined = decl.ty.hasWellDefinedLayout(); |
| 17912 | 17913 | break :blk ComptimePtrLoadKit{ |
| 17913 | 17914 | .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null, |
| 17914 | | .target = decl_tv, |
| 17915 | .pointee = decl_tv, |
| 17915 | 17916 | .is_mutable = is_mutable, |
| 17916 | 17917 | .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null, |
| 17917 | 17918 | }; |
| ... | ... | @@ -17923,7 +17924,7 @@ fn beginComptimePtrLoad( |
| 17923 | 17924 | var deref = try beginComptimePtrLoad(sema, block, src, elem_ptr.array_ptr, null); |
| 17924 | 17925 | |
| 17925 | 17926 | if (elem_ptr.index != 0) { |
| 17926 | | if (try sema.typeHasWellDefinedLayout(block, src, elem_ty)) { |
| 17927 | if (elem_ty.hasWellDefinedLayout()) { |
| 17927 | 17928 | if (deref.parent) |*parent| { |
| 17928 | 17929 | // Update the byte offset (in-place) |
| 17929 | 17930 | const elem_size = try sema.typeAbiSize(block, src, elem_ty); |
| ... | ... | @@ -17938,17 +17939,17 @@ fn beginComptimePtrLoad( |
| 17938 | 17939 | |
| 17939 | 17940 | // If we're loading an elem_ptr that was derived from a different type |
| 17940 | 17941 | // 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 deref_elem_ty = deref.target.?.ty.childType(); |
| 17942 | const ty_matches = if (deref.pointee != null and deref.pointee.?.ty.isArrayLike()) x: { |
| 17943 | const deref_elem_ty = deref.pointee.?.ty.childType(); |
| 17943 | 17944 | break :x (try sema.coerceInMemoryAllowed(block, deref_elem_ty, elem_ty, false, target, src, src)) == .ok or |
| 17944 | 17945 | (try sema.coerceInMemoryAllowed(block, elem_ty, deref_elem_ty, false, target, src, src)) == .ok; |
| 17945 | 17946 | } else false; |
| 17946 | 17947 | if (!ty_matches) { |
| 17947 | | deref.target = null; |
| 17948 | deref.pointee = null; |
| 17948 | 17949 | break :blk deref; |
| 17949 | 17950 | } |
| 17950 | 17951 | |
| 17951 | | var array_tv = deref.target.?; |
| 17952 | var array_tv = deref.pointee.?; |
| 17952 | 17953 | const check_len = array_tv.ty.arrayLenIncludingSentinel(); |
| 17953 | 17954 | if (elem_ptr.index >= check_len) { |
| 17954 | 17955 | // TODO have the deref include the decl so we can say "declared here" |
| ... | ... | @@ -17959,10 +17960,10 @@ fn beginComptimePtrLoad( |
| 17959 | 17960 | |
| 17960 | 17961 | if (maybe_array_ty) |load_ty| { |
| 17961 | 17962 | // 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 | 17964 | if (load_ty.isArrayLike() and load_ty.childType().eql(elem_ty)) { |
| 17964 | 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 | 17967 | .ty = try Type.array(sema.arena, N, null, elem_ty), |
| 17967 | 17968 | .val = try array_tv.val.sliceArray(sema.arena, elem_ptr.index, elem_ptr.index + N), |
| 17968 | 17969 | } else null; |
| ... | ... | @@ -17970,7 +17971,7 @@ fn beginComptimePtrLoad( |
| 17970 | 17971 | } |
| 17971 | 17972 | } |
| 17972 | 17973 | |
| 17973 | | deref.target = .{ |
| 17974 | deref.pointee = .{ |
| 17974 | 17975 | .ty = elem_ty, |
| 17975 | 17976 | .val = try array_tv.val.elemValue(sema.arena, elem_ptr.index), |
| 17976 | 17977 | }; |
| ... | ... | @@ -17983,7 +17984,7 @@ fn beginComptimePtrLoad( |
| 17983 | 17984 | const field_ty = field_ptr.container_ty.structFieldType(field_index); |
| 17984 | 17985 | var deref = try beginComptimePtrLoad(sema, block, src, field_ptr.container_ptr, field_ptr.container_ty); |
| 17985 | 17986 | |
| 17986 | | if (try sema.typeHasWellDefinedLayout(block, src, field_ptr.container_ty)) { |
| 17987 | if (field_ptr.container_ty.hasWellDefinedLayout()) { |
| 17987 | 17988 | if (deref.parent) |*parent| { |
| 17988 | 17989 | // Update the byte offset (in-place) |
| 17989 | 17990 | try sema.resolveTypeLayout(block, src, field_ptr.container_ty); |
| ... | ... | @@ -17995,19 +17996,19 @@ fn beginComptimePtrLoad( |
| 17995 | 17996 | deref.ty_without_well_defined_layout = field_ptr.container_ty; |
| 17996 | 17997 | } |
| 17997 | 17998 | |
| 17998 | | if (deref.target) |*tv| { |
| 17999 | if (deref.pointee) |*tv| { |
| 17999 | 18000 | const coerce_in_mem_ok = |
| 18000 | 18001 | (try sema.coerceInMemoryAllowed(block, field_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or |
| 18001 | 18002 | (try sema.coerceInMemoryAllowed(block, tv.ty, field_ptr.container_ty, false, target, src, src)) == .ok; |
| 18002 | 18003 | if (coerce_in_mem_ok) { |
| 18003 | | deref.target = TypedValue{ |
| 18004 | deref.pointee = TypedValue{ |
| 18004 | 18005 | .ty = field_ty, |
| 18005 | 18006 | .val = try tv.val.fieldValue(sema.arena, field_index), |
| 18006 | 18007 | }; |
| 18007 | 18008 | break :blk deref; |
| 18008 | 18009 | } |
| 18009 | 18010 | } |
| 18010 | | deref.target = null; |
| 18011 | deref.pointee = null; |
| 18011 | 18012 | break :blk deref; |
| 18012 | 18013 | }, |
| 18013 | 18014 | |
| ... | ... | @@ -18028,7 +18029,7 @@ fn beginComptimePtrLoad( |
| 18028 | 18029 | deref.ty_without_well_defined_layout = payload_ptr.container_ty; |
| 18029 | 18030 | } |
| 18030 | 18031 | |
| 18031 | | if (deref.target) |*tv| { |
| 18032 | if (deref.pointee) |*tv| { |
| 18032 | 18033 | const coerce_in_mem_ok = |
| 18033 | 18034 | (try sema.coerceInMemoryAllowed(block, payload_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or |
| 18034 | 18035 | (try sema.coerceInMemoryAllowed(block, tv.ty, payload_ptr.container_ty, false, target, src, src)) == .ok; |
| ... | ... | @@ -18042,7 +18043,7 @@ fn beginComptimePtrLoad( |
| 18042 | 18043 | break :blk deref; |
| 18043 | 18044 | } |
| 18044 | 18045 | } |
| 18045 | | deref.target = null; |
| 18046 | deref.pointee = null; |
| 18046 | 18047 | break :blk deref; |
| 18047 | 18048 | }, |
| 18048 | 18049 | |
| ... | ... | @@ -18060,7 +18061,7 @@ fn beginComptimePtrLoad( |
| 18060 | 18061 | else => unreachable, |
| 18061 | 18062 | }; |
| 18062 | 18063 | |
| 18063 | | if (deref.target) |tv| { |
| 18064 | if (deref.pointee) |tv| { |
| 18064 | 18065 | if (deref.parent == null and tv.ty.hasWellDefinedLayout()) { |
| 18065 | 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 | 21158 | else => |e| return e, |
| 21158 | 21159 | }; |
| 21159 | 21160 | |
| 21160 | | if (deref.target) |tv| { |
| 21161 | if (deref.pointee) |tv| { |
| 21161 | 21162 | const coerce_in_mem_ok = |
| 21162 | 21163 | (try sema.coerceInMemoryAllowed(block, load_ty, tv.ty, false, target, src, src)) == .ok or |
| 21163 | 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 | 21177 | |
| 21177 | 21178 | // The type is not in-memory coercible or the direct dereference failed, so it must |
| 21178 | 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 | 21181 | return sema.fail(block, src, "comptime dereference requires {} to have a well-defined layout, but it does not.", .{load_ty}); |
| 21181 | 21182 | |
| 21182 | 21183 | const load_sz = try sema.typeAbiSize(block, src, load_ty); |
| 21183 | 21184 | |
| 21184 | 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 | 21187 | return try sema.bitCastVal(block, src, tv.val, tv.ty, load_ty, 0); |
| 21187 | 21188 | |
| 21188 | 21189 | // If that fails, try to bit-cast from the largest parent value with a well-defined layout |
| ... | ... | @@ -21271,182 +21272,6 @@ fn typePtrOrOptionalPtrTy( |
| 21271 | 21272 | } |
| 21272 | 21273 | } |
| 21273 | 21274 | |
| 21274 | | fn 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 | 21275 | /// `generic_poison` will return false. |
| 21451 | 21276 | /// This function returns false negatives when structs and unions are having their |
| 21452 | 21277 | /// field types resolved. |