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}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits