1 //===-- flang/unittests/Runtime/ArrayConstructor.cpp-------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "gtest/gtest.h"
11 #include "flang/Runtime/allocatable.h"
12 #include "flang/Runtime/array-constructor.h"
13 #include "flang/Runtime/cpp-type.h"
14 #include "flang/Runtime/descriptor.h"
15 #include "flang/Runtime/type-code.h"
19 using namespace Fortran::runtime
;
20 using Fortran::common::TypeCategory
;
22 TEST(ArrayConstructor
, Basic
) {
24 // Y(2:3,4:6) = RESHAPE([5,6,7,8,9,10], shape=[2,3])
26 // Test creation of: [(i, X, Y, i=0,99,1)]
27 auto x
{MakeArray
<TypeCategory::Integer
, 4>(
28 std::vector
<int>{4}, std::vector
<std::int32_t>{1, 2, 3, 4})};
29 auto y
{MakeArray
<TypeCategory::Integer
, 4>(
30 std::vector
<int>{2, 3}, std::vector
<std::int32_t>{5, 6, 7, 8, 9, 10})};
31 y
->GetDimension(0).SetBounds(2, 3);
32 y
->GetDimension(1).SetBounds(4, 6);
34 StaticDescriptor
<1, false> statDesc
;
35 Descriptor
&result
{statDesc
.descriptor()};
36 result
.Establish(TypeCode
{CFI_type_int32_t
}, 4, /*p=*/nullptr,
37 /*rank=*/1, /*extents=*/nullptr, CFI_attribute_allocatable
);
38 std::allocator
<ArrayConstructorVector
> cookieAllocator
;
39 ArrayConstructorVector
*acVector
{cookieAllocator
.allocate(1)};
40 ASSERT_TRUE(acVector
);
42 // Case 1: result is a temp and extent is unknown before first call.
43 result
.GetDimension(0).SetBounds(1, 0);
45 RTNAME(InitArrayConstructorVector
)
46 (*acVector
, result
, /*useValueLengthParameters=*/false,
47 /*vectorClassSize=*/sizeof(ArrayConstructorVector
));
48 for (std::int32_t i
{0}; i
<= 99; ++i
) {
49 RTNAME(PushArrayConstructorSimpleScalar
)(*acVector
, &i
);
50 RTNAME(PushArrayConstructorValue
)(*acVector
, *x
);
51 RTNAME(PushArrayConstructorValue
)(*acVector
, *y
);
54 ASSERT_TRUE(result
.IsAllocated());
55 ASSERT_EQ(result
.Elements(), static_cast<std::size_t>(100 * (1 + 4 + 2 * 3)));
56 SubscriptValue subscript
[1]{1};
57 for (std::int32_t i
{0}; i
<= 99; ++i
) {
58 ASSERT_EQ(*result
.Element
<std::int32_t>(subscript
), i
);
60 for (std::int32_t j
{1}; j
<= 10; ++j
) {
61 EXPECT_EQ(*result
.Element
<std::int32_t>(subscript
), j
);
65 EXPECT_LE(result
.Elements(),
66 static_cast<std::size_t>(acVector
->actualAllocationSize
));
68 ASSERT_TRUE(!result
.IsAllocated());
70 // Case 2: result is an unallocated temp and extent is know before first call.
71 // and is allocated when the first value is pushed.
72 result
.GetDimension(0).SetBounds(1, 1234);
73 RTNAME(InitArrayConstructorVector
)
74 (*acVector
, result
, /*useValueLengthParameters=*/false,
75 /*vectorClassSize=*/sizeof(ArrayConstructorVector
));
76 EXPECT_EQ(0, acVector
->actualAllocationSize
);
78 RTNAME(PushArrayConstructorSimpleScalar
)(*acVector
, &i
);
79 ASSERT_TRUE(result
.IsAllocated());
80 EXPECT_EQ(1234, acVector
->actualAllocationSize
);
83 cookieAllocator
.deallocate(acVector
, 1);
86 TEST(ArrayConstructor
, Character
) {
87 // CHARACTER(2) :: C = "12"
88 // X(4) = ["ab", "cd", "ef", "gh"]
89 // Y(2:3,4:6) = RESHAPE(["ij", "jl", "mn", "op", "qr","st"], shape=[2,3])
90 auto x
{MakeArray
<TypeCategory::Character
, 1>(std::vector
<int>{4},
91 std::vector
<std::string
>{"ab", "cd", "ef", "gh"}, 2)};
92 auto y
{MakeArray
<TypeCategory::Character
, 1>(std::vector
<int>{2, 3},
93 std::vector
<std::string
>{"ij", "kl", "mn", "op", "qr", "st"}, 2)};
94 y
->GetDimension(0).SetBounds(2, 3);
95 y
->GetDimension(1).SetBounds(4, 6);
96 auto c
{MakeArray
<TypeCategory::Character
, 1>(
97 std::vector
<int>{}, std::vector
<std::string
>{"12"}, 2)};
99 StaticDescriptor
<1, false> statDesc
;
100 Descriptor
&result
{statDesc
.descriptor()};
101 result
.Establish(TypeCode
{CFI_type_char
}, 0, /*p=*/nullptr,
102 /*rank=*/1, /*extents=*/nullptr, CFI_attribute_allocatable
);
103 std::allocator
<ArrayConstructorVector
> cookieAllocator
;
104 ArrayConstructorVector
*acVector
{cookieAllocator
.allocate(1)};
105 ASSERT_TRUE(acVector
);
107 // Case 1: result is a temp and extent and length are unknown before the first
108 // call. Test creation of: [(C, X, Y, i=1,10,1)]
109 static constexpr std::size_t expectedElements
{10 * (1 + 4 + 2 * 3)};
110 result
.GetDimension(0).SetBounds(1, 0);
111 RTNAME(InitArrayConstructorVector
)
112 (*acVector
, result
, /*useValueLengthParameters=*/true,
113 /*vectorClassSize=*/sizeof(ArrayConstructorVector
));
114 for (std::int32_t i
{1}; i
<= 10; ++i
) {
115 RTNAME(PushArrayConstructorValue
)(*acVector
, *c
);
116 RTNAME(PushArrayConstructorValue
)(*acVector
, *x
);
117 RTNAME(PushArrayConstructorValue
)(*acVector
, *y
);
119 ASSERT_TRUE(result
.IsAllocated());
120 ASSERT_EQ(result
.Elements(), expectedElements
);
121 ASSERT_EQ(result
.ElementBytes(), 2u);
122 EXPECT_LE(result
.Elements(),
123 static_cast<std::size_t>(acVector
->actualAllocationSize
));
124 std::string CXY
{"12abcdefghijklmnopqrst"};
126 for (int i
{0}; i
< 10; ++i
)
128 EXPECT_EQ(std::memcmp(
129 result
.OffsetElement
<char>(0), expect
.data(), expect
.length()),
132 cookieAllocator
.deallocate(acVector
, 1);
135 TEST(ArrayConstructor
, CharacterRuntimeCheck
) {
136 // CHARACTER(2) :: C2
137 // CHARACTER(3) :: C3
138 // Test the runtime catch bad [C2, C3] array constructors (Fortran 2018 7.8
140 auto c2
{MakeArray
<TypeCategory::Character
, 1>(
141 std::vector
<int>{}, std::vector
<std::string
>{"ab"}, 2)};
142 auto c3
{MakeArray
<TypeCategory::Character
, 1>(
143 std::vector
<int>{}, std::vector
<std::string
>{"abc"}, 3)};
144 StaticDescriptor
<1, false> statDesc
;
145 Descriptor
&result
{statDesc
.descriptor()};
146 result
.Establish(TypeCode
{CFI_type_char
}, 0, /*p=*/nullptr,
147 /*rank=*/1, /*extents=*/nullptr, CFI_attribute_allocatable
);
148 std::allocator
<ArrayConstructorVector
> cookieAllocator
;
149 ArrayConstructorVector
*acVector
{cookieAllocator
.allocate(1)};
150 ASSERT_TRUE(acVector
);
152 result
.GetDimension(0).SetBounds(1, 0);
153 RTNAME(InitArrayConstructorVector
)
154 (*acVector
, result
, /*useValueLengthParameters=*/true,
155 /*vectorClassSize=*/sizeof(ArrayConstructorVector
));
156 RTNAME(PushArrayConstructorValue
)(*acVector
, *c2
);
157 ASSERT_DEATH(RTNAME(PushArrayConstructorValue
)(*acVector
, *c3
),
158 "Array constructor: mismatched character lengths");