Compiling following program on any gcc version, with C++14 or newer standard fails with "'__builtin_strlen(...)' is not a constant expression" for some of the static asserts. It compiles successfuly on clang. g++ -std=c++14 constexpr unsigned constexpr_strlen(const char* str) { #ifdef WORKAROUND if (!__builtin_constant_p(str)) { unsigned i = 0; while (str[i] != '\0') { ++i; } return i; } #endif return __builtin_strlen(str); } struct StaticString { constexpr StaticString(const char (&src)[4]) : buf{src[0], src[1], src[2], src[3]} {} constexpr const char* data() const { return &buf[0]; } char buf[4]; }; constexpr StaticString createStaticString() { return {"foo"}; } constexpr const char *s1 = "foo"; constexpr const char s2[] = "foo"; constexpr StaticString s3{"foo"}; constexpr StaticString s4 = s2; constexpr StaticString s5 = s4; constexpr StaticString s6 = createStaticString(); void test() { constexpr const char *s7 = "foo"; constexpr const char s8[] = "foo"; constexpr StaticString s9{"foo"}; constexpr StaticString s10 = s8; constexpr StaticString s11 = s10; constexpr StaticString s12 = createStaticString(); static constexpr const char *s13 = "foo"; static constexpr const char s14[] = "foo"; static constexpr StaticString s15{"foo"}; static constexpr StaticString s16 = s14; static constexpr StaticString s17 = s6; static constexpr StaticString s18 = createStaticString(); static_assert(constexpr_strlen(s1) == 3, ""); static_assert(constexpr_strlen(s2) == 3, ""); static_assert(constexpr_strlen(s3.data()) == 3, ""); static_assert(constexpr_strlen(s4.data()) == 3, ""); // ERROR static_assert(constexpr_strlen(s5.data()) == 3, ""); // ERROR static_assert(constexpr_strlen(s6.data()) == 3, ""); // ERROR static_assert(constexpr_strlen(s7) == 3, ""); static_assert(constexpr_strlen(s8) == 3, ""); // ERROR static_assert(constexpr_strlen(s9.data()) == 3, ""); // ERROR static_assert(constexpr_strlen(s10.data()) == 3, ""); // ERROR static_assert(constexpr_strlen(s11.data()) == 3, ""); // ERROR static_assert(constexpr_strlen(s12.data()) == 3, ""); // ERROR static_assert(constexpr_strlen(s13) == 3, ""); static_assert(constexpr_strlen(s14) == 3, ""); static_assert(constexpr_strlen(s15.data()) == 3, ""); static_assert(constexpr_strlen(s16.data()) == 3, ""); // ERROR static_assert(constexpr_strlen(s17.data()) == 3, ""); // ERROR static_assert(constexpr_strlen(s18.data()) == 3, ""); // ERROR }
You can either use char_traits<char>::length (which is actually required to work in constexpr) or use __builtin_is_constant_evaluated() instead of your workaround.
__builtin_strlen like many other string/memory builtins simply tries the middle-end folding and gives up otherwise. So if it is called on a string literal, it is folded, but if it would require reading the bytes of the string one by one, it will most likely fail. This has been discussed in some other PR that we should have a helper that allows constexpr.cc to read a single character and as fallback for the string builtins call those in a loop and essentially evaluate the builtins as a non-optimized trivial C++ implementation of those builtins. I think std::strlen isn't constexpr even in latest C++, so all of this is permitted by the standard...
(In reply to Jakub Jelinek from comment #2) > I think std::strlen isn't constexpr even in latest C++, so all of this is > permitted by the standard... Right, which is why I recommend using char_traits::length instead.
*** Bug 119866 has been marked as a duplicate of this bug. ***