2 #include "flang/ISO_Fortran_binding_wrapper.h"
3 #include "flang/Runtime/descriptor.h"
4 #include "llvm/Support/raw_ostream.h"
7 using namespace Fortran::runtime
;
8 using namespace Fortran::ISO
;
10 // CFI_CDESC_T test helpers
11 template <int rank
> class Test_CFI_CDESC_T
{
14 ~Test_CFI_CDESC_T() {}
16 // Test CFI_CDESC_T macro defined in section 18.5.4 of F2018 standard
17 // CFI_CDESC_T must give storage that is:
18 using type
= decltype(dvStorage_
);
20 MATCH(false, std::is_const
<type
>::value
);
21 MATCH(false, std::is_volatile
<type
>::value
);
24 MATCH(sizeof(dvStorage_
), Descriptor::SizeInBytes(rank_
, false));
25 } else { // C++ implementation over-allocates for rank=0 by 24bytes.
26 MATCH(true, sizeof(dvStorage_
) >= Descriptor::SizeInBytes(rank_
, false));
28 // suitable in alignment
30 reinterpret_cast<std::uintptr_t>(&dvStorage_
) &
31 (alignof(CFI_cdesc_t
) - 1));
35 static constexpr int rank_
{rank
};
36 CFI_CDESC_T(rank
) dvStorage_
;
39 template <int rank
> static void TestCdescMacroForAllRanksSmallerThan() {
40 static_assert(rank
> 0, "rank<0!");
41 Test_CFI_CDESC_T
<rank
> obj
;
43 TestCdescMacroForAllRanksSmallerThan
<rank
- 1>();
46 template <> void TestCdescMacroForAllRanksSmallerThan
<0>() {
47 Test_CFI_CDESC_T
<0> obj
;
51 // CFI_establish test helper
52 static void AddNoiseToCdesc(CFI_cdesc_t
*dv
, CFI_rank_t rank
) {
53 static const int trap
{0};
55 // This address is not supposed to be used. Any write attempt should trigger
56 // program termination
57 dv
->base_addr
= const_cast<int *>(&trap
);
59 dv
->type
= CFI_type_struct
;
60 dv
->attribute
= CFI_attribute_pointer
;
61 for (int i
{0}; i
< rank
; i
++) {
62 dv
->dim
[i
].extent
= -42;
63 dv
->dim
[i
].lower_bound
= -42;
69 static void DumpTestWorld(const void *bAddr
, CFI_attribute_t attr
,
70 CFI_type_t ty
, std::size_t eLen
, CFI_rank_t rank
,
71 const CFI_index_t
*eAddr
) {
72 llvm::outs() << " base_addr: ";
73 llvm::outs().write_hex(reinterpret_cast<std::intptr_t>(bAddr
))
74 << " attribute: " << static_cast<int>(attr
)
75 << " type: " << static_cast<int>(ty
) << " elem_len: " << eLen
76 << " rank: " << static_cast<int>(rank
) << " extent: ";
77 llvm::outs().write_hex(reinterpret_cast<std::intptr_t>(eAddr
)) << '\n';
82 static void check_CFI_establish(CFI_cdesc_t
*dv
, void *base_addr
,
83 CFI_attribute_t attribute
, CFI_type_t type
, std::size_t elem_len
,
84 CFI_rank_t rank
, const CFI_index_t extents
[]) {
86 DumpTestWorld(base_addr
, attribute
, type
, elem_len
, rank
, extent
);
88 // CFI_establish reqs from F2018 section 18.5.5
90 CFI_establish(dv
, base_addr
, attribute
, type
, elem_len
, rank
, extents
)};
91 Descriptor
*res
{reinterpret_cast<Descriptor
*>(dv
)};
92 if (retCode
== CFI_SUCCESS
) {
94 MATCH((attribute
== CFI_attribute_pointer
), res
->IsPointer());
95 MATCH((attribute
== CFI_attribute_allocatable
), res
->IsAllocatable());
96 MATCH(rank
, res
->rank());
97 MATCH(reinterpret_cast<std::intptr_t>(dv
->base_addr
),
98 reinterpret_cast<std::intptr_t>(base_addr
));
99 MATCH(true, dv
->version
== CFI_VERSION
);
100 if (base_addr
!= nullptr) {
101 MATCH(true, res
->IsContiguous());
102 for (int i
{0}; i
< rank
; ++i
) {
103 MATCH(extents
[i
], res
->GetDimension(i
).Extent());
106 if (attribute
== CFI_attribute_allocatable
) {
107 MATCH(res
->IsAllocated(), false);
109 if (attribute
== CFI_attribute_pointer
) {
110 if (base_addr
!= nullptr) {
111 for (int i
{0}; i
< rank
; ++i
) {
112 MATCH(0, res
->GetDimension(i
).LowerBound());
116 if (type
== CFI_type_struct
|| type
== CFI_type_char
||
117 type
== CFI_type_char16_t
|| type
== CFI_type_char32_t
||
118 type
== CFI_type_other
) {
119 MATCH(elem_len
, res
->ElementBytes());
122 // Checking failure/success according to combination of args forbidden by the
125 int expectedRetCode
{CFI_SUCCESS
};
126 if (base_addr
!= nullptr && attribute
== CFI_attribute_allocatable
) {
128 expectedRetCode
= CFI_ERROR_BASE_ADDR_NOT_NULL
;
130 if (rank
> CFI_MAX_RANK
) {
132 expectedRetCode
= CFI_INVALID_RANK
;
134 if (type
< 0 || type
> CFI_TYPE_LAST
) {
136 expectedRetCode
= CFI_INVALID_TYPE
;
139 if ((type
== CFI_type_struct
|| type
== CFI_type_char
||
140 type
== CFI_type_char16_t
|| type
== CFI_type_char32_t
||
141 type
== CFI_type_other
) &&
144 expectedRetCode
= CFI_INVALID_ELEM_LEN
;
146 if (rank
> 0 && base_addr
!= nullptr && extents
== nullptr) {
148 expectedRetCode
= CFI_INVALID_EXTENT
;
151 MATCH(true, retCode
!= CFI_SUCCESS
);
153 MATCH(retCode
, expectedRetCode
);
157 static void run_CFI_establish_tests() {
158 // Testing CFI_establish defined in section 18.5.5
159 CFI_index_t extents
[CFI_MAX_RANK
];
160 for (int i
{0}; i
< CFI_MAX_RANK
; ++i
) {
163 CFI_CDESC_T(CFI_MAX_RANK
) dv_storage
;
164 CFI_cdesc_t
*dv
{&dv_storage
};
166 void *dummyAddr
{&base
};
168 CFI_attribute_t attrCases
[]{
169 CFI_attribute_pointer
, CFI_attribute_allocatable
, CFI_attribute_other
};
170 CFI_type_t typeCases
[]{CFI_type_int
, CFI_type_struct
, CFI_type_double
,
171 CFI_type_char
, CFI_type_char16_t
, CFI_type_char32_t
, CFI_type_other
,
173 CFI_index_t
*extentCases
[]{extents
, nullptr};
174 void *baseAddrCases
[]{dummyAddr
, nullptr};
175 CFI_rank_t rankCases
[]{0, 1, CFI_MAX_RANK
, CFI_MAX_RANK
+ 1};
176 std::size_t lenCases
[]{0, 42};
178 for (CFI_attribute_t attribute
: attrCases
) {
179 for (void *base_addr
: baseAddrCases
) {
180 for (CFI_index_t
*extent
: extentCases
) {
181 for (CFI_rank_t rank
: rankCases
) {
182 for (CFI_type_t type
: typeCases
) {
183 for (size_t elem_len
: lenCases
) {
184 AddNoiseToCdesc(dv
, CFI_MAX_RANK
);
186 dv
, base_addr
, attribute
, type
, elem_len
, rank
, extent
);
193 // If base_addr is null, extents shall be ignored even if rank !=0
195 CFI_CDESC_T(rank3d
) dv3darrayStorage
;
196 CFI_cdesc_t
*dv_3darray
{&dv3darrayStorage
};
197 AddNoiseToCdesc(dv_3darray
, rank3d
); // => dv_3darray->dim[2].extent = -42
198 check_CFI_establish(dv_3darray
, nullptr, CFI_attribute_other
, CFI_type_int
, 4,
201 dv_3darray
->dim
[2].extent
== 2 + 66); // extents was read
204 static void check_CFI_address(
205 const CFI_cdesc_t
*dv
, const CFI_index_t subscripts
[]) {
207 void *addr
{CFI_address(dv
, subscripts
)};
208 const Descriptor
*desc
{reinterpret_cast<const Descriptor
*>(dv
)};
209 void *addrCheck
{desc
->Element
<void>(subscripts
)};
210 MATCH(true, addr
== addrCheck
);
213 // Helper function to set lower bound of descriptor
214 static void EstablishLowerBounds(CFI_cdesc_t
*dv
, CFI_index_t
*sub
) {
215 for (int i
{0}; i
< dv
->rank
; ++i
) {
216 dv
->dim
[i
].lower_bound
= sub
[i
];
220 // Helper to get size without making internal compiler functions accessible
221 static std::size_t ByteSize(CFI_type_t ty
, std::size_t size
) {
222 CFI_CDESC_T(0) storage
;
223 CFI_cdesc_t
*dv
{&storage
};
225 CFI_establish(dv
, nullptr, CFI_attribute_other
, ty
, size
, 0, nullptr)};
226 return retCode
== CFI_SUCCESS
? dv
->elem_len
: 0;
229 static void run_CFI_address_tests() {
230 // Test CFI_address defined in 18.5.5.2
232 CFI_index_t extents
[CFI_MAX_RANK
];
233 CFI_CDESC_T(CFI_MAX_RANK
) dv_storage
;
234 CFI_cdesc_t
*dv
{&dv_storage
};
236 void *dummyAddr
{&base
};
237 CFI_attribute_t attrCases
[]{
238 CFI_attribute_pointer
, CFI_attribute_allocatable
, CFI_attribute_other
};
239 CFI_type_t validTypeCases
[]{
240 CFI_type_int
, CFI_type_struct
, CFI_type_double
, CFI_type_char
};
241 CFI_index_t subscripts
[CFI_MAX_RANK
];
242 CFI_index_t negativeLowerBounds
[CFI_MAX_RANK
];
243 CFI_index_t zeroLowerBounds
[CFI_MAX_RANK
];
244 CFI_index_t positiveLowerBounds
[CFI_MAX_RANK
];
245 CFI_index_t
*lowerBoundCases
[]{
246 negativeLowerBounds
, zeroLowerBounds
, positiveLowerBounds
};
247 for (int i
{0}; i
< CFI_MAX_RANK
; ++i
) {
248 negativeLowerBounds
[i
] = -1;
249 zeroLowerBounds
[i
] = 0;
250 positiveLowerBounds
[i
] = 1;
252 subscripts
[i
] = i
+ 1;
256 for (CFI_attribute_t attribute
: attrCases
) {
257 for (CFI_type_t type
: validTypeCases
) {
258 CFI_establish(dv
, dummyAddr
, attribute
, type
, 42, 0, nullptr);
259 check_CFI_address(dv
, nullptr);
263 CFI_establish(dv
, dummyAddr
, CFI_attribute_other
, CFI_type_int
, 0,
264 CFI_MAX_RANK
, extents
);
265 for (CFI_index_t
*lowerBounds
: lowerBoundCases
) {
266 EstablishLowerBounds(dv
, lowerBounds
);
267 for (CFI_type_t type
: validTypeCases
) {
268 for (bool contiguous
: {true, false}) {
269 std::size_t size
{ByteSize(type
, 12)};
271 for (int i
{0}; i
< dv
->rank
; ++i
) {
272 dv
->dim
[i
].sm
= size
+ (contiguous
? 0 : dv
->elem_len
);
273 size
= dv
->dim
[i
].sm
* dv
->dim
[i
].extent
;
275 for (CFI_attribute_t attribute
: attrCases
) {
276 dv
->attribute
= attribute
;
277 check_CFI_address(dv
, subscripts
);
282 // Test on an assumed size array.
284 dv
, dummyAddr
, CFI_attribute_other
, CFI_type_int
, 0, 3, extents
);
285 dv
->dim
[2].extent
= -1;
286 check_CFI_address(dv
, subscripts
);
289 static void check_CFI_allocate(CFI_cdesc_t
*dv
,
290 const CFI_index_t lower_bounds
[], const CFI_index_t upper_bounds
[],
291 std::size_t elem_len
) {
293 // Backup descriptor data for future checks
294 const CFI_rank_t rank
{dv
->rank
};
295 const std::size_t desc_elem_len
{dv
->elem_len
};
296 const CFI_attribute_t attribute
{dv
->attribute
};
297 const CFI_type_t type
{dv
->type
};
298 const void *base_addr
{dv
->base_addr
};
299 const int version
{dv
->version
};
301 DumpTestWorld(base_addr
, attribute
, type
, elem_len
, rank
, nullptr);
303 int retCode
{CFI_allocate(dv
, lower_bounds
, upper_bounds
, elem_len
)};
304 Descriptor
*desc
= reinterpret_cast<Descriptor
*>(dv
);
305 if (retCode
== CFI_SUCCESS
) {
306 // check res properties from 18.5.5.3 par 3
307 MATCH(true, dv
->base_addr
!= nullptr);
308 for (int i
{0}; i
< rank
; ++i
) {
309 MATCH(lower_bounds
[i
], dv
->dim
[i
].lower_bound
);
310 MATCH(upper_bounds
[i
], dv
->dim
[i
].extent
+ dv
->dim
[i
].lower_bound
- 1);
312 if (type
== CFI_type_char
) {
313 MATCH(elem_len
, dv
->elem_len
);
315 MATCH(true, desc_elem_len
== dv
->elem_len
);
317 MATCH(true, desc
->IsContiguous());
319 MATCH(true, base_addr
== dv
->base_addr
);
322 // Below dv members shall not be altered by CFI_allocate regardless of
324 MATCH(true, attribute
== dv
->attribute
);
325 MATCH(true, rank
== dv
->rank
);
326 MATCH(true, type
== dv
->type
);
327 MATCH(true, version
== dv
->version
);
329 // Success/failure according to standard
331 int expectedRetCode
{CFI_SUCCESS
};
332 if (rank
> CFI_MAX_RANK
) {
334 expectedRetCode
= CFI_INVALID_RANK
;
336 if (type
< 0 || type
> CFI_TYPE_LAST
) {
338 expectedRetCode
= CFI_INVALID_TYPE
;
340 if (base_addr
!= nullptr && attribute
== CFI_attribute_allocatable
) {
341 // This is less restrictive than 18.5.5.3 arg req for which pointers arg
342 // shall be unassociated. However, this match ALLOCATE behavior
345 expectedRetCode
= CFI_ERROR_BASE_ADDR_NOT_NULL
;
347 if (attribute
!= CFI_attribute_pointer
&&
348 attribute
!= CFI_attribute_allocatable
) {
350 expectedRetCode
= CFI_INVALID_ATTRIBUTE
;
352 if (rank
> 0 && (lower_bounds
== nullptr || upper_bounds
== nullptr)) {
354 expectedRetCode
= CFI_INVALID_EXTENT
;
357 // Memory allocation failures are unpredictable in this test.
358 if (numErr
== 0 && retCode
!= CFI_SUCCESS
) {
359 MATCH(true, retCode
== CFI_ERROR_MEM_ALLOCATION
);
360 } else if (numErr
> 1) {
361 MATCH(true, retCode
!= CFI_SUCCESS
);
363 MATCH(expectedRetCode
, retCode
);
366 if (retCode
== CFI_SUCCESS
) {
371 static void run_CFI_allocate_tests() {
374 CFI_CDESC_T(CFI_MAX_RANK
) dv_storage
;
375 CFI_cdesc_t
*dv
{&dv_storage
};
377 void *dummyAddr
{&base
};
378 CFI_attribute_t attrCases
[]{
379 CFI_attribute_pointer
, CFI_attribute_allocatable
, CFI_attribute_other
};
380 CFI_type_t typeCases
[]{CFI_type_int
, CFI_type_struct
, CFI_type_double
,
381 CFI_type_char
, CFI_type_other
, CFI_TYPE_LAST
+ 1};
382 void *baseAddrCases
[]{dummyAddr
, nullptr};
383 CFI_rank_t rankCases
[]{0, 1, CFI_MAX_RANK
, CFI_MAX_RANK
+ 1};
384 std::size_t lenCases
[]{0, 42};
385 CFI_index_t lb1
[CFI_MAX_RANK
];
386 CFI_index_t ub1
[CFI_MAX_RANK
];
387 for (int i
{0}; i
< CFI_MAX_RANK
; ++i
) {
393 dv
, nullptr, CFI_attribute_other
, CFI_type_int
, 0, 0, nullptr);
394 for (CFI_type_t type
: typeCases
) {
395 std::size_t ty_len
{ByteSize(type
, 12)};
396 for (CFI_attribute_t attribute
: attrCases
) {
397 for (void *base_addr
: baseAddrCases
) {
398 for (CFI_rank_t rank
: rankCases
) {
399 for (size_t elem_len
: lenCases
) {
400 dv
->base_addr
= base_addr
;
402 dv
->attribute
= attribute
;
404 dv
->elem_len
= ty_len
;
405 check_CFI_allocate(dv
, lb1
, ub1
, elem_len
);
413 static void run_CFI_section_tests() {
415 bool testPreConditions
{true};
416 constexpr CFI_index_t m
{5}, n
{6}, o
{7};
417 constexpr CFI_rank_t rank
{3};
418 long long array
[o
][n
][m
]; // Fortran A(m,n,o)
419 long long counter
{1};
421 for (CFI_index_t k
{0}; k
< o
; ++k
) {
422 for (CFI_index_t j
{0}; j
< n
; ++j
) {
423 for (CFI_index_t i
{0}; i
< m
; ++i
) {
424 array
[k
][j
][i
] = counter
++; // Fortran A(i,j,k)
428 CFI_CDESC_T(rank
) sourceStorage
;
429 CFI_cdesc_t
*source
{&sourceStorage
};
430 CFI_index_t extent
[rank
] = {m
, n
, o
};
431 int retCode
{CFI_establish(source
, &array
, CFI_attribute_other
,
432 CFI_type_long_long
, 0, rank
, extent
)};
433 testPreConditions
&= (retCode
== CFI_SUCCESS
);
435 CFI_index_t lb
[rank
] = {2, 5, 4};
436 CFI_index_t ub
[rank
] = {4, 5, 6};
437 CFI_index_t strides
[rank
] = {2, 0, 2};
438 constexpr CFI_rank_t resultRank
{rank
- 1};
440 CFI_CDESC_T(resultRank
) resultStorage
;
441 CFI_cdesc_t
*result
{&resultStorage
};
442 retCode
= CFI_establish(result
, nullptr, CFI_attribute_other
,
443 CFI_type_long_long
, 0, resultRank
, nullptr);
444 testPreConditions
&= (retCode
== CFI_SUCCESS
);
446 if (!testPreConditions
) {
447 MATCH(true, testPreConditions
);
451 retCode
= CFI_section(
452 result
, source
, lb
, ub
, strides
); // Fortran B = A(2:4:2, 5:5:0, 4:6:2)
453 MATCH(true, retCode
== CFI_SUCCESS
);
455 const CFI_index_t lbs0
{source
->dim
[0].lower_bound
};
456 const CFI_index_t lbs1
{source
->dim
[1].lower_bound
};
457 const CFI_index_t lbs2
{source
->dim
[2].lower_bound
};
459 CFI_index_t resJ
{result
->dim
[1].lower_bound
};
460 for (CFI_index_t k
{lb
[2]}; k
<= ub
[2]; k
+= strides
[2]) {
461 for (CFI_index_t j
{lb
[1]}; j
<= ub
[1]; j
+= strides
[1] ? strides
[1] : 1) {
462 CFI_index_t resI
{result
->dim
[0].lower_bound
};
463 for (CFI_index_t i
{lb
[0]}; i
<= ub
[0]; i
+= strides
[0]) {
464 // check A(i,j,k) == B(resI, resJ) == array[k-1][j-1][i-1]
465 const CFI_index_t resSubcripts
[]{resI
, resJ
};
466 const CFI_index_t srcSubcripts
[]{i
, j
, k
};
468 CFI_address(source
, srcSubcripts
) ==
469 CFI_address(result
, resSubcripts
));
471 CFI_address(source
, srcSubcripts
) ==
472 &array
[k
- lbs2
][j
- lbs1
][i
- lbs0
]);
482 retCode
= CFI_section(
483 result
, source
, lb
, ub
, strides
); // Fortran B = A(4:2:-1, 5:5:0, 4:6:2)
484 MATCH(true, retCode
== CFI_SUCCESS
);
486 resJ
= result
->dim
[1].lower_bound
;
487 for (CFI_index_t k
{lb
[2]}; k
<= ub
[2]; k
+= strides
[2]) {
488 for (CFI_index_t j
{lb
[1]}; j
<= ub
[1]; j
+= 1) {
489 CFI_index_t resI
{result
->dim
[1].lower_bound
+ result
->dim
[0].extent
- 1};
490 for (CFI_index_t i
{2}; i
<= 4; ++i
) {
491 // check A(i,j,k) == B(resI, resJ) == array[k-1][j-1][i-1]
492 const CFI_index_t resSubcripts
[]{resI
, resJ
};
493 const CFI_index_t srcSubcripts
[]{i
, j
, k
};
495 CFI_address(source
, srcSubcripts
) ==
496 CFI_address(result
, resSubcripts
));
498 CFI_address(source
, srcSubcripts
) ==
499 &array
[k
- lbs2
][j
- lbs1
][i
- lbs0
]);
507 static void run_CFI_select_part_tests() {
508 constexpr std::size_t name_len
{5};
515 const CFI_rank_t rank
{2};
516 constexpr CFI_index_t universeSize
[]{2, 3};
517 Galaxy universe
[universeSize
[1]][universeSize
[0]];
519 for (int i
{0}; i
< universeSize
[1]; ++i
) {
520 for (int j
{0}; j
< universeSize
[0]; ++j
) {
521 // Initializing Fortran var universe(j,i)
522 universe
[i
][j
].distance
= j
+ i
* 32;
523 universe
[i
][j
].stars
= j
* 2 + i
* 64;
524 universe
[i
][j
].name
[2] = static_cast<char>(j
);
525 universe
[i
][j
].name
[3] = static_cast<char>(i
);
529 CFI_CDESC_T(rank
) resStorage
, srcStorage
;
530 CFI_cdesc_t
*result
{&resStorage
};
531 CFI_cdesc_t
*source
{&srcStorage
};
533 bool testPreConditions
{true};
534 int retCode
{CFI_establish(result
, nullptr, CFI_attribute_other
, CFI_type_int
,
535 sizeof(int), rank
, nullptr)};
536 testPreConditions
&= (retCode
== CFI_SUCCESS
);
537 retCode
= CFI_establish(source
, &universe
, CFI_attribute_other
,
538 CFI_type_struct
, sizeof(Galaxy
), rank
, universeSize
);
539 testPreConditions
&= (retCode
== CFI_SUCCESS
);
540 if (!testPreConditions
) {
541 MATCH(true, testPreConditions
);
545 std::size_t displacement
{offsetof(Galaxy
, stars
)};
546 std::size_t elem_len
{0}; // ignored
547 retCode
= CFI_select_part(result
, source
, displacement
, elem_len
);
548 MATCH(CFI_SUCCESS
, retCode
);
550 bool baseAddrShiftedOk
{
551 static_cast<char *>(source
->base_addr
) + displacement
==
553 MATCH(true, baseAddrShiftedOk
);
554 if (!baseAddrShiftedOk
) {
558 MATCH(sizeof(int), result
->elem_len
);
559 for (CFI_index_t j
{0}; j
< universeSize
[1]; ++j
) {
560 for (CFI_index_t i
{0}; i
< universeSize
[0]; ++i
) {
561 CFI_index_t subscripts
[]{
562 result
->dim
[0].lower_bound
+ i
, result
->dim
[1].lower_bound
+ j
};
564 i
* 2 + j
* 64, *static_cast<int *>(CFI_address(result
, subscripts
)));
568 // Test for Fortran character type
569 retCode
= CFI_establish(
570 result
, nullptr, CFI_attribute_other
, CFI_type_char
, 2, rank
, nullptr);
571 testPreConditions
&= (retCode
== CFI_SUCCESS
);
572 if (!testPreConditions
) {
573 MATCH(true, testPreConditions
);
577 displacement
= offsetof(Galaxy
, name
) + 2;
578 elem_len
= 2; // not ignored this time
579 retCode
= CFI_select_part(result
, source
, displacement
, elem_len
);
580 MATCH(CFI_SUCCESS
, retCode
);
582 baseAddrShiftedOk
= static_cast<char *>(source
->base_addr
) + displacement
==
584 MATCH(true, baseAddrShiftedOk
);
585 if (!baseAddrShiftedOk
) {
589 MATCH(elem_len
, result
->elem_len
);
590 for (CFI_index_t j
{0}; j
< universeSize
[1]; ++j
) {
591 for (CFI_index_t i
{0}; i
< universeSize
[0]; ++i
) {
592 CFI_index_t subscripts
[]{
593 result
->dim
[0].lower_bound
+ i
, result
->dim
[1].lower_bound
+ j
};
594 MATCH(static_cast<char>(i
),
595 static_cast<char *>(CFI_address(result
, subscripts
))[0]);
596 MATCH(static_cast<char>(j
),
597 static_cast<char *>(CFI_address(result
, subscripts
))[1]);
602 static void run_CFI_setpointer_tests() {
603 constexpr CFI_rank_t rank
{3};
604 CFI_CDESC_T(rank
) resStorage
, srcStorage
;
605 CFI_cdesc_t
*result
{&resStorage
};
606 CFI_cdesc_t
*source
{&srcStorage
};
607 CFI_index_t lower_bounds
[rank
];
608 CFI_index_t extents
[rank
];
609 for (int i
{0}; i
< rank
; ++i
) {
615 char *dummyBaseAddress
{&target
};
616 bool testPreConditions
{true};
617 CFI_type_t type
{CFI_type_int
};
618 std::size_t elem_len
{ByteSize(type
, 42)};
619 int retCode
{CFI_establish(
620 result
, nullptr, CFI_attribute_pointer
, type
, elem_len
, rank
, nullptr)};
621 testPreConditions
&= (retCode
== CFI_SUCCESS
);
622 retCode
= CFI_establish(source
, dummyBaseAddress
, CFI_attribute_other
, type
,
623 elem_len
, rank
, extents
);
624 testPreConditions
&= (retCode
== CFI_SUCCESS
);
625 if (!testPreConditions
) {
626 MATCH(true, testPreConditions
);
630 retCode
= CFI_setpointer(result
, source
, lower_bounds
);
631 MATCH(CFI_SUCCESS
, retCode
);
633 // The following members must be invariant
634 MATCH(rank
, result
->rank
);
635 MATCH(elem_len
, result
->elem_len
);
636 MATCH(type
, result
->type
);
637 // check pointer association
638 MATCH(true, result
->base_addr
== source
->base_addr
);
639 for (int j
{0}; j
< rank
; ++j
) {
640 MATCH(source
->dim
[j
].extent
, result
->dim
[j
].extent
);
641 MATCH(source
->dim
[j
].sm
, result
->dim
[j
].sm
);
642 MATCH(lower_bounds
[j
], result
->dim
[j
].lower_bound
);
647 TestCdescMacroForAllRanksSmallerThan
<CFI_MAX_RANK
>();
648 run_CFI_establish_tests();
649 run_CFI_address_tests();
650 run_CFI_allocate_tests();
651 // TODO: test CFI_deallocate
652 // TODO: test CFI_is_contiguous
653 run_CFI_section_tests();
654 run_CFI_select_part_tests();
655 run_CFI_setpointer_tests();
656 return testing::Complete();