[flang-commits] [flang] 5112bd6 - [flang] Fix a bug in the character runtime

Diana Picus via flang-commits flang-commits at lists.llvm.org
Mon May 3 01:17:35 PDT 2021


Author: Diana Picus
Date: 2021-05-03T08:08:08Z
New Revision: 5112bd6b6e10b27b81aa83cfdbe3588973a6f1f5

URL: https://github.com/llvm/llvm-project/commit/5112bd6b6e10b27b81aa83cfdbe3588973a6f1f5
DIFF: https://github.com/llvm/llvm-project/commit/5112bd6b6e10b27b81aa83cfdbe3588973a6f1f5.diff

LOG: [flang] Fix a bug in the character runtime

The number of bytes copied in CopyAndPad should depend on the size of
the type being copied, not on its shift value (which in the case of char
is 0, leading to no bytes at all being copied).

Add unit tests for CharacterMin and CharacterMax, which exercise this
code path.

Differential Revision: https://reviews.llvm.org/D101355

Added: 
    

Modified: 
    flang/runtime/character.cpp
    flang/unittests/RuntimeGTest/CharacterTest.cpp

Removed: 
    


################################################################################
diff  --git a/flang/runtime/character.cpp b/flang/runtime/character.cpp
index 3b383bb29ea5c..ed8e5f4984f8b 100644
--- a/flang/runtime/character.cpp
+++ b/flang/runtime/character.cpp
@@ -456,9 +456,9 @@ static void CopyAndPad(
       to[j] = static_cast<TO>(' ');
     }
   } else if (toChars <= fromChars) {
-    std::memcpy(to, from, toChars * shift<TO>);
+    std::memcpy(to, from, toChars * sizeof(TO));
   } else {
-    std::memcpy(to, from, fromChars * shift<TO>);
+    std::memcpy(to, from, fromChars * sizeof(TO));
     for (std::size_t j{fromChars}; j < toChars; ++j) {
       to[j] = static_cast<TO>(' ');
     }

diff  --git a/flang/unittests/RuntimeGTest/CharacterTest.cpp b/flang/unittests/RuntimeGTest/CharacterTest.cpp
index 6afba32e33e35..458a7fd3c8864 100644
--- a/flang/unittests/RuntimeGTest/CharacterTest.cpp
+++ b/flang/unittests/RuntimeGTest/CharacterTest.cpp
@@ -10,6 +10,7 @@
 // in Fortran.
 
 #include "../../runtime/character.h"
+#include "../../runtime/descriptor.h"
 #include "gtest/gtest.h"
 #include <cstring>
 #include <functional>
@@ -134,11 +135,79 @@ TYPED_TEST(CharacterComparisonTests, CompareCharacters) {
     std::memcpy(buf[0], x, xBytes);
     std::memcpy(buf[1], y, yBytes);
     ASSERT_EQ(cmp, expect) << "compare '" << x << "'(" << xBytes << ") to '"
-                           << y << "'(" << yBytes << "), got " << cmp
+                           << y << "'(" << yBytes << "'), got " << cmp
                            << ", should be " << expect << '\n';
   }
 }
 
+// Test MIN() and MAX()
+struct ExtremumTestCase {
+  const char *x, *y, *expect;
+};
+
+template <typename CHAR>
+void RunExtremumTests(const char *which,
+    std::function<void(Descriptor &, const Descriptor &, const char *, int)>
+        function,
+    const std::vector<ExtremumTestCase> &testCases) {
+
+  // Helper for creating, allocating and filling up a descriptor with data from
+  // a raw character literal, converted to the CHAR type used by the test.
+  auto CreateDescriptor = [](const char *raw) -> OwningPtr<Descriptor> {
+    std::size_t length{std::strlen(raw)};
+    std::basic_string<CHAR> converted{raw, raw + length};
+
+    OwningPtr<Descriptor> descriptor{Descriptor::Create(
+        sizeof(CHAR), length, nullptr, 0, nullptr, CFI_attribute_allocatable)};
+    if (descriptor->Allocate() != 0) {
+      return nullptr;
+    }
+
+    std::copy(
+        converted.begin(), converted.end(), descriptor->OffsetElement<CHAR>());
+
+    return descriptor;
+  };
+
+  for (const auto &t : testCases) {
+    OwningPtr<Descriptor> x = CreateDescriptor(t.x);
+    OwningPtr<Descriptor> y = CreateDescriptor(t.y);
+
+    ASSERT_NE(x, nullptr);
+    ASSERT_TRUE(x->IsAllocated());
+    ASSERT_NE(y, nullptr);
+    ASSERT_TRUE(y->IsAllocated());
+    function(*x, *y, nullptr, 0);
+
+    std::basic_string<CHAR> got{
+        x->OffsetElement<CHAR>(), x->ElementBytes() / sizeof(CHAR)};
+    std::basic_string<CHAR> expect{t.expect, t.expect + std::strlen(t.expect)};
+    EXPECT_EQ(expect, got) << which << "('" << t.x << "','" << t.y
+                           << "') for CHARACTER(kind=" << sizeof(CHAR) << ")";
+  }
+}
+
+template <typename CHAR> struct ExtremumTests : public ::testing::Test {};
+TYPED_TEST_CASE(ExtremumTests, CharacterTypes);
+
+TYPED_TEST(ExtremumTests, MinTests) {
+  static std::vector<ExtremumTestCase> tests{
+      {"a", "z", "a"},
+      {"zaaa", "aa", "aa  "},
+      {"aaz", "aaaaa", "aaaaa"},
+  };
+  RunExtremumTests<TypeParam>("MIN", RTNAME(CharacterMin), tests);
+}
+
+TYPED_TEST(ExtremumTests, MaxTests) {
+  static std::vector<ExtremumTestCase> tests{
+      {"a", "z", "z"},
+      {"zaa", "aaaaa", "zaa  "},
+      {"aaaaa", "aazaa", "aazaa"},
+  };
+  RunExtremumTests<TypeParam>("MAX", RTNAME(CharacterMax), tests);
+}
+
 // Test search functions INDEX(), SCAN(), and VERIFY()
 
 template <typename CHAR>


        


More information about the flang-commits mailing list