@@ -2025,15 +2025,24 @@ pub(crate) fn lower_expr_full( |
| 2025 | 2025 | ) |
| 2026 | 2026 | .unwrap_or(IrType::Int(IntWidth::I32)); |
| 2027 | 2027 | // Honor the abstract-interface descriptor |
| 2028 | | - // mask when forwarding actuals. Without |
| 2029 | | - // this, an assumed-shape dummy |
| 2030 | | - // (`real(8), intent(in) :: x(:)`) received |
| 2031 | | - // only a base data pointer in place of |
| 2032 | | - // the descriptor — the callee then read |
| 2033 | | - // dims/rank out of the array elements' |
| 2034 | | - // bytes and segfaulted (stdlib's iterative |
| 2035 | | - // solvers all dispatch dot_product through |
| 2036 | | - // a procedure-pointer field this way). |
| 2028 | + // mask when forwarding actuals. When an |
| 2029 | + // actual is a descriptor-backed array |
| 2030 | + // (assumed-shape dummy / allocatable / |
| 2031 | + // pointer), pass its full descriptor — |
| 2032 | + // the callee declared via the abstract |
| 2033 | + // interface must take a descriptor for |
| 2034 | + // assumed-shape parameters. Without this, |
| 2035 | + // `lower_arg_by_ref_full` returned the |
| 2036 | + // base data pointer (loaded out of the |
| 2037 | + // descriptor) and the callee tried to |
| 2038 | + // read rank/dims out of the array elements' |
| 2039 | + // bytes — stdlib's iterative solvers all |
| 2040 | + // dispatch dot_product/matvec through a |
| 2041 | + // procedure-pointer field of a class arg |
| 2042 | + // this way and SEGV'd deep inside |
| 2043 | + // stdlib_dot_product_dp on an indirect |
| 2044 | + // load whose target was the array's first |
| 2045 | + // f64 (1.0 = bits 0x3ff0...). |
| 2037 | 2046 | let callee_descriptor_args = |
| 2038 | 2047 | first_procedure_lookup(&abi_lookup_keys, |k| { |
| 2039 | 2048 | descriptor_params |
@@ -2046,10 +2055,20 @@ pub(crate) fn lower_expr_full( |
| 2046 | 2055 | e, |
| 2047 | 2056 | ) = &arg.value |
| 2048 | 2057 | { |
| 2049 | | - let wants_descriptor = callee_descriptor_args |
| 2058 | + let mask_says_descriptor = callee_descriptor_args |
| 2050 | 2059 | .as_ref() |
| 2051 | 2060 | .map(|mask| mask.get(i).copied().unwrap_or(false)) |
| 2052 | 2061 | .unwrap_or(false); |
| 2062 | + // Fallback: if the lookup missed |
| 2063 | + // (abstract iface not in |
| 2064 | + // descriptor_params), inspect the |
| 2065 | + // actual itself. A descriptor- |
| 2066 | + // backed local must be passed by |
| 2067 | + // descriptor regardless. |
| 2068 | + let actual_is_descriptor_backed = |
| 2069 | + actual_is_descriptor_array(locals, e); |
| 2070 | + let wants_descriptor = mask_says_descriptor |
| 2071 | + || actual_is_descriptor_backed; |
| 2053 | 2072 | let v = if wants_descriptor { |
| 2054 | 2073 | lower_arg_descriptor( |
| 2055 | 2074 | b, |