The semantic_candidates filter above already proved that at least
one specific in `interface assignment(=)` matches both operands by
category and kind. The earlier IR-level gate (`if
same_intrinsic_semantic_type(...) && !derived { return false }`)
fired in two distinct false-positive shapes:
1. `lv2 = s` where lv2 is `logical(int32), allocatable` and s is
`type(bitset_64)`. Both operands peeled to `Bool` after Ptr
stripping, so the gate skipped the user-defined
`logint32_assign_64` and a scalar broadcast crashed.
2. stdlib_strings / path call sites where the intrinsic memcpy
happened to be wrong but didn't crash, masking the bug.
Trust the semantic filter — the IR types only ever produce false
positives here.
AFS_LD=1 (or any non-falsy value) now picks the sibling afs-ld
binary alongside the armfortas executable, in addition to the
existing AFS_LD_PATH override that names a specific path. The
afs-ld backend now forwards library_search_paths, link_libs, and
rpath through to the linker instead of erroring out, so the same
driver invocation works under both system ld and afs-ld for the
common cases.
Test: hello_world_runs_through_driver_with_afs_ld_enable_flag.
arg_uses_descriptor_from_decls grouped ArraySpec::AssumedSize with
AssumedShape / Deferred / AssumedRank and returned descriptor_arg=true
for them. Per F2018 §15.5.2 an assumed-size dummy (`tau(*)` or
`a(lda, *)`) is passed as a bare element pointer, not a descriptor,
so flagging it as descriptor_arg made every `tau(i)` reference go
through array_descriptor_addr → array_base_addr — which loads through
the slot a SECOND time as if the slot held a descriptor pointer. For
`real, intent(out) :: tau(*)` the second load read the first 8
bytes of the (zero-initialised) array as the supposed base pointer,
so the element address came out zero.
Concretely, stdlib_sgeqr2 -> stdlib_slarfg(..., tau(i)) passed x4=null
to slarfg, which then SEGV'd at the `tau = zero` store inside the
`xnorm == 0` branch. After the fix slarfg receives a proper element
address and the QR/EIG cluster no longer crashes.
The intrinsic random_number(harvest) was always lowered to a single
scalar afs_random_number_f32/f64 call, even when harvest was a whole
array. That filled only harvest(1,1) and left the rest at whatever
stack data happened to be there — programs like example_qr seemed to
work on small problems by accident (zero-init bss) and crashed
nondeterministically on real ones once LAPACK hit a row of garbage.
Add afs_random_number_array_{f32,f64}(ptr, n) runtime entries that
draw n independent values, and dispatch through them in the IR
lowering when the harvest expression is a Name bound to an
array-like local. Scalar callers keep the original entries so
existing code paths are unchanged.
Probe: random_number(A) on a 3x3 array now produces independent
draws in (0, 1) for every element, where before A(2,2)/A(3,3) etc.
were left at -1.0.
stdlib savetxt(unit, x, ...) checks
inquire(unit=unit, opened=opened, write=writable)
if (.not. opened .or. writable(1:1) /= 'Y') call error_stop
to verify the unit can be written before emitting any data. Two gaps:
1. afs_inquire_unit / afs_inquire_file had no parameter for write=,
read=, or readwrite=, so the caller's writable variable was left
at uninitialized stack data — savetxt always concluded the unit
was not writable.
2. The IR's Stmt::Inquire lowering never extracted these three specs
from the AST, so even adding runtime params would have silently
passed null buffers.
Add (read_buf, write_buf, readwrite_buf) trios to both runtime
functions and to both call-emission sites in IR. Populate based on
the connected unit's Action: Read => YES/NO/NO, Write => NO/YES/NO,
ReadWrite => YES/YES/YES, disconnected => UNKNOWN.
Make Action Copy so the action-cap helper can take it by value
without cloning at every call site.
write(unit, fmt, iostat=ios, iomsg=iomsg) values would leave the user's
ios variable at its uninitialized stack value on success — only error
paths are even capable of writing it, and there are none in the runtime
yet. Stdlib's universal pattern is
if (ios/=0) call error_stop(msg=trim(iomsg))
so on a successful write the user's program would die with a spurious
ERROR STOP because ios was random garbage. Resolve the iostat= control
target up front and store i32(0) after afs_fmt_end / lower_write_items_adv
returns, both for unit-targeted writes and for internal-buffer writes.
Combined with 4986129 (descriptor-aware section iteration), savetxt
now writes example.dat / example.csv / example2.dat / example3.dat
correctly with three rows of data each. Remaining savetxt failure is
a separate output_unit (stdout via unit 6) handling bug.
Both formatted-write (write(u, fmt) d(i, :)) and list-directed-write
(write(u, *) d(i, :)) of an array section through an assumed-shape
dummy were silently producing empty rows. info.dims is empty for
assumed-shape (decl_ext == 0), so the existing fixed-shape iterators
ran zero iterations and emitted only newlines.
Add lower_alloc_section_write_nd and lower_alloc_section_fmt_push_nd
that load lower bound, upper bound, and per-dim memory stride from
the runtime ArrayDescriptor — matching what compute_flat_elem_offset
already does for descriptor reads — and route through them when
local_uses_array_descriptor is true. Stdlib savetxt and the many
log_io_error / log_text_error / cov / similar paths flow through
this code now.