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