From 7f24db01751da6953782630bb42dcca8a111590b Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Sun, 5 Apr 2020 15:23:53 -0700 Subject: [PATCH] Add documentation and testing for 2c88a485c71155c19e512f22c54e63ee337282a3. Also extend it to cover memchr for consistency. --- clang/docs/LanguageExtensions.rst | 4 ++-- clang/lib/AST/ExprConstant.cpp | 2 +- clang/test/SemaCXX/constexpr-string.cpp | 25 +++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 6dcfd1a..f83d7cf 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -2368,8 +2368,8 @@ constant expressions in C++11 onwards (where a cast from ``void*`` to ``char*`` is disallowed in general). Constant evaluation support for the ``__builtin_mem*`` functions is provided -only for arrays of ``char``, ``signed char``, or ``unsigned char``, despite -these functions accepting an argument of type ``const void*``. +only for arrays of ``char``, ``signed char``, ``unsigned char``, or ``char8_t``, +despite these functions accepting an argument of type ``const void*``. Support for constant expression evaluation for the above builtins can be detected with ``__has_feature(cxx_constexpr_string_builtins)``. diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 7508bcb..a10a4da 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -8469,7 +8469,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, } // Give up on byte-oriented matching against multibyte elements. // FIXME: We can compare the bytes in the correct order. - if (IsRawByte && !CharTy->isCharType()) { + if (IsRawByte && !CharTy->isCharType() && !CharTy->isChar8Type()) { Info.FFDiag(E, diag::note_constexpr_memchr_unsupported) << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'") << CharTy; diff --git a/clang/test/SemaCXX/constexpr-string.cpp b/clang/test/SemaCXX/constexpr-string.cpp index 79ac3bf..b9f90ad 100644 --- a/clang/test/SemaCXX/constexpr-string.cpp +++ b/clang/test/SemaCXX/constexpr-string.cpp @@ -107,6 +107,17 @@ namespace StrcmpEtc { static_assert(__builtin_memcmp("abab\0banana", "abab\0canada", 6) == -1); static_assert(__builtin_memcmp("abab\0banana", "abab\0canada", 5) == 0); + static_assert(__builtin_memcmp(u8"abaa", u8"abba", 3) == -1); + static_assert(__builtin_memcmp(u8"abaa", u8"abba", 2) == 0); + static_assert(__builtin_memcmp(u8"a\203", u8"a", 2) == 1); + static_assert(__builtin_memcmp(u8"a\203", u8"a\003", 2) == 1); + static_assert(__builtin_memcmp(0, 0, 0) == 0); + static_assert(__builtin_memcmp(u8"abab\0banana", u8"abab\0banana", 100) == 0); // expected-error {{not an integral constant}} expected-note {{dereferenced one-past-the-end}} + static_assert(__builtin_memcmp(u8"abab\0banana", u8"abab\0canada", 100) == -1); // FIXME: Should we reject this? + static_assert(__builtin_memcmp(u8"abab\0banana", u8"abab\0canada", 7) == -1); + static_assert(__builtin_memcmp(u8"abab\0banana", u8"abab\0canada", 6) == -1); + static_assert(__builtin_memcmp(u8"abab\0banana", u8"abab\0canada", 5) == 0); + static_assert(__builtin_bcmp("abaa", "abba", 3) != 0); static_assert(__builtin_bcmp("abaa", "abba", 2) == 0); static_assert(__builtin_bcmp("a\203", "a", 2) != 0); @@ -373,6 +384,20 @@ namespace StrchrEtc { static_assert(__builtin_memchr(nullptr, 'x', 3) == nullptr); // expected-error {{not an integral constant}} expected-note {{dereferenced null}} static_assert(__builtin_memchr(nullptr, 'x', 0) == nullptr); // FIXME: Should we reject this? + constexpr const char8_t *kU8Str = u8"abca\xff\0d"; + constexpr char8_t kU8Foo[] = {u8'f', u8'o', u8'o'}; + static_assert(__builtin_memchr(kU8Str, u8'a', 0) == nullptr); + static_assert(__builtin_memchr(kU8Str, u8'a', 1) == kU8Str); + static_assert(__builtin_memchr(kU8Str, u8'\0', 5) == nullptr); + static_assert(__builtin_memchr(kU8Str, u8'\0', 6) == kU8Str + 5); + static_assert(__builtin_memchr(kU8Str, u8'\xff', 8) == kU8Str + 4); + static_assert(__builtin_memchr(kU8Str, u8'\xff' + 256, 8) == kU8Str + 4); + static_assert(__builtin_memchr(kU8Str, u8'\xff' - 256, 8) == kU8Str + 4); + static_assert(__builtin_memchr(kU8Foo, u8'x', 3) == nullptr); + static_assert(__builtin_memchr(kU8Foo, u8'x', 4) == nullptr); // expected-error {{not an integral constant}} expected-note {{dereferenced one-past-the-end}} + static_assert(__builtin_memchr(nullptr, u8'x', 3) == nullptr); // expected-error {{not an integral constant}} expected-note {{dereferenced null}} + static_assert(__builtin_memchr(nullptr, u8'x', 0) == nullptr); // FIXME: Should we reject this? + extern struct Incomplete incomplete; static_assert(__builtin_memchr(&incomplete, 0, 0u) == nullptr); static_assert(__builtin_memchr(&incomplete, 0, 1u) == nullptr); // expected-error {{not an integral constant}} expected-note {{read of incomplete type 'struct Incomplete'}} -- 2.7.4