authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-09-10 01:47:51-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-09-10 01:47:51-07:00
log504c85a62641fecb29ead2cc2c900374fb4210a8
tree0afc7dadae39bd4d176c9a0122230ae60b409c88
parent0b75a2a1b1972777350c33c27cfe720172491de6

Sema: allow coercion of generic function pointer

to runtime function pointer when comptime-known.

1 files changed, 23 insertions(+), 10 deletions(-)

src/Sema.zig+23-10
......@@ -29545,18 +29545,18 @@ pub fn coerceInMemoryAllowed(
2954529545 const maybe_src_ptr_ty = try sema.typePtrOrOptionalPtrTy(src_ty);
2954629546 if (maybe_dest_ptr_ty) |dest_ptr_ty| {
2954729547 if (maybe_src_ptr_ty) |src_ptr_ty| {
29548 return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ptr_ty, src_ptr_ty, dest_is_mut, target, dest_src, src_src);
29548 return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ptr_ty, src_ptr_ty, dest_is_mut, target, dest_src, src_src, src_val);
2954929549 }
2955029550 }
2955129551
2955229552 // Slices
2955329553 if (dest_ty.isSlice(zcu) and src_ty.isSlice(zcu)) {
29554 return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target, dest_src, src_src);
29554 return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target, dest_src, src_src, src_val);
2955529555 }
2955629556
2955729557 // Functions
2955829558 if (dest_tag == .@"fn" and src_tag == .@"fn") {
29559 return try sema.coerceInMemoryAllowedFns(block, dest_ty, src_ty, dest_is_mut, target, dest_src, src_src);
29559 return try sema.coerceInMemoryAllowedFns(block, dest_ty, src_ty, dest_is_mut, target, dest_src, src_src, src_val);
2956029560 }
2956129561
2956229562 // Error Unions
......@@ -29801,6 +29801,7 @@ fn coerceInMemoryAllowedFns(
2980129801 target: *const std.Target,
2980229802 dest_src: LazySrcLoc,
2980329803 src_src: LazySrcLoc,
29804 src_val: ?Value,
2980429805) !InMemoryCoercionResult {
2980529806 const pt = sema.pt;
2980629807 const zcu = pt.zcu;
......@@ -29809,17 +29810,22 @@ fn coerceInMemoryAllowedFns(
2980929810 const dest_info = zcu.typeToFunc(dest_ty).?;
2981029811 const src_info = zcu.typeToFunc(src_ty).?;
2981129812
29813 const comptime_known_src = src_val != null;
29814 const inline_exempt = src_info.cc == .@"inline" and comptime_known_src;
29815
2981229816 {
2981329817 if (dest_info.is_var_args != src_info.is_var_args) {
29814 return InMemoryCoercionResult{ .fn_var_args = dest_info.is_var_args };
29818 return .{ .fn_var_args = dest_info.is_var_args };
2981529819 }
2981629820
2981729821 if (dest_info.is_generic != src_info.is_generic) {
29818 return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic };
29822 // Coercion of pointer to generic function to regular function pointer is allowed as long
29823 // as the pointer to generic function is comptime known.
29824 if (!comptime_known_src) return .{ .fn_generic = dest_info.is_generic };
2981929825 }
2982029826
29821 const callconv_ok = callconvCoerceAllowed(target, src_info.cc, dest_info.cc) and
29822 (!dest_is_mut or callconvCoerceAllowed(target, dest_info.cc, src_info.cc));
29827 const callconv_ok = inline_exempt or (callconvCoerceAllowed(target, src_info.cc, dest_info.cc) and
29828 (!dest_is_mut or callconvCoerceAllowed(target, dest_info.cc, src_info.cc)));
2982329829
2982429830 if (!callconv_ok) {
2982529831 return .{ .fn_cc = .{
......@@ -29874,6 +29880,7 @@ fn coerceInMemoryAllowedFns(
2987429880 const src_param_ty: Type = .fromInterned(src_info.param_types.get(ip)[param_i]);
2987529881
2987629882 comptime_param: {
29883 if (inline_exempt) break :comptime_param;
2987729884 const src_is_comptime = src_info.paramIsComptime(@intCast(param_i));
2987829885 const dest_is_comptime = dest_info.paramIsComptime(@intCast(param_i));
2987929886 if (src_is_comptime == dest_is_comptime) break :comptime_param;
......@@ -29956,6 +29963,7 @@ fn coerceInMemoryAllowedPtrs(
2995629963 target: *const std.Target,
2995729964 dest_src: LazySrcLoc,
2995829965 src_src: LazySrcLoc,
29966 src_val: ?Value,
2995929967) !InMemoryCoercionResult {
2996029968 const pt = sema.pt;
2996129969 const zcu = pt.zcu;
......@@ -30004,6 +30012,11 @@ fn coerceInMemoryAllowedPtrs(
3000430012 } };
3000530013 }
3000630014
30015 const child_src_val: ?Value = if (src_val) |v| switch (try pointerDerefExtra(sema, block, src_src, v)) {
30016 .val => |val| val,
30017 .runtime_load, .needed_well_defined, .out_of_bounds => null,
30018 } else null;
30019
3000730020 const dest_child: Type = .fromInterned(dest_info.child);
3000830021 const src_child: Type = .fromInterned(src_info.child);
3000930022 const child = try sema.coerceInMemoryAllowed(
......@@ -30025,7 +30038,7 @@ fn coerceInMemoryAllowedPtrs(
3002530038 target,
3002630039 dest_src,
3002730040 src_src,
30028 null,
30041 child_src_val,
3002930042 );
3003030043 if (child != .ok and !dest_is_mut) allow: {
3003130044 // As a special case, we also allow coercing `*[n:s]T` to `*[n]T`, akin to dropping the sentinel from a slice.
......@@ -33750,11 +33763,11 @@ fn resolvePeerTypesInner(
3375033763 .peer_idx_b = i,
3375133764 } };
3375233765 // ty -> cur_ty
33753 if (.ok == try sema.coerceInMemoryAllowedFns(block, cur_ty, ty, false, target, src, src)) {
33766 if (.ok == try sema.coerceInMemoryAllowedFns(block, cur_ty, ty, false, target, src, src, null)) {
3375433767 continue;
3375533768 }
3375633769 // cur_ty -> ty
33757 if (.ok == try sema.coerceInMemoryAllowedFns(block, ty, cur_ty, false, target, src, src)) {
33770 if (.ok == try sema.coerceInMemoryAllowedFns(block, ty, cur_ty, false, target, src, src, null)) {
3375833771 opt_cur_ty = ty;
3375933772 continue;
3376033773 }