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