@@ -28623,6 +28623,49 @@ fn cmplx_whole_array_with_kind_keyword_returns_correct_kind_descriptor() { |
| 28623 | 28623 | let _ = std::fs::remove_file(&src); |
| 28624 | 28624 | } |
| 28625 | 28625 | |
| 28626 | +#[test] |
| 28627 | +fn allocatable_rank2_section_row_assignment_uses_columnmajor_stride() { |
| 28628 | + // F2018 §6.5.3: section assignment to a "row" of a column-major |
| 28629 | + // allocatable matrix (e.g. `a(1,:) = [...]`) must step through |
| 28630 | + // memory by the column extent, not contiguously. The compiler |
| 28631 | + // builds the section descriptor via afs_create_section using the |
| 28632 | + // source array's per-dim stride, so the source descriptor's |
| 28633 | + // strides must match the column-major canonical layout. For |
| 28634 | + // stack arrays, materialize_array_descriptor_for_info computes |
| 28635 | + // those correctly; for allocatables, afs_allocate_array used to |
| 28636 | + // copy whatever stride the compiler emitted (always 1) and the |
| 28637 | + // resulting section view collapsed into a contiguous walk — |
| 28638 | + // `a(1,:) = [10,20,30]; a(2,:) = [100,200,300]` left a as |
| 28639 | + // [[10,200,?],[100,300,?]] instead of [[10,20,30],[100,200,300]]. |
| 28640 | + // Matched stdlib_sparse_conversion (rebuild needed): from_ijv was |
| 28641 | + // initializing COO%index via section assignment, then passing the |
| 28642 | + // descriptor to assumed-size dummies that read garbage. |
| 28643 | + let src = write_program( |
| 28644 | + "program p\n implicit none\n integer, allocatable :: a(:,:)\n allocate(a(2, 3))\n a(1, :) = [10, 20, 30]\n a(2, :) = [100, 200, 300]\n if (a(1,1) /= 10 .or. a(1,2) /= 20 .or. a(1,3) /= 30 ) error stop 1\n if (a(2,1) /= 100 .or. a(2,2) /= 200 .or. a(2,3) /= 300) error stop 2\n print *, 'ok'\nend program\n", |
| 28645 | + "f90", |
| 28646 | + ); |
| 28647 | + let out = unique_path("allocatable_rank2_row_section", "bin"); |
| 28648 | + let compile = Command::new(compiler("armfortas")) |
| 28649 | + .args([src.to_str().unwrap(), "-o", out.to_str().unwrap()]) |
| 28650 | + .output() |
| 28651 | + .expect("allocatable rank-2 row section compile failed to spawn"); |
| 28652 | + assert!( |
| 28653 | + compile.status.success(), |
| 28654 | + "allocatable rank-2 row section compile failed: {}", |
| 28655 | + String::from_utf8_lossy(&compile.stderr) |
| 28656 | + ); |
| 28657 | + let run = Command::new(&out).output().expect("run failed"); |
| 28658 | + assert!( |
| 28659 | + run.status.success() && String::from_utf8_lossy(&run.stdout).contains("ok"), |
| 28660 | + "allocatable rank-2 row section run failed: status={:?} stdout={} stderr={}", |
| 28661 | + run.status, |
| 28662 | + String::from_utf8_lossy(&run.stdout), |
| 28663 | + String::from_utf8_lossy(&run.stderr) |
| 28664 | + ); |
| 28665 | + let _ = std::fs::remove_file(&out); |
| 28666 | + let _ = std::fs::remove_file(&src); |
| 28667 | +} |
| 28668 | + |
| 28626 | 28669 | #[test] |
| 28627 | 28670 | fn allocate_stat_int64_writes_back_to_user_variable() { |
| 28628 | 28671 | // F2018 §9.7.1.3: STAT= variable receives the allocate status. |