r286678 - [c++1z] Add constant-folding support for strcmp, strncmp, and memcmp, to

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Fri Nov 11 15:43:35 PST 2016


Author: rsmith
Date: Fri Nov 11 17:43:35 2016
New Revision: 286678

URL: http://llvm.org/viewvc/llvm-project?rev=286678&view=rev
Log:
[c++1z] Add constant-folding support for strcmp, strncmp, and memcmp, to
support constexpr char_traits.

Added:
    cfe/trunk/test/SemaCXX/constexpr-string.cpp
      - copied, changed from r286401, cfe/trunk/test/SemaCXX/constexpr-strlen.cpp
Removed:
    cfe/trunk/test/SemaCXX/constexpr-strlen.cpp
Modified:
    cfe/trunk/lib/AST/ExprConstant.cpp

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=286678&r1=286677&r2=286678&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Fri Nov 11 17:43:35 2016
@@ -7078,6 +7078,56 @@ bool IntExprEvaluator::VisitCallExpr(con
     }
   }
 
+  case Builtin::BIstrcmp:
+  case Builtin::BIstrncmp:
+  case Builtin::BImemcmp:
+    // A call to strlen is not a constant expression.
+    if (Info.getLangOpts().CPlusPlus11)
+      Info.CCEDiag(E, diag::note_constexpr_invalid_function)
+        << /*isConstexpr*/0 << /*isConstructor*/0
+        << (BuiltinOp == Builtin::BIstrncmp ? "'strncmp'" :
+            BuiltinOp == Builtin::BImemcmp ? "'memcmp'" :
+            "'strcmp'");
+    else
+      Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
+    // Fall through.
+  case Builtin::BI__builtin_strcmp:
+  case Builtin::BI__builtin_strncmp:
+  case Builtin::BI__builtin_memcmp: {
+    LValue String1, String2;
+    if (!EvaluatePointer(E->getArg(0), String1, Info) ||
+        !EvaluatePointer(E->getArg(1), String2, Info))
+      return false;
+    uint64_t MaxLength = uint64_t(-1);
+    if (BuiltinOp != Builtin::BIstrcmp &&
+        BuiltinOp != Builtin::BI__builtin_strcmp) {
+      APSInt N;
+      if (!EvaluateInteger(E->getArg(2), N, Info))
+        return false;
+      MaxLength = N.getExtValue();
+    }
+    bool StopAtNull = (BuiltinOp != Builtin::BImemcmp &&
+                       BuiltinOp != Builtin::BI__builtin_memcmp);
+    QualType CharTy = E->getArg(0)->getType()->getPointeeType();
+    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 (StopAtNull && !Char1.getInt())
+        return Success(0, E);
+      assert(!(StopAtNull && !Char2.getInt()));
+      if (!HandleLValueArrayAdjustment(Info, E, String1, CharTy, 1) ||
+          !HandleLValueArrayAdjustment(Info, E, String2, CharTy, 1))
+        return false;
+    }
+    // We hit the strncmp / memcmp limit.
+    return Success(0, E);
+  }
+
   case Builtin::BI__atomic_always_lock_free:
   case Builtin::BI__atomic_is_lock_free:
   case Builtin::BI__c11_atomic_is_lock_free: {

Copied: cfe/trunk/test/SemaCXX/constexpr-string.cpp (from r286401, cfe/trunk/test/SemaCXX/constexpr-strlen.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constexpr-string.cpp?p2=cfe/trunk/test/SemaCXX/constexpr-string.cpp&p1=cfe/trunk/test/SemaCXX/constexpr-strlen.cpp&r1=286401&r2=286678&rev=286678&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constexpr-strlen.cpp (original)
+++ cfe/trunk/test/SemaCXX/constexpr-string.cpp Fri Nov 11 17:43:35 2016
@@ -1,15 +1,68 @@
-// RUN: %clang_cc1 %s -std=c++11 -fsyntax-only -verify -pedantic
+// RUN: %clang_cc1 %s -std=c++1z -fsyntax-only -verify -pedantic
 
-# 1 "/usr/include/string.h" 1 3 4
+# 4 "/usr/include/string.h" 1 3 4
 extern "C" {
   typedef decltype(sizeof(int)) size_t;
+
   extern size_t strlen(const char *p);
+
+  extern int strcmp(const char *s1, const char *s2);
+  extern int strncmp(const char *s1, const char *s2, size_t n);
+  extern int memcmp(const char *s1, const char *s2, size_t n); // expected-note {{here}}
+}
+
+# 15 "SemaCXX/constexpr-string.cpp" 2
+namespace Strlen {
+  constexpr int n = __builtin_strlen("hello"); // ok
+  constexpr int m = strlen("hello"); // expected-error {{constant expression}} expected-note {{non-constexpr function 'strlen' cannot be used in a constant expression}}
+
+  // Make sure we can evaluate a call to strlen.
+  int arr[3]; // expected-note {{here}}
+  int k = arr[strlen("hello")]; // expected-warning {{array index 5}}
 }
 
-# 10 "SemaCXX/constexpr-strlen.cpp" 2
-constexpr int n = __builtin_strlen("hello"); // ok
-constexpr int m = strlen("hello"); // expected-error {{constant expression}} expected-note {{non-constexpr function 'strlen' cannot be used in a constant expression}}
-
-// Make sure we can evaluate a call to strlen.
-int arr[3]; // expected-note {{here}}
-int k = arr[strlen("hello")]; // expected-warning {{array index 5}}
+namespace StrcmpEtc {
+  constexpr char kFoobar[6] = {'f','o','o','b','a','r'};
+  constexpr char kFoobazfoobar[12] = {'f','o','o','b','a','z','f','o','o','b','a','r'};
+
+  static_assert(__builtin_strcmp("abab", "abab") == 0);
+  static_assert(__builtin_strcmp("abab", "abba") == -1);
+  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("abab\0banana", "abab") == 0);
+  static_assert(__builtin_strcmp("abab", "abab\0banana") == 0);
+  static_assert(__builtin_strcmp("abab\0banana", "abab\0canada") == 0);
+  static_assert(__builtin_strcmp(0, "abab") == 0); // expected-error {{not an integral constant}} expected-note {{dereferenced null}}
+  static_assert(__builtin_strcmp("abab", 0) == 0); // expected-error {{not an integral constant}} expected-note {{dereferenced null}}
+
+  static_assert(__builtin_strcmp(kFoobar, kFoobazfoobar) == -1); // FIXME: Should we reject this?
+  static_assert(__builtin_strcmp(kFoobar, kFoobazfoobar + 6) == 0); // expected-error {{not an integral constant}} expected-note {{dereferenced one-past-the-end}}
+
+  static_assert(__builtin_strncmp("abaa", "abba", 5) == -1);
+  static_assert(__builtin_strncmp("abaa", "abba", 4) == -1);
+  static_assert(__builtin_strncmp("abaa", "abba", 3) == -1);
+  static_assert(__builtin_strncmp("abaa", "abba", 2) == 0);
+  static_assert(__builtin_strncmp("abaa", "abba", 1) == 0);
+  static_assert(__builtin_strncmp("abaa", "abba", 0) == 0);
+  static_assert(__builtin_strncmp(0, 0, 0) == 0);
+  static_assert(__builtin_strncmp("abab\0banana", "abab\0canada", 100) == 0);
+
+  static_assert(__builtin_strncmp(kFoobar, kFoobazfoobar, 6) == -1);
+  static_assert(__builtin_strncmp(kFoobar, kFoobazfoobar, 7) == -1); // FIXME: Should we reject this?
+  static_assert(__builtin_strncmp(kFoobar, kFoobazfoobar + 6, 6) == 0);
+  static_assert(__builtin_strncmp(kFoobar, kFoobazfoobar + 6, 7) == 0); // expected-error {{not an integral constant}} expected-note {{dereferenced one-past-the-end}}
+
+  static_assert(__builtin_memcmp("abaa", "abba", 3) == -1);
+  static_assert(__builtin_memcmp("abaa", "abba", 2) == 0);
+  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?
+  static_assert(__builtin_memcmp("abab\0banana", "abab\0canada", 7) == -1);
+  static_assert(__builtin_memcmp("abab\0banana", "abab\0canada", 6) == -1);
+  static_assert(__builtin_memcmp("abab\0banana", "abab\0canada", 5) == 0);
+
+  constexpr int a = strcmp("hello", "world"); // expected-error {{constant expression}} expected-note {{non-constexpr function 'strcmp' cannot be used in a constant expression}}
+  constexpr int b = strncmp("hello", "world", 3); // expected-error {{constant expression}} expected-note {{non-constexpr function 'strncmp' cannot be used in a constant expression}}
+  constexpr int c = memcmp("hello", "world", 3); // expected-error {{constant expression}} expected-note {{non-constexpr function 'memcmp' cannot be used in a constant expression}}
+}

Removed: cfe/trunk/test/SemaCXX/constexpr-strlen.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constexpr-strlen.cpp?rev=286677&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/constexpr-strlen.cpp (original)
+++ cfe/trunk/test/SemaCXX/constexpr-strlen.cpp (removed)
@@ -1,15 +0,0 @@
-// RUN: %clang_cc1 %s -std=c++11 -fsyntax-only -verify -pedantic
-
-# 1 "/usr/include/string.h" 1 3 4
-extern "C" {
-  typedef decltype(sizeof(int)) size_t;
-  extern size_t strlen(const char *p);
-}
-
-# 10 "SemaCXX/constexpr-strlen.cpp" 2
-constexpr int n = __builtin_strlen("hello"); // ok
-constexpr int m = strlen("hello"); // expected-error {{constant expression}} expected-note {{non-constexpr function 'strlen' cannot be used in a constant expression}}
-
-// Make sure we can evaluate a call to strlen.
-int arr[3]; // expected-note {{here}}
-int k = arr[strlen("hello")]; // expected-warning {{array index 5}}




More information about the cfe-commits mailing list