| ... | @@ -30797,7 +30797,8 @@ const InMemoryCoercionResult = union(enum) { | ... | @@ -30797,7 +30797,8 @@ const InMemoryCoercionResult = union(enum) { |
| 30797 | ptr_addrspace: AddressSpace, | 30797 | ptr_addrspace: AddressSpace, |
| 30798 | ptr_sentinel: Sentinel, | 30798 | ptr_sentinel: Sentinel, |
| 30799 | ptr_size: Size, | 30799 | ptr_size: Size, |
| 30800 | ptr_qualifiers: Qualifiers, | 30800 | ptr_const: Pair, |
| | 30801 | ptr_volatile: Pair, |
| 30801 | ptr_allowzero: Pair, | 30802 | ptr_allowzero: Pair, |
| 30802 | ptr_bit_range: BitRange, | 30803 | ptr_bit_range: BitRange, |
| 30803 | ptr_alignment: AlignPair, | 30804 | ptr_alignment: AlignPair, |
| ... | @@ -30861,13 +30862,6 @@ const InMemoryCoercionResult = union(enum) { | ... | @@ -30861,13 +30862,6 @@ const InMemoryCoercionResult = union(enum) { |
| 30861 | wanted: std.builtin.Type.Pointer.Size, | 30862 | wanted: std.builtin.Type.Pointer.Size, |
| 30862 | }; | 30863 | }; |
| 30863 | | 30864 | |
| 30864 | const Qualifiers = struct { | | |
| 30865 | actual_const: bool, | | |
| 30866 | wanted_const: bool, | | |
| 30867 | actual_volatile: bool, | | |
| 30868 | wanted_volatile: bool, | | |
| 30869 | }; | | |
| 30870 | | | |
| 30871 | const AddressSpace = struct { | 30865 | const AddressSpace = struct { |
| 30872 | actual: std.builtin.AddressSpace, | 30866 | actual: std.builtin.AddressSpace, |
| 30873 | wanted: std.builtin.AddressSpace, | 30867 | wanted: std.builtin.AddressSpace, |
| ... | @@ -31067,16 +31061,6 @@ const InMemoryCoercionResult = union(enum) { | ... | @@ -31067,16 +31061,6 @@ const InMemoryCoercionResult = union(enum) { |
| 31067 | try sema.errNote(src, msg, "a {s} pointer cannot cast into a {s} pointer", .{ pointerSizeString(size.actual), pointerSizeString(size.wanted) }); | 31061 | try sema.errNote(src, msg, "a {s} pointer cannot cast into a {s} pointer", .{ pointerSizeString(size.actual), pointerSizeString(size.wanted) }); |
| 31068 | break; | 31062 | break; |
| 31069 | }, | 31063 | }, |
| 31070 | .ptr_qualifiers => |qualifiers| { | | |
| 31071 | const ok_const = !qualifiers.actual_const or qualifiers.wanted_const; | | |
| 31072 | const ok_volatile = !qualifiers.actual_volatile or qualifiers.wanted_volatile; | | |
| 31073 | if (!ok_const) { | | |
| 31074 | try sema.errNote(src, msg, "cast discards const qualifier", .{}); | | |
| 31075 | } else if (!ok_volatile) { | | |
| 31076 | try sema.errNote(src, msg, "cast discards volatile qualifier", .{}); | | |
| 31077 | } | | |
| 31078 | break; | | |
| 31079 | }, | | |
| 31080 | .ptr_allowzero => |pair| { | 31064 | .ptr_allowzero => |pair| { |
| 31081 | const wanted_allow_zero = pair.wanted.ptrAllowsZero(pt.zcu); | 31065 | const wanted_allow_zero = pair.wanted.ptrAllowsZero(pt.zcu); |
| 31082 | const actual_allow_zero = pair.actual.ptrAllowsZero(pt.zcu); | 31066 | const actual_allow_zero = pair.actual.ptrAllowsZero(pt.zcu); |
| ... | @@ -31085,8 +31069,32 @@ const InMemoryCoercionResult = union(enum) { | ... | @@ -31085,8 +31069,32 @@ const InMemoryCoercionResult = union(enum) { |
| 31085 | pair.actual.fmt(pt), pair.wanted.fmt(pt), | 31069 | pair.actual.fmt(pt), pair.wanted.fmt(pt), |
| 31086 | }); | 31070 | }); |
| 31087 | } else { | 31071 | } else { |
| 31088 | try sema.errNote(src, msg, "mutable '{}' allows illegal null values stored to type '{}'", .{ | 31072 | try sema.errNote(src, msg, "mutable '{}' would allow illegal null values stored to type '{}'", .{ |
| 31089 | pair.actual.fmt(pt), pair.wanted.fmt(pt), | 31073 | pair.wanted.fmt(pt), pair.actual.fmt(pt), |
| | 31074 | }); |
| | 31075 | } |
| | 31076 | break; |
| | 31077 | }, |
| | 31078 | .ptr_const => |pair| { |
| | 31079 | const wanted_const = pair.wanted.isConstPtr(pt.zcu); |
| | 31080 | const actual_const = pair.actual.isConstPtr(pt.zcu); |
| | 31081 | if (actual_const and !wanted_const) { |
| | 31082 | try sema.errNote(src, msg, "cast discards const qualifier", .{}); |
| | 31083 | } else { |
| | 31084 | try sema.errNote(src, msg, "mutable '{}' would allow illegal const pointers stored to type '{}'", .{ |
| | 31085 | pair.wanted.fmt(pt), pair.actual.fmt(pt), |
| | 31086 | }); |
| | 31087 | } |
| | 31088 | break; |
| | 31089 | }, |
| | 31090 | .ptr_volatile => |pair| { |
| | 31091 | const wanted_volatile = pair.wanted.isVolatilePtr(pt.zcu); |
| | 31092 | const actual_volatile = pair.actual.isVolatilePtr(pt.zcu); |
| | 31093 | if (actual_volatile and !wanted_volatile) { |
| | 31094 | try sema.errNote(src, msg, "cast discards volatile qualifier", .{}); |
| | 31095 | } else { |
| | 31096 | try sema.errNote(src, msg, "mutable '{}' would allow illegal volatile pointers stored to type '{}'", .{ |
| | 31097 | pair.wanted.fmt(pt), pair.actual.fmt(pt), |
| 31090 | }); | 31098 | }); |
| 31091 | } | 31099 | } |
| 31092 | break; | 31100 | break; |
| ... | @@ -31136,20 +31144,22 @@ fn pointerSizeString(size: std.builtin.Type.Pointer.Size) []const u8 { | ... | @@ -31136,20 +31144,22 @@ fn pointerSizeString(size: std.builtin.Type.Pointer.Size) []const u8 { |
| 31136 | }; | 31144 | }; |
| 31137 | } | 31145 | } |
| 31138 | | 31146 | |
| 31139 | /// If pointers have the same representation in runtime memory, a bitcast AIR instruction | 31147 | /// If types `A` and `B` have identical representations in runtime memory, they are considered |
| 31140 | /// may be used for the coercion. | 31148 | /// "in-memory coercible". This is a subset of normal coercions. Not only can `A` coerce to `B`, but |
| 31141 | /// * `const` attribute can be gained | 31149 | /// also, coercions can happen through pointers. For instance, `*const A` can coerce to `*const B`. |
| 31142 | /// * `volatile` attribute can be gained | 31150 | /// |
| 31143 | /// * `allowzero` attribute can be gained (whether from explicit attribute, C pointer, or optional pointer) but only if !dest_is_mut | 31151 | /// If this function is called, the coercion must be applied, or a compile error emitted if `.ok` |
| 31144 | /// * alignment can be decreased | 31152 | /// is not returned. This is because this function may modify inferred error sets to make a |
| 31145 | /// * bit offset attributes must match exactly | 31153 | /// coercion possible, even if `.ok` is not returned. |
| 31146 | /// * `*`/`[*]` must match exactly, but `[*c]` matches either one | | |
| 31147 | /// * sentinel-terminated pointers can coerce into `[*]` | | |
| 31148 | pub fn coerceInMemoryAllowed( | 31154 | pub fn coerceInMemoryAllowed( |
| 31149 | sema: *Sema, | 31155 | sema: *Sema, |
| 31150 | block: *Block, | 31156 | block: *Block, |
| 31151 | dest_ty: Type, | 31157 | dest_ty: Type, |
| 31152 | src_ty: Type, | 31158 | src_ty: Type, |
| | 31159 | /// If `true`, this query comes from an attempted coercion of the form `*Src` -> `*Dest`, where |
| | 31160 | /// both pointers are mutable. If this coercion is allowed, one could store to the `*Dest` and |
| | 31161 | /// load from the `*Src` to effectively perform an in-memory coercion from `Dest` to `Src`. |
| | 31162 | /// Therefore, when `dest_is_mut`, the in-memory coercion must be valid in *both directions*. |
| 31153 | dest_is_mut: bool, | 31163 | dest_is_mut: bool, |
| 31154 | target: std.Target, | 31164 | target: std.Target, |
| 31155 | dest_src: LazySrcLoc, | 31165 | dest_src: LazySrcLoc, |
| ... | @@ -31224,7 +31234,7 @@ pub fn coerceInMemoryAllowed( | ... | @@ -31224,7 +31234,7 @@ pub fn coerceInMemoryAllowed( |
| 31224 | | 31234 | |
| 31225 | // Functions | 31235 | // Functions |
| 31226 | if (dest_tag == .@"fn" and src_tag == .@"fn") { | 31236 | if (dest_tag == .@"fn" and src_tag == .@"fn") { |
| 31227 | return try sema.coerceInMemoryAllowedFns(block, dest_ty, src_ty, target, dest_src, src_src); | 31237 | return try sema.coerceInMemoryAllowedFns(block, dest_ty, src_ty, dest_is_mut, target, dest_src, src_src); |
| 31228 | } | 31238 | } |
| 31229 | | 31239 | |
| 31230 | // Error Unions | 31240 | // Error Unions |
| ... | @@ -31233,7 +31243,7 @@ pub fn coerceInMemoryAllowed( | ... | @@ -31233,7 +31243,7 @@ pub fn coerceInMemoryAllowed( |
| 31233 | const src_payload = src_ty.errorUnionPayload(zcu); | 31243 | const src_payload = src_ty.errorUnionPayload(zcu); |
| 31234 | const child = try sema.coerceInMemoryAllowed(block, dest_payload, src_payload, dest_is_mut, target, dest_src, src_src, null); | 31244 | const child = try sema.coerceInMemoryAllowed(block, dest_payload, src_payload, dest_is_mut, target, dest_src, src_src, null); |
| 31235 | if (child != .ok) { | 31245 | if (child != .ok) { |
| 31236 | return InMemoryCoercionResult{ .error_union_payload = .{ | 31246 | return .{ .error_union_payload = .{ |
| 31237 | .child = try child.dupe(sema.arena), | 31247 | .child = try child.dupe(sema.arena), |
| 31238 | .actual = src_payload, | 31248 | .actual = src_payload, |
| 31239 | .wanted = dest_payload, | 31249 | .wanted = dest_payload, |
| ... | @@ -31244,7 +31254,11 @@ pub fn coerceInMemoryAllowed( | ... | @@ -31244,7 +31254,11 @@ pub fn coerceInMemoryAllowed( |
| 31244 | | 31254 | |
| 31245 | // Error Sets | 31255 | // Error Sets |
| 31246 | if (dest_tag == .error_set and src_tag == .error_set) { | 31256 | if (dest_tag == .error_set and src_tag == .error_set) { |
| 31247 | return try sema.coerceInMemoryAllowedErrorSets(block, dest_ty, src_ty, dest_src, src_src); | 31257 | const res1 = try sema.coerceInMemoryAllowedErrorSets(block, dest_ty, src_ty, dest_src, src_src); |
| | 31258 | if (!dest_is_mut or res1 != .ok) return res1; |
| | 31259 | // src -> dest is okay, but `dest_is_mut`, so it needs to be allowed in the other direction. |
| | 31260 | const res2 = try sema.coerceInMemoryAllowedErrorSets(block, src_ty, dest_ty, src_src, dest_src); |
| | 31261 | return res2; |
| 31248 | } | 31262 | } |
| 31249 | | 31263 | |
| 31250 | // Arrays | 31264 | // Arrays |
| ... | @@ -31252,7 +31266,7 @@ pub fn coerceInMemoryAllowed( | ... | @@ -31252,7 +31266,7 @@ pub fn coerceInMemoryAllowed( |
| 31252 | const dest_info = dest_ty.arrayInfo(zcu); | 31266 | const dest_info = dest_ty.arrayInfo(zcu); |
| 31253 | const src_info = src_ty.arrayInfo(zcu); | 31267 | const src_info = src_ty.arrayInfo(zcu); |
| 31254 | if (dest_info.len != src_info.len) { | 31268 | if (dest_info.len != src_info.len) { |
| 31255 | return InMemoryCoercionResult{ .array_len = .{ | 31269 | return .{ .array_len = .{ |
| 31256 | .actual = src_info.len, | 31270 | .actual = src_info.len, |
| 31257 | .wanted = dest_info.len, | 31271 | .wanted = dest_info.len, |
| 31258 | } }; | 31272 | } }; |
| ... | @@ -31263,7 +31277,7 @@ pub fn coerceInMemoryAllowed( | ... | @@ -31263,7 +31277,7 @@ pub fn coerceInMemoryAllowed( |
| 31263 | .ok => {}, | 31277 | .ok => {}, |
| 31264 | .no_match => return child, | 31278 | .no_match => return child, |
| 31265 | else => { | 31279 | else => { |
| 31266 | return InMemoryCoercionResult{ .array_elem = .{ | 31280 | return .{ .array_elem = .{ |
| 31267 | .child = try child.dupe(sema.arena), | 31281 | .child = try child.dupe(sema.arena), |
| 31268 | .actual = src_info.elem_type, | 31282 | .actual = src_info.elem_type, |
| 31269 | .wanted = dest_info.elem_type, | 31283 | .wanted = dest_info.elem_type, |
| ... | @@ -31279,7 +31293,7 @@ pub fn coerceInMemoryAllowed( | ... | @@ -31279,7 +31293,7 @@ pub fn coerceInMemoryAllowed( |
| 31279 | zcu, | 31293 | zcu, |
| 31280 | )); | 31294 | )); |
| 31281 | if (!ok_sent) { | 31295 | if (!ok_sent) { |
| 31282 | return InMemoryCoercionResult{ .array_sentinel = .{ | 31296 | return .{ .array_sentinel = .{ |
| 31283 | .actual = src_info.sentinel orelse Value.@"unreachable", | 31297 | .actual = src_info.sentinel orelse Value.@"unreachable", |
| 31284 | .wanted = dest_info.sentinel orelse Value.@"unreachable", | 31298 | .wanted = dest_info.sentinel orelse Value.@"unreachable", |
| 31285 | .ty = dest_info.elem_type, | 31299 | .ty = dest_info.elem_type, |
| ... | @@ -31293,7 +31307,7 @@ pub fn coerceInMemoryAllowed( | ... | @@ -31293,7 +31307,7 @@ pub fn coerceInMemoryAllowed( |
| 31293 | const dest_len = dest_ty.vectorLen(zcu); | 31307 | const dest_len = dest_ty.vectorLen(zcu); |
| 31294 | const src_len = src_ty.vectorLen(zcu); | 31308 | const src_len = src_ty.vectorLen(zcu); |
| 31295 | if (dest_len != src_len) { | 31309 | if (dest_len != src_len) { |
| 31296 | return InMemoryCoercionResult{ .vector_len = .{ | 31310 | return .{ .vector_len = .{ |
| 31297 | .actual = src_len, | 31311 | .actual = src_len, |
| 31298 | .wanted = dest_len, | 31312 | .wanted = dest_len, |
| 31299 | } }; | 31313 | } }; |
| ... | @@ -31303,7 +31317,7 @@ pub fn coerceInMemoryAllowed( | ... | @@ -31303,7 +31317,7 @@ pub fn coerceInMemoryAllowed( |
| 31303 | const src_elem_ty = src_ty.scalarType(zcu); | 31317 | const src_elem_ty = src_ty.scalarType(zcu); |
| 31304 | const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src, null); | 31318 | const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src, null); |
| 31305 | if (child != .ok) { | 31319 | if (child != .ok) { |
| 31306 | return InMemoryCoercionResult{ .vector_elem = .{ | 31320 | return .{ .vector_elem = .{ |
| 31307 | .child = try child.dupe(sema.arena), | 31321 | .child = try child.dupe(sema.arena), |
| 31308 | .actual = src_elem_ty, | 31322 | .actual = src_elem_ty, |
| 31309 | .wanted = dest_elem_ty, | 31323 | .wanted = dest_elem_ty, |
| ... | @@ -31320,7 +31334,7 @@ pub fn coerceInMemoryAllowed( | ... | @@ -31320,7 +31334,7 @@ pub fn coerceInMemoryAllowed( |
| 31320 | const dest_len = dest_ty.arrayLen(zcu); | 31334 | const dest_len = dest_ty.arrayLen(zcu); |
| 31321 | const src_len = src_ty.arrayLen(zcu); | 31335 | const src_len = src_ty.arrayLen(zcu); |
| 31322 | if (dest_len != src_len) { | 31336 | if (dest_len != src_len) { |
| 31323 | return InMemoryCoercionResult{ .array_len = .{ | 31337 | return .{ .array_len = .{ |
| 31324 | .actual = src_len, | 31338 | .actual = src_len, |
| 31325 | .wanted = dest_len, | 31339 | .wanted = dest_len, |
| 31326 | } }; | 31340 | } }; |
| ... | @@ -31330,7 +31344,7 @@ pub fn coerceInMemoryAllowed( | ... | @@ -31330,7 +31344,7 @@ pub fn coerceInMemoryAllowed( |
| 31330 | const src_elem_ty = src_ty.childType(zcu); | 31344 | const src_elem_ty = src_ty.childType(zcu); |
| 31331 | const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src, null); | 31345 | const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src, null); |
| 31332 | if (child != .ok) { | 31346 | if (child != .ok) { |
| 31333 | return InMemoryCoercionResult{ .array_elem = .{ | 31347 | return .{ .array_elem = .{ |
| 31334 | .child = try child.dupe(sema.arena), | 31348 | .child = try child.dupe(sema.arena), |
| 31335 | .actual = src_elem_ty, | 31349 | .actual = src_elem_ty, |
| 31336 | .wanted = dest_elem_ty, | 31350 | .wanted = dest_elem_ty, |
| ... | @@ -31340,7 +31354,7 @@ pub fn coerceInMemoryAllowed( | ... | @@ -31340,7 +31354,7 @@ pub fn coerceInMemoryAllowed( |
| 31340 | if (dest_tag == .array) { | 31354 | if (dest_tag == .array) { |
| 31341 | const dest_info = dest_ty.arrayInfo(zcu); | 31355 | const dest_info = dest_ty.arrayInfo(zcu); |
| 31342 | if (dest_info.sentinel != null) { | 31356 | if (dest_info.sentinel != null) { |
| 31343 | return InMemoryCoercionResult{ .array_sentinel = .{ | 31357 | return .{ .array_sentinel = .{ |
| 31344 | .actual = Value.@"unreachable", | 31358 | .actual = Value.@"unreachable", |
| 31345 | .wanted = dest_info.sentinel.?, | 31359 | .wanted = dest_info.sentinel.?, |
| 31346 | .ty = dest_info.elem_type, | 31360 | .ty = dest_info.elem_type, |
| ... | @@ -31360,7 +31374,7 @@ pub fn coerceInMemoryAllowed( | ... | @@ -31360,7 +31374,7 @@ pub fn coerceInMemoryAllowed( |
| 31360 | // Optionals | 31374 | // Optionals |
| 31361 | if (dest_tag == .optional and src_tag == .optional) { | 31375 | if (dest_tag == .optional and src_tag == .optional) { |
| 31362 | if ((maybe_dest_ptr_ty != null) != (maybe_src_ptr_ty != null)) { | 31376 | if ((maybe_dest_ptr_ty != null) != (maybe_src_ptr_ty != null)) { |
| 31363 | return InMemoryCoercionResult{ .optional_shape = .{ | 31377 | return .{ .optional_shape = .{ |
| 31364 | .actual = src_ty, | 31378 | .actual = src_ty, |
| 31365 | .wanted = dest_ty, | 31379 | .wanted = dest_ty, |
| 31366 | } }; | 31380 | } }; |
| ... | @@ -31370,7 +31384,7 @@ pub fn coerceInMemoryAllowed( | ... | @@ -31370,7 +31384,7 @@ pub fn coerceInMemoryAllowed( |
| 31370 | | 31384 | |
| 31371 | const child = try sema.coerceInMemoryAllowed(block, dest_child_type, src_child_type, dest_is_mut, target, dest_src, src_src, null); | 31385 | const child = try sema.coerceInMemoryAllowed(block, dest_child_type, src_child_type, dest_is_mut, target, dest_src, src_src, null); |
| 31372 | if (child != .ok) { | 31386 | if (child != .ok) { |
| 31373 | return InMemoryCoercionResult{ .optional_child = .{ | 31387 | return .{ .optional_child = .{ |
| 31374 | .child = try child.dupe(sema.arena), | 31388 | .child = try child.dupe(sema.arena), |
| 31375 | .actual = src_child_type, | 31389 | .actual = src_child_type, |
| 31376 | .wanted = dest_child_type, | 31390 | .wanted = dest_child_type, |
| ... | @@ -31382,7 +31396,6 @@ pub fn coerceInMemoryAllowed( | ... | @@ -31382,7 +31396,6 @@ pub fn coerceInMemoryAllowed( |
| 31382 | | 31396 | |
| 31383 | // Tuples (with in-memory-coercible fields) | 31397 | // Tuples (with in-memory-coercible fields) |
| 31384 | if (dest_ty.isTuple(zcu) and src_ty.isTuple(zcu)) tuple: { | 31398 | if (dest_ty.isTuple(zcu) and src_ty.isTuple(zcu)) tuple: { |
| 31385 | if (dest_ty.containerLayout(zcu) != src_ty.containerLayout(zcu)) break :tuple; | | |
| 31386 | if (dest_ty.structFieldCount(zcu) != src_ty.structFieldCount(zcu)) break :tuple; | 31399 | if (dest_ty.structFieldCount(zcu) != src_ty.structFieldCount(zcu)) break :tuple; |
| 31387 | const field_count = dest_ty.structFieldCount(zcu); | 31400 | const field_count = dest_ty.structFieldCount(zcu); |
| 31388 | for (0..field_count) |field_idx| { | 31401 | for (0..field_count) |field_idx| { |
| ... | @@ -31396,7 +31409,7 @@ pub fn coerceInMemoryAllowed( | ... | @@ -31396,7 +31409,7 @@ pub fn coerceInMemoryAllowed( |
| 31396 | return .ok; | 31409 | return .ok; |
| 31397 | } | 31410 | } |
| 31398 | | 31411 | |
| 31399 | return InMemoryCoercionResult{ .no_match = .{ | 31412 | return .{ .no_match = .{ |
| 31400 | .actual = dest_ty, | 31413 | .actual = dest_ty, |
| 31401 | .wanted = src_ty, | 31414 | .wanted = src_ty, |
| 31402 | } }; | 31415 | } }; |
| ... | @@ -31505,6 +31518,8 @@ fn coerceInMemoryAllowedFns( | ... | @@ -31505,6 +31518,8 @@ fn coerceInMemoryAllowedFns( |
| 31505 | block: *Block, | 31518 | block: *Block, |
| 31506 | dest_ty: Type, | 31519 | dest_ty: Type, |
| 31507 | src_ty: Type, | 31520 | src_ty: Type, |
| | 31521 | /// If set, the coercion must be valid in both directions. |
| | 31522 | dest_is_mut: bool, |
| 31508 | target: std.Target, | 31523 | target: std.Target, |
| 31509 | dest_src: LazySrcLoc, | 31524 | dest_src: LazySrcLoc, |
| 31510 | src_src: LazySrcLoc, | 31525 | src_src: LazySrcLoc, |
| ... | @@ -31525,40 +31540,49 @@ fn coerceInMemoryAllowedFns( | ... | @@ -31525,40 +31540,49 @@ fn coerceInMemoryAllowedFns( |
| 31525 | return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic }; | 31540 | return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic }; |
| 31526 | } | 31541 | } |
| 31527 | | 31542 | |
| 31528 | if (!callconvCoerceAllowed(target, src_info.cc, dest_info.cc)) { | 31543 | const callconv_ok = callconvCoerceAllowed(target, src_info.cc, dest_info.cc) and |
| | 31544 | (!dest_is_mut or callconvCoerceAllowed(target, dest_info.cc, src_info.cc)); |
| | 31545 | |
| | 31546 | if (!callconv_ok) { |
| 31529 | return .{ .fn_cc = .{ | 31547 | return .{ .fn_cc = .{ |
| 31530 | .actual = src_info.cc, | 31548 | .actual = src_info.cc, |
| 31531 | .wanted = dest_info.cc, | 31549 | .wanted = dest_info.cc, |
| 31532 | } }; | 31550 | } }; |
| 31533 | } | 31551 | } |
| 31534 | | 31552 | |
| 31535 | switch (src_info.return_type) { | 31553 | if (!switch (src_info.return_type) { |
| 31536 | .noreturn_type, .generic_poison_type => {}, | 31554 | .generic_poison_type => true, |
| 31537 | else => { | 31555 | .noreturn_type => !dest_is_mut, |
| 31538 | const dest_return_type = Type.fromInterned(dest_info.return_type); | 31556 | else => false, |
| 31539 | const src_return_type = Type.fromInterned(src_info.return_type); | 31557 | }) { |
| 31540 | const rt = try sema.coerceInMemoryAllowed(block, dest_return_type, src_return_type, false, target, dest_src, src_src, null); | 31558 | const rt = try sema.coerceInMemoryAllowed( |
| 31541 | if (rt != .ok) { | 31559 | block, |
| 31542 | return InMemoryCoercionResult{ .fn_return_type = .{ | 31560 | .fromInterned(dest_info.return_type), |
| 31543 | .child = try rt.dupe(sema.arena), | 31561 | .fromInterned(src_info.return_type), |
| 31544 | .actual = src_return_type, | 31562 | dest_is_mut, |
| 31545 | .wanted = dest_return_type, | 31563 | target, |
| 31546 | } }; | 31564 | dest_src, |
| 31547 | } | 31565 | src_src, |
| 31548 | }, | 31566 | null, |
| | 31567 | ); |
| | 31568 | if (rt != .ok) return .{ .fn_return_type = .{ |
| | 31569 | .child = try rt.dupe(sema.arena), |
| | 31570 | .actual = .fromInterned(src_info.return_type), |
| | 31571 | .wanted = .fromInterned(dest_info.return_type), |
| | 31572 | } }; |
| 31549 | } | 31573 | } |
| 31550 | } | 31574 | } |
| 31551 | | 31575 | |
| 31552 | const params_len = params_len: { | 31576 | const params_len = params_len: { |
| 31553 | if (dest_info.param_types.len != src_info.param_types.len) { | 31577 | if (dest_info.param_types.len != src_info.param_types.len) { |
| 31554 | return InMemoryCoercionResult{ .fn_param_count = .{ | 31578 | return .{ .fn_param_count = .{ |
| 31555 | .actual = src_info.param_types.len, | 31579 | .actual = src_info.param_types.len, |
| 31556 | .wanted = dest_info.param_types.len, | 31580 | .wanted = dest_info.param_types.len, |
| 31557 | } }; | 31581 | } }; |
| 31558 | } | 31582 | } |
| 31559 | | 31583 | |
| 31560 | if (dest_info.noalias_bits != src_info.noalias_bits) { | 31584 | if (dest_info.noalias_bits != src_info.noalias_bits) { |
| 31561 | return InMemoryCoercionResult{ .fn_param_noalias = .{ | 31585 | return .{ .fn_param_noalias = .{ |
| 31562 | .actual = src_info.noalias_bits, | 31586 | .actual = src_info.noalias_bits, |
| 31563 | .wanted = dest_info.noalias_bits, | 31587 | .wanted = dest_info.noalias_bits, |
| 31564 | } }; | 31588 | } }; |
| ... | @@ -31568,14 +31592,15 @@ fn coerceInMemoryAllowedFns( | ... | @@ -31568,14 +31592,15 @@ fn coerceInMemoryAllowedFns( |
| 31568 | }; | 31592 | }; |
| 31569 | | 31593 | |
| 31570 | for (0..params_len) |param_i| { | 31594 | for (0..params_len) |param_i| { |
| 31571 | const dest_param_ty = Type.fromInterned(dest_info.param_types.get(ip)[param_i]); | 31595 | const dest_param_ty: Type = .fromInterned(dest_info.param_types.get(ip)[param_i]); |
| 31572 | const src_param_ty = Type.fromInterned(src_info.param_types.get(ip)[param_i]); | 31596 | const src_param_ty: Type = .fromInterned(src_info.param_types.get(ip)[param_i]); |
| 31573 | | 31597 | |
| 31574 | const param_i_small: u5 = @intCast(param_i); | 31598 | const src_is_comptime = src_info.paramIsComptime(@intCast(param_i)); |
| 31575 | if (dest_info.paramIsComptime(param_i_small) != src_info.paramIsComptime(param_i_small)) { | 31599 | const dest_is_comptime = dest_info.paramIsComptime(@intCast(param_i)); |
| 31576 | return InMemoryCoercionResult{ .fn_param_comptime = .{ | 31600 | if (src_is_comptime != dest_is_comptime) { |
| | 31601 | return .{ .fn_param_comptime = .{ |
| 31577 | .index = param_i, | 31602 | .index = param_i, |
| 31578 | .wanted = dest_info.paramIsComptime(param_i_small), | 31603 | .wanted = dest_is_comptime, |
| 31579 | } }; | 31604 | } }; |
| 31580 | } | 31605 | } |
| 31581 | | 31606 | |
| ... | @@ -31583,9 +31608,9 @@ fn coerceInMemoryAllowedFns( | ... | @@ -31583,9 +31608,9 @@ fn coerceInMemoryAllowedFns( |
| 31583 | .generic_poison_type => {}, | 31608 | .generic_poison_type => {}, |
| 31584 | else => { | 31609 | else => { |
| 31585 | // Note: Cast direction is reversed here. | 31610 | // Note: Cast direction is reversed here. |
| 31586 | const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, false, target, dest_src, src_src, null); | 31611 | const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, dest_is_mut, target, dest_src, src_src, null); |
| 31587 | if (param != .ok) { | 31612 | if (param != .ok) { |
| 31588 | return InMemoryCoercionResult{ .fn_param = .{ | 31613 | return .{ .fn_param = .{ |
| 31589 | .child = try param.dupe(sema.arena), | 31614 | .child = try param.dupe(sema.arena), |
| 31590 | .actual = src_param_ty, | 31615 | .actual = src_param_ty, |
| 31591 | .wanted = dest_param_ty, | 31616 | .wanted = dest_param_ty, |
| ... | @@ -31644,6 +31669,7 @@ fn coerceInMemoryAllowedPtrs( | ... | @@ -31644,6 +31669,7 @@ fn coerceInMemoryAllowedPtrs( |
| 31644 | src_ty: Type, | 31669 | src_ty: Type, |
| 31645 | dest_ptr_ty: Type, | 31670 | dest_ptr_ty: Type, |
| 31646 | src_ptr_ty: Type, | 31671 | src_ptr_ty: Type, |
| | 31672 | /// If set, the coercion must be valid in both directions. |
| 31647 | dest_is_mut: bool, | 31673 | dest_is_mut: bool, |
| 31648 | target: std.Target, | 31674 | target: std.Target, |
| 31649 | dest_src: LazySrcLoc, | 31675 | dest_src: LazySrcLoc, |
| ... | @@ -31663,21 +31689,34 @@ fn coerceInMemoryAllowedPtrs( | ... | @@ -31663,21 +31689,34 @@ fn coerceInMemoryAllowedPtrs( |
| 31663 | } }; | 31689 | } }; |
| 31664 | } | 31690 | } |
| 31665 | | 31691 | |
| 31666 | const ok_cv_qualifiers = | 31692 | const ok_const = src_info.flags.is_const == dest_info.flags.is_const or |
| 31667 | (!src_info.flags.is_const or dest_info.flags.is_const) and | 31693 | (!dest_is_mut and dest_info.flags.is_const); |
| 31668 | (!src_info.flags.is_volatile or dest_info.flags.is_volatile); | | |
| 31669 | | 31694 | |
| 31670 | if (!ok_cv_qualifiers) { | 31695 | if (!ok_const) return .{ .ptr_const = .{ |
| 31671 | return InMemoryCoercionResult{ .ptr_qualifiers = .{ | 31696 | .actual = src_ty, |
| 31672 | .actual_const = src_info.flags.is_const, | 31697 | .wanted = dest_ty, |
| 31673 | .wanted_const = dest_info.flags.is_const, | 31698 | } }; |
| 31674 | .actual_volatile = src_info.flags.is_volatile, | 31699 | |
| 31675 | .wanted_volatile = dest_info.flags.is_volatile, | 31700 | const ok_volatile = src_info.flags.is_volatile == dest_info.flags.is_volatile or |
| 31676 | } }; | 31701 | (!dest_is_mut and dest_info.flags.is_volatile); |
| 31677 | } | 31702 | |
| | 31703 | if (!ok_volatile) return .{ .ptr_volatile = .{ |
| | 31704 | .actual = src_ty, |
| | 31705 | .wanted = dest_ty, |
| | 31706 | } }; |
| | 31707 | |
| | 31708 | const dest_allowzero = dest_ty.ptrAllowsZero(zcu); |
| | 31709 | const src_allowzero = src_ty.ptrAllowsZero(zcu); |
| | 31710 | const ok_allowzero = src_allowzero == dest_allowzero or |
| | 31711 | (!dest_is_mut and dest_allowzero); |
| | 31712 | |
| | 31713 | if (!ok_allowzero) return .{ .ptr_allowzero = .{ |
| | 31714 | .actual = src_ty, |
| | 31715 | .wanted = dest_ty, |
| | 31716 | } }; |
| 31678 | | 31717 | |
| 31679 | if (dest_info.flags.address_space != src_info.flags.address_space) { | 31718 | if (dest_info.flags.address_space != src_info.flags.address_space) { |
| 31680 | return InMemoryCoercionResult{ .ptr_addrspace = .{ | 31719 | return .{ .ptr_addrspace = .{ |
| 31681 | .actual = src_info.flags.address_space, | 31720 | .actual = src_info.flags.address_space, |
| 31682 | .wanted = dest_info.flags.address_space, | 31721 | .wanted = dest_info.flags.address_space, |
| 31683 | } }; | 31722 | } }; |
| ... | @@ -31685,8 +31724,28 @@ fn coerceInMemoryAllowedPtrs( | ... | @@ -31685,8 +31724,28 @@ fn coerceInMemoryAllowedPtrs( |
| 31685 | | 31724 | |
| 31686 | const dest_child = Type.fromInterned(dest_info.child); | 31725 | const dest_child = Type.fromInterned(dest_info.child); |
| 31687 | const src_child = Type.fromInterned(src_info.child); | 31726 | const src_child = Type.fromInterned(src_info.child); |
| 31688 | const child = try sema.coerceInMemoryAllowed(block, dest_child, src_child, !dest_info.flags.is_const, target, dest_src, src_src, null); | 31727 | const child = try sema.coerceInMemoryAllowed( |
| 31689 | if (child != .ok) allow: { | 31728 | block, |
| | 31729 | dest_child, |
| | 31730 | src_child, |
| | 31731 | // We must also include `dest_is_mut`. |
| | 31732 | // Otherwise, this code is valid: |
| | 31733 | // |
| | 31734 | // const b: B = ...; |
| | 31735 | // var pa: *const A = undefined; |
| | 31736 | // const ppa: **const A = &pa; |
| | 31737 | // const ppb: **const B = ppa; // <-- this is what that allows |
| | 31738 | // ppb.* = &b; |
| | 31739 | // const a: A = pa.*; |
| | 31740 | // |
| | 31741 | // ...effectively performing an in-memory coercion from B to A. |
| | 31742 | dest_is_mut or !dest_info.flags.is_const, |
| | 31743 | target, |
| | 31744 | dest_src, |
| | 31745 | src_src, |
| | 31746 | null, |
| | 31747 | ); |
| | 31748 | if (child != .ok and !dest_is_mut) allow: { |
| 31690 | // As a special case, we also allow coercing `*[n:s]T` to `*[n]T`, akin to dropping the sentinel from a slice. | 31749 | // As a special case, we also allow coercing `*[n:s]T` to `*[n]T`, akin to dropping the sentinel from a slice. |
| 31691 | // `*[n:s]T` cannot coerce in memory to `*[n]T` since they have different sizes. | 31750 | // `*[n:s]T` cannot coerce in memory to `*[n]T` since they have different sizes. |
| 31692 | if (src_child.zigTypeTag(zcu) == .array and dest_child.zigTypeTag(zcu) == .array and | 31751 | if (src_child.zigTypeTag(zcu) == .array and dest_child.zigTypeTag(zcu) == .array and |
| ... | @@ -31695,30 +31754,17 @@ fn coerceInMemoryAllowedPtrs( | ... | @@ -31695,30 +31754,17 @@ fn coerceInMemoryAllowedPtrs( |
| 31695 | { | 31754 | { |
| 31696 | break :allow; | 31755 | break :allow; |
| 31697 | } | 31756 | } |
| 31698 | return InMemoryCoercionResult{ .ptr_child = .{ | 31757 | return .{ .ptr_child = .{ |
| 31699 | .child = try child.dupe(sema.arena), | 31758 | .child = try child.dupe(sema.arena), |
| 31700 | .actual = Type.fromInterned(src_info.child), | 31759 | .actual = .fromInterned(src_info.child), |
| 31701 | .wanted = Type.fromInterned(dest_info.child), | 31760 | .wanted = .fromInterned(dest_info.child), |
| 31702 | } }; | | |
| 31703 | } | | |
| 31704 | | | |
| 31705 | const dest_allow_zero = dest_ty.ptrAllowsZero(zcu); | | |
| 31706 | const src_allow_zero = src_ty.ptrAllowsZero(zcu); | | |
| 31707 | | | |
| 31708 | const ok_allows_zero = (dest_allow_zero and | | |
| 31709 | (src_allow_zero or !dest_is_mut)) or | | |
| 31710 | (!dest_allow_zero and !src_allow_zero); | | |
| 31711 | if (!ok_allows_zero) { | | |
| 31712 | return InMemoryCoercionResult{ .ptr_allowzero = .{ | | |
| 31713 | .actual = src_ty, | | |
| 31714 | .wanted = dest_ty, | | |
| 31715 | } }; | 31761 | } }; |
| 31716 | } | 31762 | } |
| 31717 | | 31763 | |
| 31718 | if (src_info.packed_offset.host_size != dest_info.packed_offset.host_size or | 31764 | if (src_info.packed_offset.host_size != dest_info.packed_offset.host_size or |
| 31719 | src_info.packed_offset.bit_offset != dest_info.packed_offset.bit_offset) | 31765 | src_info.packed_offset.bit_offset != dest_info.packed_offset.bit_offset) |
| 31720 | { | 31766 | { |
| 31721 | return InMemoryCoercionResult{ .ptr_bit_range = .{ | 31767 | return .{ .ptr_bit_range = .{ |
| 31722 | .actual_host = src_info.packed_offset.host_size, | 31768 | .actual_host = src_info.packed_offset.host_size, |
| 31723 | .wanted_host = dest_info.packed_offset.host_size, | 31769 | .wanted_host = dest_info.packed_offset.host_size, |
| 31724 | .actual_offset = src_info.packed_offset.bit_offset, | 31770 | .actual_offset = src_info.packed_offset.bit_offset, |
| ... | @@ -31726,11 +31772,20 @@ fn coerceInMemoryAllowedPtrs( | ... | @@ -31726,11 +31772,20 @@ fn coerceInMemoryAllowedPtrs( |
| 31726 | } }; | 31772 | } }; |
| 31727 | } | 31773 | } |
| 31728 | | 31774 | |
| 31729 | const ok_sent = dest_info.sentinel == .none or src_info.flags.size == .C or | 31775 | const sentinel_ok = ok: { |
| 31730 | (src_info.sentinel != .none and | 31776 | const ss = src_info.sentinel; |
| 31731 | dest_info.sentinel == try zcu.intern_pool.getCoerced(sema.gpa, pt.tid, src_info.sentinel, dest_info.child)); | 31777 | const ds = dest_info.sentinel; |
| 31732 | if (!ok_sent) { | 31778 | if (ss == .none and ds == .none) break :ok true; |
| 31733 | return InMemoryCoercionResult{ .ptr_sentinel = .{ | 31779 | if (ss != .none and ds != .none) { |
| | 31780 | if (ds == try zcu.intern_pool.getCoerced(sema.gpa, pt.tid, ss, dest_info.child)) break :ok true; |
| | 31781 | } |
| | 31782 | if (src_info.flags.size == .C) break :ok true; |
| | 31783 | if (!dest_is_mut and dest_info.sentinel == .none) break :ok true; |
| | 31784 | break :ok false; |
| | 31785 | }; |
| | 31786 | |
| | 31787 | if (!sentinel_ok) { |
| | 31788 | return .{ .ptr_sentinel = .{ |
| 31734 | .actual = switch (src_info.sentinel) { | 31789 | .actual = switch (src_info.sentinel) { |
| 31735 | .none => Value.@"unreachable", | 31790 | .none => Value.@"unreachable", |
| 31736 | else => Value.fromInterned(src_info.sentinel), | 31791 | else => Value.fromInterned(src_info.sentinel), |
| ... | @@ -31760,7 +31815,7 @@ fn coerceInMemoryAllowedPtrs( | ... | @@ -31760,7 +31815,7 @@ fn coerceInMemoryAllowedPtrs( |
| 31760 | else | 31815 | else |
| 31761 | try Type.fromInterned(dest_info.child).abiAlignmentSema(pt); | 31816 | try Type.fromInterned(dest_info.child).abiAlignmentSema(pt); |
| 31762 | | 31817 | |
| 31763 | if (dest_align.compare(.gt, src_align)) { | 31818 | if (dest_align.compare(if (dest_is_mut) .neq else .gt, src_align)) { |
| 31764 | return InMemoryCoercionResult{ .ptr_alignment = .{ | 31819 | return InMemoryCoercionResult{ .ptr_alignment = .{ |
| 31765 | .actual = src_align, | 31820 | .actual = src_align, |
| 31766 | .wanted = dest_align, | 31821 | .wanted = dest_align, |
| ... | @@ -32252,19 +32307,23 @@ fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_resul | ... | @@ -32252,19 +32307,23 @@ fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_resul |
| 32252 | (Type.fromInterned(inst_info.child).arrayLen(zcu) == 0 and dest_info.sentinel == .none and dest_info.flags.size != .C and dest_info.flags.size != .Many))) or | 32307 | (Type.fromInterned(inst_info.child).arrayLen(zcu) == 0 and dest_info.sentinel == .none and dest_info.flags.size != .C and dest_info.flags.size != .Many))) or |
| 32253 | (Type.fromInterned(inst_info.child).isTuple(zcu) and Type.fromInterned(inst_info.child).structFieldCount(zcu) == 0); | 32308 | (Type.fromInterned(inst_info.child).isTuple(zcu) and Type.fromInterned(inst_info.child).structFieldCount(zcu) == 0); |
| 32254 | | 32309 | |
| 32255 | const ok_cv_qualifiers = | 32310 | const ok_const = (!inst_info.flags.is_const or dest_info.flags.is_const) or len0; |
| 32256 | ((!inst_info.flags.is_const or dest_info.flags.is_const) or len0) and | 32311 | const ok_volatile = !inst_info.flags.is_volatile or dest_info.flags.is_volatile; |
| 32257 | (!inst_info.flags.is_volatile or dest_info.flags.is_volatile); | 32312 | if (!ok_const) { |
| 32258 | | 32313 | in_memory_result.* = .{ .ptr_const = .{ |
| 32259 | if (!ok_cv_qualifiers) { | 32314 | .actual = inst_ty, |
| 32260 | in_memory_result.* = .{ .ptr_qualifiers = .{ | 32315 | .wanted = dest_ty, |
| 32261 | .actual_const = inst_info.flags.is_const, | | |
| 32262 | .wanted_const = dest_info.flags.is_const, | | |
| 32263 | .actual_volatile = inst_info.flags.is_volatile, | | |
| 32264 | .wanted_volatile = dest_info.flags.is_volatile, | | |
| 32265 | } }; | 32316 | } }; |
| 32266 | return false; | 32317 | return false; |
| 32267 | } | 32318 | } |
| | 32319 | if (!ok_volatile) { |
| | 32320 | in_memory_result.* = .{ .ptr_volatile = .{ |
| | 32321 | .actual = inst_ty, |
| | 32322 | .wanted = dest_ty, |
| | 32323 | } }; |
| | 32324 | return false; |
| | 32325 | } |
| | 32326 | |
| 32268 | if (dest_info.flags.address_space != inst_info.flags.address_space) { | 32327 | if (dest_info.flags.address_space != inst_info.flags.address_space) { |
| 32269 | in_memory_result.* = .{ .ptr_addrspace = .{ | 32328 | in_memory_result.* = .{ .ptr_addrspace = .{ |
| 32270 | .actual = inst_info.flags.address_space, | 32329 | .actual = inst_info.flags.address_space, |
| ... | @@ -35441,11 +35500,11 @@ fn resolvePeerTypesInner( | ... | @@ -35441,11 +35500,11 @@ fn resolvePeerTypesInner( |
| 35441 | .peer_idx_b = i, | 35500 | .peer_idx_b = i, |
| 35442 | } }; | 35501 | } }; |
| 35443 | // ty -> cur_ty | 35502 | // ty -> cur_ty |
| 35444 | if (.ok == try sema.coerceInMemoryAllowedFns(block, cur_ty, ty, target, src, src)) { | 35503 | if (.ok == try sema.coerceInMemoryAllowedFns(block, cur_ty, ty, false, target, src, src)) { |
| 35445 | continue; | 35504 | continue; |
| 35446 | } | 35505 | } |
| 35447 | // cur_ty -> ty | 35506 | // cur_ty -> ty |
| 35448 | if (.ok == try sema.coerceInMemoryAllowedFns(block, ty, cur_ty, target, src, src)) { | 35507 | if (.ok == try sema.coerceInMemoryAllowedFns(block, ty, cur_ty, false, target, src, src)) { |
| 35449 | opt_cur_ty = ty; | 35508 | opt_cur_ty = ty; |
| 35450 | continue; | 35509 | continue; |
| 35451 | } | 35510 | } |
| ... | @@ -35834,12 +35893,12 @@ fn resolvePairInMemoryCoercible(sema: *Sema, block: *Block, src: LazySrcLoc, ty_ | ... | @@ -35834,12 +35893,12 @@ fn resolvePairInMemoryCoercible(sema: *Sema, block: *Block, src: LazySrcLoc, ty_ |
| 35834 | const target = sema.pt.zcu.getTarget(); | 35893 | const target = sema.pt.zcu.getTarget(); |
| 35835 | | 35894 | |
| 35836 | // ty_b -> ty_a | 35895 | // ty_b -> ty_a |
| 35837 | if (.ok == try sema.coerceInMemoryAllowed(block, ty_a, ty_b, true, target, src, src, null)) { | 35896 | if (.ok == try sema.coerceInMemoryAllowed(block, ty_a, ty_b, false, target, src, src, null)) { |
| 35838 | return ty_a; | 35897 | return ty_a; |
| 35839 | } | 35898 | } |
| 35840 | | 35899 | |
| 35841 | // ty_a -> ty_b | 35900 | // ty_a -> ty_b |
| 35842 | if (.ok == try sema.coerceInMemoryAllowed(block, ty_b, ty_a, true, target, src, src, null)) { | 35901 | if (.ok == try sema.coerceInMemoryAllowed(block, ty_b, ty_a, false, target, src, src, null)) { |
| 35843 | return ty_b; | 35902 | return ty_b; |
| 35844 | } | 35903 | } |
| 35845 | | 35904 | |