r330656 - [AST] strcmp/memcmp always compares unsigned chars.

Benjamin Kramer via cfe-commits cfe-commits at lists.llvm.org
Mon Apr 23 15:04:34 PDT 2018


Author: d0k
Date: Mon Apr 23 15:04:34 2018
New Revision: 330656

URL: http://llvm.org/viewvc/llvm-project?rev=330656&view=rev
Log:
[AST] strcmp/memcmp always compares unsigned chars.

This makes it return the right result in a couple of edge cases. The
wide versions always do the comparison on the underlying wchar_t type.

Modified:
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/test/SemaCXX/constexpr-string.cpp

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=330656&r1=330655&r2=330656&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Mon Apr 23 15:04:34 2018
@@ -8046,14 +8046,24 @@ bool IntExprEvaluator::VisitBuiltinCallE
                        BuiltinOp != Builtin::BIwmemcmp &&
                        BuiltinOp != Builtin::BI__builtin_memcmp &&
                        BuiltinOp != Builtin::BI__builtin_wmemcmp);
+    bool IsWide = BuiltinOp == Builtin::BIwcscmp ||
+                  BuiltinOp == Builtin::BIwcsncmp ||
+                  BuiltinOp == Builtin::BIwmemcmp ||
+                  BuiltinOp == Builtin::BI__builtin_wcscmp ||
+                  BuiltinOp == Builtin::BI__builtin_wcsncmp ||
+                  BuiltinOp == Builtin::BI__builtin_wmemcmp;
     for (; MaxLength; --MaxLength) {
       APValue Char1, Char2;
       if (!handleLValueToRValueConversion(Info, E, CharTy, String1, Char1) ||
           !handleLValueToRValueConversion(Info, E, CharTy, String2, Char2) ||
           !Char1.isInt() || !Char2.isInt())
         return false;
-      if (Char1.getInt() != Char2.getInt())
-        return Success(Char1.getInt() < Char2.getInt() ? -1 : 1, E);
+      if (Char1.getInt() != Char2.getInt()) {
+        if (IsWide) // wmemcmp compares with wchar_t signedness.
+          return Success(Char1.getInt() < Char2.getInt() ? -1 : 1, E);
+        // memcmp always compares unsigned chars.
+        return Success(Char1.getInt().ult(Char2.getInt()) ? -1 : 1, E);
+      }
       if (StopAtNull && !Char1.getInt())
         return Success(0, E);
       assert(!(StopAtNull && !Char2.getInt()));

Modified: cfe/trunk/test/SemaCXX/constexpr-string.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constexpr-string.cpp?rev=330656&r1=330655&r2=330656&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constexpr-string.cpp (original)
+++ cfe/trunk/test/SemaCXX/constexpr-string.cpp Mon Apr 23 15:04:34 2018
@@ -53,6 +53,8 @@ namespace StrcmpEtc {
   static_assert(__builtin_strcmp("abab", "abaa") == 1);
   static_assert(__builtin_strcmp("ababa", "abab") == 1);
   static_assert(__builtin_strcmp("abab", "ababa") == -1);
+  static_assert(__builtin_strcmp("a\203", "a") == 1);
+  static_assert(__builtin_strcmp("a\203", "a\003") == 1);
   static_assert(__builtin_strcmp("abab\0banana", "abab") == 0);
   static_assert(__builtin_strcmp("abab", "abab\0banana") == 0);
   static_assert(__builtin_strcmp("abab\0banana", "abab\0canada") == 0);
@@ -78,6 +80,8 @@ namespace StrcmpEtc {
 
   static_assert(__builtin_memcmp("abaa", "abba", 3) == -1);
   static_assert(__builtin_memcmp("abaa", "abba", 2) == 0);
+  static_assert(__builtin_memcmp("a\203", "a", 2) == 1);
+  static_assert(__builtin_memcmp("a\203", "a\003", 2) == 1);
   static_assert(__builtin_memcmp(0, 0, 0) == 0);
   static_assert(__builtin_memcmp("abab\0banana", "abab\0banana", 100) == 0); // expected-error {{not an integral constant}} expected-note {{dereferenced one-past-the-end}}
   static_assert(__builtin_memcmp("abab\0banana", "abab\0canada", 100) == -1); // FIXME: Should we reject this?
@@ -102,6 +106,9 @@ namespace WcscmpEtc {
   static_assert(__builtin_wcscmp(L"abab\0banana", L"abab") == 0);
   static_assert(__builtin_wcscmp(L"abab", L"abab\0banana") == 0);
   static_assert(__builtin_wcscmp(L"abab\0banana", L"abab\0canada") == 0);
+#if __WCHAR_WIDTH__ == 32
+  static_assert(__builtin_wcscmp(L"a\x83838383", L"a") == -1);
+#endif
   static_assert(__builtin_wcscmp(0, L"abab") == 0); // expected-error {{not an integral constant}} expected-note {{dereferenced null}}
   static_assert(__builtin_wcscmp(L"abab", 0) == 0); // expected-error {{not an integral constant}} expected-note {{dereferenced null}}
 
@@ -116,6 +123,9 @@ namespace WcscmpEtc {
   static_assert(__builtin_wcsncmp(L"abaa", L"abba", 0) == 0);
   static_assert(__builtin_wcsncmp(0, 0, 0) == 0);
   static_assert(__builtin_wcsncmp(L"abab\0banana", L"abab\0canada", 100) == 0);
+#if __WCHAR_WIDTH__ == 32
+  static_assert(__builtin_wcsncmp(L"a\x83838383", L"aa", 2) == -1);
+#endif
 
   static_assert(__builtin_wcsncmp(kFoobar, kFoobazfoobar, 6) == -1);
   static_assert(__builtin_wcsncmp(kFoobar, kFoobazfoobar, 7) == -1); // FIXME: Should we reject this?
@@ -125,6 +135,9 @@ namespace WcscmpEtc {
   static_assert(__builtin_wmemcmp(L"abaa", L"abba", 3) == -1);
   static_assert(__builtin_wmemcmp(L"abaa", L"abba", 2) == 0);
   static_assert(__builtin_wmemcmp(0, 0, 0) == 0);
+#if __WCHAR_WIDTH__ == 32
+  static_assert(__builtin_wmemcmp(L"a\x83838383", L"aa", 2) == -1);
+#endif
   static_assert(__builtin_wmemcmp(L"abab\0banana", L"abab\0banana", 100) == 0); // expected-error {{not an integral constant}} expected-note {{dereferenced one-past-the-end}}
   static_assert(__builtin_wmemcmp(L"abab\0banana", L"abab\0canada", 100) == -1); // FIXME: Should we reject this?
   static_assert(__builtin_wmemcmp(L"abab\0banana", L"abab\0canada", 7) == -1);




More information about the cfe-commits mailing list