| ... | ... | @@ -30797,7 +30797,8 @@ const InMemoryCoercionResult = union(enum) { |
| 30797 | 30797 | ptr_addrspace: AddressSpace, |
| 30798 | 30798 | ptr_sentinel: Sentinel, |
| 30799 | 30799 | ptr_size: Size, |
| 30800 | | ptr_qualifiers: Qualifiers, |
| 30800 | ptr_const: Pair, |
| 30801 | ptr_volatile: Pair, |
| 30801 | 30802 | ptr_allowzero: Pair, |
| 30802 | 30803 | ptr_bit_range: BitRange, |
| 30803 | 30804 | ptr_alignment: AlignPair, |
| ... | ... | @@ -30861,13 +30862,6 @@ const InMemoryCoercionResult = union(enum) { |
| 30861 | 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 | 30865 | const AddressSpace = struct { |
| 30872 | 30866 | actual: std.builtin.AddressSpace, |
| 30873 | 30867 | wanted: std.builtin.AddressSpace, |
| ... | ... | @@ -31067,16 +31061,6 @@ const InMemoryCoercionResult = union(enum) { |
| 31067 | 31061 | try sema.errNote(src, msg, "a {s} pointer cannot cast into a {s} pointer", .{ pointerSizeString(size.actual), pointerSizeString(size.wanted) }); |
| 31068 | 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 | 31064 | .ptr_allowzero => |pair| { |
| 31081 | 31065 | const wanted_allow_zero = pair.wanted.ptrAllowsZero(pt.zcu); |
| 31082 | 31066 | const actual_allow_zero = pair.actual.ptrAllowsZero(pt.zcu); |
| ... | ... | @@ -31085,8 +31069,32 @@ const InMemoryCoercionResult = union(enum) { |
| 31085 | 31069 | pair.actual.fmt(pt), pair.wanted.fmt(pt), |
| 31086 | 31070 | }); |
| 31087 | 31071 | } else { |
| 31088 | | try sema.errNote(src, msg, "mutable '{}' allows illegal null values stored to type '{}'", .{ |
| 31089 | | pair.actual.fmt(pt), pair.wanted.fmt(pt), |
| 31072 | try sema.errNote(src, msg, "mutable '{}' would allow illegal null values stored to type '{}'", .{ |
| 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 | 31100 | break; |
| ... | ... | @@ -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 |
| 31140 | | /// may be used for the coercion. |
| 31141 | | /// * `const` attribute can be gained |
| 31142 | | /// * `volatile` attribute can be gained |
| 31143 | | /// * `allowzero` attribute can be gained (whether from explicit attribute, C pointer, or optional pointer) but only if !dest_is_mut |
| 31144 | | /// * alignment can be decreased |
| 31145 | | /// * bit offset attributes must match exactly |
| 31146 | | /// * `*`/`[*]` must match exactly, but `[*c]` matches either one |
| 31147 | | /// * sentinel-terminated pointers can coerce into `[*]` |
| 31147 | /// If types `A` and `B` have identical representations in runtime memory, they are considered |
| 31148 | /// "in-memory coercible". This is a subset of normal coercions. Not only can `A` coerce to `B`, but |
| 31149 | /// also, coercions can happen through pointers. For instance, `*const A` can coerce to `*const B`. |
| 31150 | /// |
| 31151 | /// If this function is called, the coercion must be applied, or a compile error emitted if `.ok` |
| 31152 | /// is not returned. This is because this function may modify inferred error sets to make a |
| 31153 | /// coercion possible, even if `.ok` is not returned. |
| 31148 | 31154 | pub fn coerceInMemoryAllowed( |
| 31149 | 31155 | sema: *Sema, |
| 31150 | 31156 | block: *Block, |
| 31151 | 31157 | dest_ty: Type, |
| 31152 | 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 | 31163 | dest_is_mut: bool, |
| 31154 | 31164 | target: std.Target, |
| 31155 | 31165 | dest_src: LazySrcLoc, |
| ... | ... | @@ -31224,7 +31234,7 @@ pub fn coerceInMemoryAllowed( |
| 31224 | 31234 | |
| 31225 | 31235 | // Functions |
| 31226 | 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 | 31240 | // Error Unions |
| ... | ... | @@ -31233,7 +31243,7 @@ pub fn coerceInMemoryAllowed( |
| 31233 | 31243 | const src_payload = src_ty.errorUnionPayload(zcu); |
| 31234 | 31244 | const child = try sema.coerceInMemoryAllowed(block, dest_payload, src_payload, dest_is_mut, target, dest_src, src_src, null); |
| 31235 | 31245 | if (child != .ok) { |
| 31236 | | return InMemoryCoercionResult{ .error_union_payload = .{ |
| 31246 | return .{ .error_union_payload = .{ |
| 31237 | 31247 | .child = try child.dupe(sema.arena), |
| 31238 | 31248 | .actual = src_payload, |
| 31239 | 31249 | .wanted = dest_payload, |
| ... | ... | @@ -31244,7 +31254,11 @@ pub fn coerceInMemoryAllowed( |
| 31244 | 31254 | |
| 31245 | 31255 | // Error Sets |
| 31246 | 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 | 31264 | // Arrays |
| ... | ... | @@ -31252,7 +31266,7 @@ pub fn coerceInMemoryAllowed( |
| 31252 | 31266 | const dest_info = dest_ty.arrayInfo(zcu); |
| 31253 | 31267 | const src_info = src_ty.arrayInfo(zcu); |
| 31254 | 31268 | if (dest_info.len != src_info.len) { |
| 31255 | | return InMemoryCoercionResult{ .array_len = .{ |
| 31269 | return .{ .array_len = .{ |
| 31256 | 31270 | .actual = src_info.len, |
| 31257 | 31271 | .wanted = dest_info.len, |
| 31258 | 31272 | } }; |
| ... | ... | @@ -31263,7 +31277,7 @@ pub fn coerceInMemoryAllowed( |
| 31263 | 31277 | .ok => {}, |
| 31264 | 31278 | .no_match => return child, |
| 31265 | 31279 | else => { |
| 31266 | | return InMemoryCoercionResult{ .array_elem = .{ |
| 31280 | return .{ .array_elem = .{ |
| 31267 | 31281 | .child = try child.dupe(sema.arena), |
| 31268 | 31282 | .actual = src_info.elem_type, |
| 31269 | 31283 | .wanted = dest_info.elem_type, |
| ... | ... | @@ -31279,7 +31293,7 @@ pub fn coerceInMemoryAllowed( |
| 31279 | 31293 | zcu, |
| 31280 | 31294 | )); |
| 31281 | 31295 | if (!ok_sent) { |
| 31282 | | return InMemoryCoercionResult{ .array_sentinel = .{ |
| 31296 | return .{ .array_sentinel = .{ |
| 31283 | 31297 | .actual = src_info.sentinel orelse Value.@"unreachable", |
| 31284 | 31298 | .wanted = dest_info.sentinel orelse Value.@"unreachable", |
| 31285 | 31299 | .ty = dest_info.elem_type, |
| ... | ... | @@ -31293,7 +31307,7 @@ pub fn coerceInMemoryAllowed( |
| 31293 | 31307 | const dest_len = dest_ty.vectorLen(zcu); |
| 31294 | 31308 | const src_len = src_ty.vectorLen(zcu); |
| 31295 | 31309 | if (dest_len != src_len) { |
| 31296 | | return InMemoryCoercionResult{ .vector_len = .{ |
| 31310 | return .{ .vector_len = .{ |
| 31297 | 31311 | .actual = src_len, |
| 31298 | 31312 | .wanted = dest_len, |
| 31299 | 31313 | } }; |
| ... | ... | @@ -31303,7 +31317,7 @@ pub fn coerceInMemoryAllowed( |
| 31303 | 31317 | const src_elem_ty = src_ty.scalarType(zcu); |
| 31304 | 31318 | const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src, null); |
| 31305 | 31319 | if (child != .ok) { |
| 31306 | | return InMemoryCoercionResult{ .vector_elem = .{ |
| 31320 | return .{ .vector_elem = .{ |
| 31307 | 31321 | .child = try child.dupe(sema.arena), |
| 31308 | 31322 | .actual = src_elem_ty, |
| 31309 | 31323 | .wanted = dest_elem_ty, |
| ... | ... | @@ -31320,7 +31334,7 @@ pub fn coerceInMemoryAllowed( |
| 31320 | 31334 | const dest_len = dest_ty.arrayLen(zcu); |
| 31321 | 31335 | const src_len = src_ty.arrayLen(zcu); |
| 31322 | 31336 | if (dest_len != src_len) { |
| 31323 | | return InMemoryCoercionResult{ .array_len = .{ |
| 31337 | return .{ .array_len = .{ |
| 31324 | 31338 | .actual = src_len, |
| 31325 | 31339 | .wanted = dest_len, |
| 31326 | 31340 | } }; |
| ... | ... | @@ -31330,7 +31344,7 @@ pub fn coerceInMemoryAllowed( |
| 31330 | 31344 | const src_elem_ty = src_ty.childType(zcu); |
| 31331 | 31345 | const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src, null); |
| 31332 | 31346 | if (child != .ok) { |
| 31333 | | return InMemoryCoercionResult{ .array_elem = .{ |
| 31347 | return .{ .array_elem = .{ |
| 31334 | 31348 | .child = try child.dupe(sema.arena), |
| 31335 | 31349 | .actual = src_elem_ty, |
| 31336 | 31350 | .wanted = dest_elem_ty, |
| ... | ... | @@ -31340,7 +31354,7 @@ pub fn coerceInMemoryAllowed( |
| 31340 | 31354 | if (dest_tag == .array) { |
| 31341 | 31355 | const dest_info = dest_ty.arrayInfo(zcu); |
| 31342 | 31356 | if (dest_info.sentinel != null) { |
| 31343 | | return InMemoryCoercionResult{ .array_sentinel = .{ |
| 31357 | return .{ .array_sentinel = .{ |
| 31344 | 31358 | .actual = Value.@"unreachable", |
| 31345 | 31359 | .wanted = dest_info.sentinel.?, |
| 31346 | 31360 | .ty = dest_info.elem_type, |
| ... | ... | @@ -31360,7 +31374,7 @@ pub fn coerceInMemoryAllowed( |
| 31360 | 31374 | // Optionals |
| 31361 | 31375 | if (dest_tag == .optional and src_tag == .optional) { |
| 31362 | 31376 | if ((maybe_dest_ptr_ty != null) != (maybe_src_ptr_ty != null)) { |
| 31363 | | return InMemoryCoercionResult{ .optional_shape = .{ |
| 31377 | return .{ .optional_shape = .{ |
| 31364 | 31378 | .actual = src_ty, |
| 31365 | 31379 | .wanted = dest_ty, |
| 31366 | 31380 | } }; |
| ... | ... | @@ -31370,7 +31384,7 @@ pub fn coerceInMemoryAllowed( |
| 31370 | 31384 | |
| 31371 | 31385 | const child = try sema.coerceInMemoryAllowed(block, dest_child_type, src_child_type, dest_is_mut, target, dest_src, src_src, null); |
| 31372 | 31386 | if (child != .ok) { |
| 31373 | | return InMemoryCoercionResult{ .optional_child = .{ |
| 31387 | return .{ .optional_child = .{ |
| 31374 | 31388 | .child = try child.dupe(sema.arena), |
| 31375 | 31389 | .actual = src_child_type, |
| 31376 | 31390 | .wanted = dest_child_type, |
| ... | ... | @@ -31382,7 +31396,6 @@ pub fn coerceInMemoryAllowed( |
| 31382 | 31396 | |
| 31383 | 31397 | // Tuples (with in-memory-coercible fields) |
| 31384 | 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 | 31399 | if (dest_ty.structFieldCount(zcu) != src_ty.structFieldCount(zcu)) break :tuple; |
| 31387 | 31400 | const field_count = dest_ty.structFieldCount(zcu); |
| 31388 | 31401 | for (0..field_count) |field_idx| { |
| ... | ... | @@ -31396,7 +31409,7 @@ pub fn coerceInMemoryAllowed( |
| 31396 | 31409 | return .ok; |
| 31397 | 31410 | } |
| 31398 | 31411 | |
| 31399 | | return InMemoryCoercionResult{ .no_match = .{ |
| 31412 | return .{ .no_match = .{ |
| 31400 | 31413 | .actual = dest_ty, |
| 31401 | 31414 | .wanted = src_ty, |
| 31402 | 31415 | } }; |
| ... | ... | @@ -31505,6 +31518,8 @@ fn coerceInMemoryAllowedFns( |
| 31505 | 31518 | block: *Block, |
| 31506 | 31519 | dest_ty: Type, |
| 31507 | 31520 | src_ty: Type, |
| 31521 | /// If set, the coercion must be valid in both directions. |
| 31522 | dest_is_mut: bool, |
| 31508 | 31523 | target: std.Target, |
| 31509 | 31524 | dest_src: LazySrcLoc, |
| 31510 | 31525 | src_src: LazySrcLoc, |
| ... | ... | @@ -31525,40 +31540,49 @@ fn coerceInMemoryAllowedFns( |
| 31525 | 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 | 31547 | return .{ .fn_cc = .{ |
| 31530 | 31548 | .actual = src_info.cc, |
| 31531 | 31549 | .wanted = dest_info.cc, |
| 31532 | 31550 | } }; |
| 31533 | 31551 | } |
| 31534 | 31552 | |
| 31535 | | switch (src_info.return_type) { |
| 31536 | | .noreturn_type, .generic_poison_type => {}, |
| 31537 | | else => { |
| 31538 | | const dest_return_type = Type.fromInterned(dest_info.return_type); |
| 31539 | | const src_return_type = Type.fromInterned(src_info.return_type); |
| 31540 | | const rt = try sema.coerceInMemoryAllowed(block, dest_return_type, src_return_type, false, target, dest_src, src_src, null); |
| 31541 | | if (rt != .ok) { |
| 31542 | | return InMemoryCoercionResult{ .fn_return_type = .{ |
| 31543 | | .child = try rt.dupe(sema.arena), |
| 31544 | | .actual = src_return_type, |
| 31545 | | .wanted = dest_return_type, |
| 31546 | | } }; |
| 31547 | | } |
| 31548 | | }, |
| 31553 | if (!switch (src_info.return_type) { |
| 31554 | .generic_poison_type => true, |
| 31555 | .noreturn_type => !dest_is_mut, |
| 31556 | else => false, |
| 31557 | }) { |
| 31558 | const rt = try sema.coerceInMemoryAllowed( |
| 31559 | block, |
| 31560 | .fromInterned(dest_info.return_type), |
| 31561 | .fromInterned(src_info.return_type), |
| 31562 | dest_is_mut, |
| 31563 | target, |
| 31564 | dest_src, |
| 31565 | src_src, |
| 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 | 31576 | const params_len = params_len: { |
| 31553 | 31577 | if (dest_info.param_types.len != src_info.param_types.len) { |
| 31554 | | return InMemoryCoercionResult{ .fn_param_count = .{ |
| 31578 | return .{ .fn_param_count = .{ |
| 31555 | 31579 | .actual = src_info.param_types.len, |
| 31556 | 31580 | .wanted = dest_info.param_types.len, |
| 31557 | 31581 | } }; |
| 31558 | 31582 | } |
| 31559 | 31583 | |
| 31560 | 31584 | if (dest_info.noalias_bits != src_info.noalias_bits) { |
| 31561 | | return InMemoryCoercionResult{ .fn_param_noalias = .{ |
| 31585 | return .{ .fn_param_noalias = .{ |
| 31562 | 31586 | .actual = src_info.noalias_bits, |
| 31563 | 31587 | .wanted = dest_info.noalias_bits, |
| 31564 | 31588 | } }; |
| ... | ... | @@ -31568,14 +31592,15 @@ fn coerceInMemoryAllowedFns( |
| 31568 | 31592 | }; |
| 31569 | 31593 | |
| 31570 | 31594 | for (0..params_len) |param_i| { |
| 31571 | | 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]); |
| 31595 | const dest_param_ty: Type = .fromInterned(dest_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); |
| 31575 | | if (dest_info.paramIsComptime(param_i_small) != src_info.paramIsComptime(param_i_small)) { |
| 31576 | | return InMemoryCoercionResult{ .fn_param_comptime = .{ |
| 31598 | const src_is_comptime = src_info.paramIsComptime(@intCast(param_i)); |
| 31599 | const dest_is_comptime = dest_info.paramIsComptime(@intCast(param_i)); |
| 31600 | if (src_is_comptime != dest_is_comptime) { |
| 31601 | return .{ .fn_param_comptime = .{ |
| 31577 | 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 | 31608 | .generic_poison_type => {}, |
| 31584 | 31609 | else => { |
| 31585 | 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 | 31612 | if (param != .ok) { |
| 31588 | | return InMemoryCoercionResult{ .fn_param = .{ |
| 31613 | return .{ .fn_param = .{ |
| 31589 | 31614 | .child = try param.dupe(sema.arena), |
| 31590 | 31615 | .actual = src_param_ty, |
| 31591 | 31616 | .wanted = dest_param_ty, |
| ... | ... | @@ -31644,6 +31669,7 @@ fn coerceInMemoryAllowedPtrs( |
| 31644 | 31669 | src_ty: Type, |
| 31645 | 31670 | dest_ptr_ty: Type, |
| 31646 | 31671 | src_ptr_ty: Type, |
| 31672 | /// If set, the coercion must be valid in both directions. |
| 31647 | 31673 | dest_is_mut: bool, |
| 31648 | 31674 | target: std.Target, |
| 31649 | 31675 | dest_src: LazySrcLoc, |
| ... | ... | @@ -31663,21 +31689,34 @@ fn coerceInMemoryAllowedPtrs( |
| 31663 | 31689 | } }; |
| 31664 | 31690 | } |
| 31665 | 31691 | |
| 31666 | | const ok_cv_qualifiers = |
| 31667 | | (!src_info.flags.is_const or dest_info.flags.is_const) and |
| 31668 | | (!src_info.flags.is_volatile or dest_info.flags.is_volatile); |
| 31692 | const ok_const = src_info.flags.is_const == dest_info.flags.is_const or |
| 31693 | (!dest_is_mut and dest_info.flags.is_const); |
| 31669 | 31694 | |
| 31670 | | if (!ok_cv_qualifiers) { |
| 31671 | | return InMemoryCoercionResult{ .ptr_qualifiers = .{ |
| 31672 | | .actual_const = src_info.flags.is_const, |
| 31673 | | .wanted_const = dest_info.flags.is_const, |
| 31674 | | .actual_volatile = src_info.flags.is_volatile, |
| 31675 | | .wanted_volatile = dest_info.flags.is_volatile, |
| 31676 | | } }; |
| 31677 | | } |
| 31695 | if (!ok_const) return .{ .ptr_const = .{ |
| 31696 | .actual = src_ty, |
| 31697 | .wanted = dest_ty, |
| 31698 | } }; |
| 31699 | |
| 31700 | const ok_volatile = src_info.flags.is_volatile == dest_info.flags.is_volatile or |
| 31701 | (!dest_is_mut and dest_info.flags.is_volatile); |
| 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 | 31718 | if (dest_info.flags.address_space != src_info.flags.address_space) { |
| 31680 | | return InMemoryCoercionResult{ .ptr_addrspace = .{ |
| 31719 | return .{ .ptr_addrspace = .{ |
| 31681 | 31720 | .actual = src_info.flags.address_space, |
| 31682 | 31721 | .wanted = dest_info.flags.address_space, |
| 31683 | 31722 | } }; |
| ... | ... | @@ -31685,8 +31724,28 @@ fn coerceInMemoryAllowedPtrs( |
| 31685 | 31724 | |
| 31686 | 31725 | const dest_child = Type.fromInterned(dest_info.child); |
| 31687 | 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); |
| 31689 | | if (child != .ok) allow: { |
| 31727 | const child = try sema.coerceInMemoryAllowed( |
| 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 | 31749 | // As a special case, we also allow coercing `*[n:s]T` to `*[n]T`, akin to dropping the sentinel from a slice. |
| 31691 | 31750 | // `*[n:s]T` cannot coerce in memory to `*[n]T` since they have different sizes. |
| 31692 | 31751 | if (src_child.zigTypeTag(zcu) == .array and dest_child.zigTypeTag(zcu) == .array and |
| ... | ... | @@ -31695,30 +31754,17 @@ fn coerceInMemoryAllowedPtrs( |
| 31695 | 31754 | { |
| 31696 | 31755 | break :allow; |
| 31697 | 31756 | } |
| 31698 | | return InMemoryCoercionResult{ .ptr_child = .{ |
| 31757 | return .{ .ptr_child = .{ |
| 31699 | 31758 | .child = try child.dupe(sema.arena), |
| 31700 | | .actual = Type.fromInterned(src_info.child), |
| 31701 | | .wanted = Type.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, |
| 31759 | .actual = .fromInterned(src_info.child), |
| 31760 | .wanted = .fromInterned(dest_info.child), |
| 31715 | 31761 | } }; |
| 31716 | 31762 | } |
| 31717 | 31763 | |
| 31718 | 31764 | if (src_info.packed_offset.host_size != dest_info.packed_offset.host_size or |
| 31719 | 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 | 31768 | .actual_host = src_info.packed_offset.host_size, |
| 31723 | 31769 | .wanted_host = dest_info.packed_offset.host_size, |
| 31724 | 31770 | .actual_offset = src_info.packed_offset.bit_offset, |
| ... | ... | @@ -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 |
| 31730 | | (src_info.sentinel != .none and |
| 31731 | | dest_info.sentinel == try zcu.intern_pool.getCoerced(sema.gpa, pt.tid, src_info.sentinel, dest_info.child)); |
| 31732 | | if (!ok_sent) { |
| 31733 | | return InMemoryCoercionResult{ .ptr_sentinel = .{ |
| 31775 | const sentinel_ok = ok: { |
| 31776 | const ss = src_info.sentinel; |
| 31777 | const ds = dest_info.sentinel; |
| 31778 | if (ss == .none and ds == .none) break :ok true; |
| 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 | 31789 | .actual = switch (src_info.sentinel) { |
| 31735 | 31790 | .none => Value.@"unreachable", |
| 31736 | 31791 | else => Value.fromInterned(src_info.sentinel), |
| ... | ... | @@ -31760,7 +31815,7 @@ fn coerceInMemoryAllowedPtrs( |
| 31760 | 31815 | else |
| 31761 | 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 | 31819 | return InMemoryCoercionResult{ .ptr_alignment = .{ |
| 31765 | 31820 | .actual = src_align, |
| 31766 | 31821 | .wanted = dest_align, |
| ... | ... | @@ -32252,19 +32307,23 @@ fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_resul |
| 32252 | 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 | 32308 | (Type.fromInterned(inst_info.child).isTuple(zcu) and Type.fromInterned(inst_info.child).structFieldCount(zcu) == 0); |
| 32254 | 32309 | |
| 32255 | | const ok_cv_qualifiers = |
| 32256 | | ((!inst_info.flags.is_const or dest_info.flags.is_const) or len0) and |
| 32257 | | (!inst_info.flags.is_volatile or dest_info.flags.is_volatile); |
| 32258 | | |
| 32259 | | if (!ok_cv_qualifiers) { |
| 32260 | | in_memory_result.* = .{ .ptr_qualifiers = .{ |
| 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, |
| 32310 | const ok_const = (!inst_info.flags.is_const or dest_info.flags.is_const) or len0; |
| 32311 | const ok_volatile = !inst_info.flags.is_volatile or dest_info.flags.is_volatile; |
| 32312 | if (!ok_const) { |
| 32313 | in_memory_result.* = .{ .ptr_const = .{ |
| 32314 | .actual = inst_ty, |
| 32315 | .wanted = dest_ty, |
| 32265 | 32316 | } }; |
| 32266 | 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 | 32327 | if (dest_info.flags.address_space != inst_info.flags.address_space) { |
| 32269 | 32328 | in_memory_result.* = .{ .ptr_addrspace = .{ |
| 32270 | 32329 | .actual = inst_info.flags.address_space, |
| ... | ... | @@ -35441,11 +35500,11 @@ fn resolvePeerTypesInner( |
| 35441 | 35500 | .peer_idx_b = i, |
| 35442 | 35501 | } }; |
| 35443 | 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 | 35504 | continue; |
| 35446 | 35505 | } |
| 35447 | 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 | 35508 | opt_cur_ty = ty; |
| 35450 | 35509 | continue; |
| 35451 | 35510 | } |
| ... | ... | @@ -35834,12 +35893,12 @@ fn resolvePairInMemoryCoercible(sema: *Sema, block: *Block, src: LazySrcLoc, ty_ |
| 35834 | 35893 | const target = sema.pt.zcu.getTarget(); |
| 35835 | 35894 | |
| 35836 | 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 | 35897 | return ty_a; |
| 35839 | 35898 | } |
| 35840 | 35899 | |
| 35841 | 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 | 35902 | return ty_b; |
| 35844 | 35903 | } |
| 35845 | 35904 | |