Problem with __builtin_strlen among compilers

Hi, I’m using libc++ with gcc and have met a problem with code below:

#include <string_view>

constexpr bool test() {

const char s1 = “mave”;

std::string_view s2(s1);

return true;

}

int main() {

static_assert(test());

}

Error message was:

$ g++ -nostdinc++ -I/home/yiyan/.local/include/c++/v1 -nodefaultlibs -lc++ -lc++abi -lm -lc -lgcc_s -lgcc -std=c++17 --compile -o /dev/null 1.cc

1.cc: In function ‘int main()’:

1.cc:8:23: error: non-constant condition for static assertion

8 | static_assert(test());

In file included from /home/yiyan/.local/include/c++/v1/string_view:175,

from 1.cc:1:

1.cc:8:23: in ‘constexpr’ expansion of ‘test()’

1.cc:4:27: in ‘constexpr’ expansion of ‘s2.std::__1::basic_string_view::basic_string_view(((const char*)(& s1)))’

/home/yiyan/.local/include/c++/v1/string_view:238:46: in ‘constexpr’ expansion of ‘std::__1::char_traits::length(__s)’

/home/yiyan/.local/include/c++/v1/__string:217:69: error: ‘__builtin_strlen(((const char*)(& s1)))’ is not a constant expression

217 | length(const char_type* __s) _NOEXCEPT {return __builtin_strlen(__s);}

Looks like the root cause is that __builtin_strlen is not constexpr in gcc.

Do you consider to fix this kind of issue?

Best,

Yichen

I think the most productive way of resolving this issue is to file a bug against GCC asking them to make __builtin_strlen constexpr.

Alternatively, libc++ could also use `if (std::is_constant_evaluated())` to pick between __builtin_strlen and a naive version, but that won't fix your problem when compiling in C++17 mode because is_constant_evaluated() is (will be) C++20.

Louis

Hi, I’m using libc++ with gcc and have met a problem with code below:

Hmmm… I think __builtin_strlen is constexpr on gcc.

Looking at a more minimal case:

int main() { static_assert(!__builtin_strlen(“”)); }

It compiles fine under:

gcc 9.2, libstdc++

/usr/local/gcc/bin/g+±9 -std=c++17 a.cpp

clang 8, libc++

/usr/local/clang/bin/clang++ -std=c++17 a.cpp

gcc 9.2, libc++
/usr/local/gcc/bin/g+±9 -nostdinc++ -I /usr/local/clang/include/c++/v1 -nodefaultlibs -lc++ -lc++abi -lm -lc -lgcc -std=c++17 a.cpp

#include <string_view>

constexpr bool test() {

const char s1 = “mave”;

std::string_view s2(s1);

return true;

}

int main() {

static_assert(test());

}

This compiles fine under both gcc 9.2 libstdc++ and clang 8 libc++, but as you point out fails under gcc 9.2 libc++.

I got a little bit confused trying to get a repro of __builtin_strlen in libc++ with gcc.

At least the behavior of __builtin_strlen is different in clang and gcc.

This passed

g++ -o /dev/null -std=c++17 --compile test2.cc

while this failed

clang++ -o /dev/null -std=c++17 --compile test2.cc

with error messages:

test2.cc:6:19: error: static_assert expression is not an integral constant expression

static_assert(!test(s));

^~~~~~~~

test2.cc:3:12: note: read of non-constexpr variable ‘s’ is not allowed in a constant expression

return __builtin_strlen(s);

^

test2.cc:6:20: note: in call to ‘test(&s[0])’

static_assert(!test(s));

^

1 error generated.

For one same file:

const char s = “”;

constexpr int test(const char* s) {

return __builtin_strlen(s);

}

constexpr void __main() {

static_assert(!test(s));

}

“__builtin_strlen” works with GCC 7.x and up and clang 6.x and up. Here is a Godbolt: https://godbolt.org/z/G9NpAX

I think __builtin_strlen is a red herring here. This just seems like a general issue with GCC’s constexpr implementation of strings.

Well, sure.
The global variable s is not constexpr in your example.

– Marshall