fortrangoingonforty/armfortas / cd7682a

Browse files

Test allocatable component → assumed-size dummy unwraps descriptor

Authored by espadonne
Committed by mfwolffe
SHA
cd7682ade6717fe2cb3f48ba6015d3883c2010a8
Parents
5a620d4
Tree
cdb096d

1 changed file

StatusFile+-
M tests/cli_driver.rs 41 0
tests/cli_driver.rsmodified
@@ -28623,6 +28623,47 @@ fn cmplx_whole_array_with_kind_keyword_returns_correct_kind_descriptor() {
28623
     let _ = std::fs::remove_file(&src);
28623
     let _ = std::fs::remove_file(&src);
28624
 }
28624
 }
28625
 
28625
 
28626
+#[test]
28627
+fn allocatable_array_component_passed_to_assumed_size_unwraps_descriptor() {
28628
+    // F2018 §15.5.2.4: when an allocatable rank-N array component
28629
+    // (e.g. `c%idx` where `idx` is `integer, allocatable :: idx(:,:)`)
28630
+    // is passed to a by-ref dummy declared assumed-size or
28631
+    // explicit-shape (`a(2, *)`), the callee expects an element
28632
+    // pointer it can index column-major directly. lower_arg_by_ref_full
28633
+    // for the ComponentAccess path used to return the field's storage
28634
+    // address — which for an allocatable component is the address of
28635
+    // the 384-byte descriptor itself — so the dummy walked descriptor
28636
+    // bytes (base_addr, elem_size, rank fields) as if they were array
28637
+    // elements. Surfaced inside stdlib_sparse_conversion's
28638
+    // sort_coo_unique_dp where `a(1, ed)` returned descriptor-pointer
28639
+    // bits and triggered "Bounds check failed: index <garbage> outside
28640
+    // [0, num_rows]" inside count_i indexing.
28641
+    let src = write_program(
28642
+        "module m\n  implicit none\n  type :: container\n    integer, allocatable :: idx(:,:)\n  end type\ncontains\n  subroutine sort_check(a, n, ok)\n    integer, intent(inout) :: a(2,*)\n    integer, intent(in) :: n\n    logical, intent(out) :: ok\n    integer :: ed\n    ok = .true.\n    do ed = 1, n\n      if (a(1, ed) /= ed)        ok = .false.\n      if (a(2, ed) /= 100 + ed)  ok = .false.\n    end do\n  end subroutine\nend module\nprogram p\n  use m\n  implicit none\n  type(container) :: c\n  integer :: ed\n  logical :: ok\n  allocate(c%idx(2, 10), source=0)\n  do ed = 1, 10\n    c%idx(1:2, ed) = [ed, 100 + ed]\n  end do\n  call sort_check(c%idx, 10, ok)\n  if (.not. ok) error stop 1\n  print *, 'ok'\nend program\n",
28643
+        "f90",
28644
+    );
28645
+    let out = unique_path("alloc_component_to_assumed_size", "bin");
28646
+    let compile = Command::new(compiler("armfortas"))
28647
+        .args([src.to_str().unwrap(), "-o", out.to_str().unwrap()])
28648
+        .output()
28649
+        .expect("alloc-component compile failed to spawn");
28650
+    assert!(
28651
+        compile.status.success(),
28652
+        "alloc-component compile failed: {}",
28653
+        String::from_utf8_lossy(&compile.stderr)
28654
+    );
28655
+    let run = Command::new(&out).output().expect("run failed");
28656
+    assert!(
28657
+        run.status.success() && String::from_utf8_lossy(&run.stdout).contains("ok"),
28658
+        "alloc-component run failed: status={:?} stdout={} stderr={}",
28659
+        run.status,
28660
+        String::from_utf8_lossy(&run.stdout),
28661
+        String::from_utf8_lossy(&run.stderr)
28662
+    );
28663
+    let _ = std::fs::remove_file(&out);
28664
+    let _ = std::fs::remove_file(&src);
28665
+}
28666
+
28626
 #[test]
28667
 #[test]
28627
 fn allocatable_rank2_section_row_assignment_uses_columnmajor_stride() {
28668
 fn allocatable_rank2_section_row_assignment_uses_columnmajor_stride() {
28628
     // F2018 §6.5.3: section assignment to a "row" of a column-major
28669
     // F2018 §6.5.3: section assignment to a "row" of a column-major