159 lines · cpp
1//===-- unittests/Runtime/ArrayConstructor.cpp ------------------*- C++ -*-===//2//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "tools.h"10#include "gtest/gtest.h"11#include "flang-rt/runtime/array-constructor.h"12#include "flang-rt/runtime/descriptor.h"13#include "flang-rt/runtime/type-code.h"14#include "flang/Runtime/allocatable.h"15#include "flang/Runtime/cpp-type.h"16 17#include <memory>18 19using namespace Fortran::runtime;20using Fortran::common::TypeCategory;21 22TEST(ArrayConstructor, Basic) {23 // X(4) = [1,2,3,4]24 // Y(2:3,4:6) = RESHAPE([5,6,7,8,9,10], shape=[2,3])25 //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);33 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);41 42 // Case 1: result is a temp and extent is unknown before first call.43 result.GetDimension(0).SetBounds(1, 0);44 45 RTNAME(InitArrayConstructorVector)46 (*acVector, result, /*useValueLengthParameters=*/false);47 for (std::int32_t i{0}; i <= 99; ++i) {48 RTNAME(PushArrayConstructorSimpleScalar)(*acVector, &i);49 RTNAME(PushArrayConstructorValue)(*acVector, *x);50 RTNAME(PushArrayConstructorValue)(*acVector, *y);51 }52 53 ASSERT_TRUE(result.IsAllocated());54 ASSERT_EQ(result.Elements(), static_cast<std::size_t>(100 * (1 + 4 + 2 * 3)));55 SubscriptValue subscript[1]{1};56 for (std::int32_t i{0}; i <= 99; ++i) {57 ASSERT_EQ(*result.Element<std::int32_t>(subscript), i);58 ++subscript[0];59 for (std::int32_t j{1}; j <= 10; ++j) {60 EXPECT_EQ(*result.Element<std::int32_t>(subscript), j);61 ++subscript[0];62 }63 }64 EXPECT_LE(result.Elements(),65 static_cast<std::size_t>(acVector->actualAllocationSize));66 result.Deallocate();67 ASSERT_TRUE(!result.IsAllocated());68 69 // Case 2: result is an unallocated temp and extent is know before first call.70 // and is allocated when the first value is pushed.71 result.GetDimension(0).SetBounds(1, 1234);72 RTNAME(InitArrayConstructorVector)73 (*acVector, result, /*useValueLengthParameters=*/false);74 EXPECT_EQ(0, acVector->actualAllocationSize);75 std::int32_t i{42};76 RTNAME(PushArrayConstructorSimpleScalar)(*acVector, &i);77 ASSERT_TRUE(result.IsAllocated());78 EXPECT_EQ(1234, acVector->actualAllocationSize);79 result.Deallocate();80 81 cookieAllocator.deallocate(acVector, 1);82}83 84TEST(ArrayConstructor, Character) {85 // CHARACTER(2) :: C = "12"86 // X(4) = ["ab", "cd", "ef", "gh"]87 // Y(2:3,4:6) = RESHAPE(["ij", "jl", "mn", "op", "qr","st"], shape=[2,3])88 auto x{MakeArray<TypeCategory::Character, 1>(std::vector<int>{4},89 std::vector<std::string>{"ab", "cd", "ef", "gh"}, 2)};90 auto y{MakeArray<TypeCategory::Character, 1>(std::vector<int>{2, 3},91 std::vector<std::string>{"ij", "kl", "mn", "op", "qr", "st"}, 2)};92 y->GetDimension(0).SetBounds(2, 3);93 y->GetDimension(1).SetBounds(4, 6);94 auto c{MakeArray<TypeCategory::Character, 1>(95 std::vector<int>{}, std::vector<std::string>{"12"}, 2)};96 97 StaticDescriptor<1, false> statDesc;98 Descriptor &result{statDesc.descriptor()};99 result.Establish(TypeCode{CFI_type_char}, 0, /*p=*/nullptr,100 /*rank=*/1, /*extents=*/nullptr, CFI_attribute_allocatable);101 std::allocator<ArrayConstructorVector> cookieAllocator;102 ArrayConstructorVector *acVector{cookieAllocator.allocate(1)};103 ASSERT_TRUE(acVector);104 105 // Case 1: result is a temp and extent and length are unknown before the first106 // call. Test creation of: [(C, X, Y, i=1,10,1)]107 static constexpr std::size_t expectedElements{10 * (1 + 4 + 2 * 3)};108 result.GetDimension(0).SetBounds(1, 0);109 RTNAME(InitArrayConstructorVector)110 (*acVector, result, /*useValueLengthParameters=*/true);111 for (std::int32_t i{1}; i <= 10; ++i) {112 RTNAME(PushArrayConstructorValue)(*acVector, *c);113 RTNAME(PushArrayConstructorValue)(*acVector, *x);114 RTNAME(PushArrayConstructorValue)(*acVector, *y);115 }116 ASSERT_TRUE(result.IsAllocated());117 ASSERT_EQ(result.Elements(), expectedElements);118 ASSERT_EQ(result.ElementBytes(), 2u);119 EXPECT_LE(result.Elements(),120 static_cast<std::size_t>(acVector->actualAllocationSize));121 std::string CXY{"12abcdefghijklmnopqrst"};122 std::string expect;123 for (int i{0}; i < 10; ++i)124 expect.append(CXY);125 EXPECT_EQ(std::memcmp(126 result.OffsetElement<char>(0), expect.data(), expect.length()),127 0);128 result.Deallocate();129 cookieAllocator.deallocate(acVector, 1);130 x->Deallocate();131 y->Deallocate();132 c->Deallocate();133}134 135TEST(ArrayConstructor, CharacterRuntimeCheck) {136 // CHARACTER(2) :: C2137 // CHARACTER(3) :: C3138 // Test the runtime catch bad [C2, C3] array constructors (Fortran 2018 7.8139 // point 2.)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);151 152 result.GetDimension(0).SetBounds(1, 0);153 RTNAME(InitArrayConstructorVector)154 (*acVector, result, /*useValueLengthParameters=*/true);155 RTNAME(PushArrayConstructorValue)(*acVector, *c2);156 ASSERT_DEATH(RTNAME(PushArrayConstructorValue)(*acVector, *c3),157 "Array constructor: mismatched character lengths");158}159