All 7 test_gap_temporal_*.ts gap tests fail to link on macOS at current main (0bb03e82f), with an undefined _CFRelease from iana_time_zone.
This is release-gating (the parity suites gate release-packages.yml) and is invisible to PR CI, because parity and compile-smoke are tag-push-only. It was found incidentally while running the full gap sweep for #6925.
Symptom
Linking (runtime-only)...
Undefined symbols for architecture arm64:
"_CFRelease", referenced from:
__RNvNtCsfzQT8WKhDmi_14iana_time_zone8platform18get_timezone_inner
in libperry_runtime.a[49](...iana_time_zone...rcgu.o)
"_CFStringGetBytes", ...
"_CFStringGetCStringPtr", ...
Affected (7/7 temporal gap tests):
test_gap_temporal_construct_overflow test_gap_temporal_options
test_gap_temporal_duration test_gap_temporal_plaindate_plaintime
test_gap_temporal_instant_zoned test_gap_temporal_plaindatetime
test_gap_temporal_now
Root cause
crates/perry/src/commands/compile/link/build_and_run.rs (~line 939) gates the macOS framework list on:
if (cfg!(target_os = "macos") || is_cross_macos)
&& !is_harmonyos
&& (ctx.needs_stdlib || ctx.needs_ui || ctx.needs_plugins || ctx.needs_geisterhand)
{
cmd.arg("-framework").arg("Security")
.arg("-framework").arg("CoreFoundation")
.arg("-framework").arg("SystemConfiguration")
.arg("-liconv").arg("-lresolv").arg("-lobjc");
}
A Temporal program is runtime-only — none of those four flags is set — so it links without CoreFoundation. But perry-runtime built with the temporal feature pulls in iana_time_zone, whose macOS timezone lookup calls CFRelease / CFStringGetBytes / CFStringGetCStringPtr. Hence the undefined symbols.
The condition needs a fifth term for the temporal/iana_time_zone surface (or, more narrowly, CoreFoundation alone when that feature is compiled in).
Introduced by #6923 (db6b2e2a4, "drop unused framework dylibs from runtime-only macOS binaries"). That change is a good win (~1.8 ms of the ~3 ms hello startup) and its own comment anticipates this exact failure mode:
"Skip the whole list for those links: a runtime-only program that genuinely needs one of these fails AT LINK TIME with an undefined symbol (deterministic, caught by the parity suites), never at runtime."
The reasoning is sound — the failure is deterministic and link-time. The gap is that the parity suites which would catch it don't run per-PR.
Attribution / how it was isolated
Not caused by #6925 (repsel Phase 5a); three independent checks:
- Identical failures with that PR's phase fully disabled (
PERRY_PTR_SHAPE_THIS=0 PERRY_PTR_SHAPE_LOCALS=0) — 7/7 fail in both arms.
build_and_run.rs is not in that PR's diff; the failing code path is byte-identical to main.
- The PR's diff contains zero linking/framework references (
grep -icE "framework|CoreFoundation|link_arg|dylib" → 0).
Suggested fix
Add the temporal surface to the gate, e.g. a ctx.needs_temporal (or reuse whatever signals the temporal runtime feature) so CoreFoundation is linked when iana_time_zone is present. Keeping the other frameworks off preserves most of #6923's startup win for the common runtime-only case.
Secondary suggestion
Consider running a small representative gap shard on PRs — the temporal group is 7 files and would have caught this within a minute. The full suite staying tag-gated is reasonable; a smoke subset is not expensive.
All 7
test_gap_temporal_*.tsgap tests fail to link on macOS at currentmain(0bb03e82f), with an undefined_CFReleasefromiana_time_zone.This is release-gating (the parity suites gate
release-packages.yml) and is invisible to PR CI, becauseparityandcompile-smokeare tag-push-only. It was found incidentally while running the full gap sweep for #6925.Symptom
Affected (7/7 temporal gap tests):
Root cause
crates/perry/src/commands/compile/link/build_and_run.rs(~line 939) gates the macOS framework list on:A Temporal program is runtime-only — none of those four flags is set — so it links without CoreFoundation. But
perry-runtimebuilt with thetemporalfeature pulls iniana_time_zone, whose macOS timezone lookup callsCFRelease/CFStringGetBytes/CFStringGetCStringPtr. Hence the undefined symbols.The condition needs a fifth term for the temporal/
iana_time_zonesurface (or, more narrowly, CoreFoundation alone when that feature is compiled in).Introduced by #6923 (
db6b2e2a4, "drop unused framework dylibs from runtime-only macOS binaries"). That change is a good win (~1.8 ms of the ~3 ms hello startup) and its own comment anticipates this exact failure mode:The reasoning is sound — the failure is deterministic and link-time. The gap is that the parity suites which would catch it don't run per-PR.
Attribution / how it was isolated
Not caused by #6925 (repsel Phase 5a); three independent checks:
PERRY_PTR_SHAPE_THIS=0 PERRY_PTR_SHAPE_LOCALS=0) — 7/7 fail in both arms.build_and_run.rsis not in that PR's diff; the failing code path is byte-identical tomain.grep -icE "framework|CoreFoundation|link_arg|dylib"→ 0).Suggested fix
Add the temporal surface to the gate, e.g. a
ctx.needs_temporal(or reuse whatever signals thetemporalruntime feature) so CoreFoundation is linked wheniana_time_zoneis present. Keeping the other frameworks off preserves most of #6923's startup win for the common runtime-only case.Secondary suggestion
Consider running a small representative gap shard on PRs — the temporal group is 7 files and would have caught this within a minute. The full suite staying tag-gated is reasonable; a smoke subset is not expensive.