diff --git a/flang/runtime/character.cpp b/flang/runtime/character.cpp --- a/flang/runtime/character.cpp +++ b/flang/runtime/character.cpp @@ -477,7 +477,7 @@ std::size_t xChars{x.ElementBytes() >> shift}; std::size_t chars{std::max(accumChars, xChars)}; bool reallocate{accumulator.raw().base_addr == nullptr || - accumChars != xChars || (accumulator.rank() == 0 && x.rank() > 0)}; + accumChars != chars || (accumulator.rank() == 0 && x.rank() > 0)}; int rank{std::max(accumulator.rank(), x.rank())}; for (int j{0}; j < rank; ++j) { lb[j] = 1; diff --git a/flang/unittests/RuntimeGTest/CharacterTest.cpp b/flang/unittests/RuntimeGTest/CharacterTest.cpp --- a/flang/unittests/RuntimeGTest/CharacterTest.cpp +++ b/flang/unittests/RuntimeGTest/CharacterTest.cpp @@ -146,47 +146,45 @@ std::vector x, y, expect; }; +// Helper for creating, allocating and filling up a descriptor with data from +// raw character literals, converted to the CHAR type used by the test. +template +OwningPtr CreateDescriptor(const std::vector &shape, + const std::vector &raw_strings) { + std::size_t length{std::strlen(raw_strings[0])}; + + OwningPtr descriptor{Descriptor::Create(sizeof(CHAR), length, + nullptr, shape.size(), nullptr, CFI_attribute_allocatable)}; + if ((shape.empty() ? descriptor->Allocate() + : descriptor->Allocate( + std::vector(shape.size(), 1).data(), + shape.data())) != 0) { + return nullptr; + } + + std::size_t offset = 0; + for (const char *raw : raw_strings) { + std::basic_string converted{raw, raw + length}; + std::copy(converted.begin(), converted.end(), + descriptor->OffsetElement(offset * length * sizeof(CHAR))); + ++offset; + } + + return descriptor; +} + template void RunExtremumTests(const char *which, std::function function, const std::vector &testCases) { - - // Helper for creating, allocating and filling up a descriptor with data from - // raw character literals, converted to the CHAR type used by the test. - auto CreateDescriptor = [](const std::vector &shape, - const std::vector &raw_strings) - -> OwningPtr { - std::size_t length{std::strlen(raw_strings[0])}; - - OwningPtr descriptor{Descriptor::Create(sizeof(CHAR), length, - nullptr, shape.size(), nullptr, CFI_attribute_allocatable)}; - if ((shape.empty() - ? descriptor->Allocate() - : descriptor->Allocate( - std::vector(shape.size(), 1).data(), - shape.data())) != 0) { - return nullptr; - } - - std::size_t offset = 0; - for (const char *raw : raw_strings) { - std::basic_string converted{raw, raw + length}; - std::copy(converted.begin(), converted.end(), - descriptor->OffsetElement(offset * length * sizeof(CHAR))); - ++offset; - } - - return descriptor; - }; - std::stringstream traceMessage; traceMessage << which << " for CHARACTER(kind=" << sizeof(CHAR) << ")"; SCOPED_TRACE(traceMessage.str()); for (const auto &t : testCases) { - OwningPtr x = CreateDescriptor(t.shape, t.x); - OwningPtr y = CreateDescriptor(t.shape, t.y); + OwningPtr x = CreateDescriptor(t.shape, t.x); + OwningPtr y = CreateDescriptor(t.shape, t.y); ASSERT_NE(x, nullptr); ASSERT_TRUE(x->IsAllocated()); @@ -232,6 +230,27 @@ RunExtremumTests("MAX", RTNAME(CharacterMax), tests); } +template +void RunAllocationTest(const char *xRaw, const char *yRaw) { + OwningPtr x = CreateDescriptor({}, {xRaw}); + OwningPtr y = CreateDescriptor({}, {yRaw}); + + ASSERT_NE(x, nullptr); + ASSERT_TRUE(x->IsAllocated()); + ASSERT_NE(y, nullptr); + ASSERT_TRUE(y->IsAllocated()); + + void *old = x->raw().base_addr; + RTNAME(CharacterMin) + (*x, *y, /* sourceFile = */ nullptr, /* sourceLine = */ 0); + EXPECT_EQ(old, x->raw().base_addr); +} + +TYPED_TEST(ExtremumTests, NoReallocate) { + // Test that we don't reallocate if the accumulator is already large enough. + RunAllocationTest("loooooong", "short"); +} + // Test search functions INDEX(), SCAN(), and VERIFY() template