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(...@@ -29545,18 +29545,18 @@ pub fn coerceInMemoryAllowed(
29545 const maybe_src_ptr_ty = try sema.typePtrOrOptionalPtrTy(src_ty);29545 const maybe_src_ptr_ty = try sema.typePtrOrOptionalPtrTy(src_ty);
29546 if (maybe_dest_ptr_ty) |dest_ptr_ty| {29546 if (maybe_dest_ptr_ty) |dest_ptr_ty| {
29547 if (maybe_src_ptr_ty) |src_ptr_ty| {29547 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);
29549 }29549 }
29550 }29550 }
2955129551
29552 // Slices29552 // Slices
29553 if (dest_ty.isSlice(zcu) and src_ty.isSlice(zcu)) {29553 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);
29555 }29555 }
2955629556
29557 // Functions29557 // Functions
29558 if (dest_tag == .@"fn" and src_tag == .@"fn") {29558 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);
29560 }29560 }
2956129561
29562 // Error Unions29562 // Error Unions
...@@ -29801,6 +29801,7 @@ fn coerceInMemoryAllowedFns(...@@ -29801,6 +29801,7 @@ fn coerceInMemoryAllowedFns(
29801 target: *const std.Target,29801 target: *const std.Target,
29802 dest_src: LazySrcLoc,29802 dest_src: LazySrcLoc,
29803 src_src: LazySrcLoc,29803 src_src: LazySrcLoc,
29804 src_val: ?Value,
29804) !InMemoryCoercionResult {29805) !InMemoryCoercionResult {
29805 const pt = sema.pt;29806 const pt = sema.pt;
29806 const zcu = pt.zcu;29807 const zcu = pt.zcu;
...@@ -29809,17 +29810,22 @@ fn coerceInMemoryAllowedFns(...@@ -29809,17 +29810,22 @@ fn coerceInMemoryAllowedFns(
29809 const dest_info = zcu.typeToFunc(dest_ty).?;29810 const dest_info = zcu.typeToFunc(dest_ty).?;
29810 const src_info = zcu.typeToFunc(src_ty).?;29811 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
29812 {29816 {
29813 if (dest_info.is_var_args != src_info.is_var_args) {29817 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 };
29815 }29819 }
2981629820
29817 if (dest_info.is_generic != src_info.is_generic) {29821 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 };
29819 }29825 }
2982029826
29821 const callconv_ok = callconvCoerceAllowed(target, src_info.cc, dest_info.cc) and29827 const callconv_ok = inline_exempt or (callconvCoerceAllowed(target, src_info.cc, dest_info.cc) and
29822 (!dest_is_mut or callconvCoerceAllowed(target, dest_info.cc, src_info.cc));29828 (!dest_is_mut or callconvCoerceAllowed(target, dest_info.cc, src_info.cc)));
2982329829
29824 if (!callconv_ok) {29830 if (!callconv_ok) {
29825 return .{ .fn_cc = .{29831 return .{ .fn_cc = .{
...@@ -29874,6 +29880,7 @@ fn coerceInMemoryAllowedFns(...@@ -29874,6 +29880,7 @@ fn coerceInMemoryAllowedFns(
29874 const src_param_ty: Type = .fromInterned(src_info.param_types.get(ip)[param_i]);29880 const src_param_ty: Type = .fromInterned(src_info.param_types.get(ip)[param_i]);
2987529881
29876 comptime_param: {29882 comptime_param: {
29883 if (inline_exempt) break :comptime_param;
29877 const src_is_comptime = src_info.paramIsComptime(@intCast(param_i));29884 const src_is_comptime = src_info.paramIsComptime(@intCast(param_i));
29878 const dest_is_comptime = dest_info.paramIsComptime(@intCast(param_i));29885 const dest_is_comptime = dest_info.paramIsComptime(@intCast(param_i));
29879 if (src_is_comptime == dest_is_comptime) break :comptime_param;29886 if (src_is_comptime == dest_is_comptime) break :comptime_param;
...@@ -29956,6 +29963,7 @@ fn coerceInMemoryAllowedPtrs(...@@ -29956,6 +29963,7 @@ fn coerceInMemoryAllowedPtrs(
29956 target: *const std.Target,29963 target: *const std.Target,
29957 dest_src: LazySrcLoc,29964 dest_src: LazySrcLoc,
29958 src_src: LazySrcLoc,29965 src_src: LazySrcLoc,
29966 src_val: ?Value,
29959) !InMemoryCoercionResult {29967) !InMemoryCoercionResult {
29960 const pt = sema.pt;29968 const pt = sema.pt;
29961 const zcu = pt.zcu;29969 const zcu = pt.zcu;
...@@ -30004,6 +30012,11 @@ fn coerceInMemoryAllowedPtrs(...@@ -30004,6 +30012,11 @@ fn coerceInMemoryAllowedPtrs(
30004 } };30012 } };
30005 }30013 }
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
30007 const dest_child: Type = .fromInterned(dest_info.child);30020 const dest_child: Type = .fromInterned(dest_info.child);
30008 const src_child: Type = .fromInterned(src_info.child);30021 const src_child: Type = .fromInterned(src_info.child);
30009 const child = try sema.coerceInMemoryAllowed(30022 const child = try sema.coerceInMemoryAllowed(
...@@ -30025,7 +30038,7 @@ fn coerceInMemoryAllowedPtrs(...@@ -30025,7 +30038,7 @@ fn coerceInMemoryAllowedPtrs(
30025 target,30038 target,
30026 dest_src,30039 dest_src,
30027 src_src,30040 src_src,
30028 null,30041 child_src_val,
30029 );30042 );
30030 if (child != .ok and !dest_is_mut) allow: {30043 if (child != .ok and !dest_is_mut) allow: {
30031 // As a special case, we also allow coercing `*[n:s]T` to `*[n]T`, akin to dropping the sentinel from a slice.30044 // 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(...@@ -33750,11 +33763,11 @@ fn resolvePeerTypesInner(
33750 .peer_idx_b = i,33763 .peer_idx_b = i,
33751 } };33764 } };
33752 // ty -> cur_ty33765 // 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)) {
33754 continue;33767 continue;
33755 }33768 }
33756 // cur_ty -> ty33769 // 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)) {
33758 opt_cur_ty = ty;33771 opt_cur_ty = ty;
33759 continue;33772 continue;
33760 }33773 }