Bug 70816 - bogus error __builtin_strcmp is not a constant expression in a constexpr function
Summary: bogus error __builtin_strcmp is not a constant expression in a constexpr func...
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 6.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: rejects-valid
Depends on:
Blocks: constexpr
  Show dependency treegraph
 
Reported: 2016-04-27 01:51 UTC by Martin Sebor
Modified: 2022-09-08 16:35 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail: 5.3.0, 6.1.0, 7.0
Last reconfirmed: 2016-06-08 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Martin Sebor 2016-04-27 01:51:06 UTC
G++ accepts most calls to __builtin_strcmp with constant arguments in constexpr contexts, except when the intrinsic is invoked on local arrays defined in a constexpr function.  The test case below shows a number of accepted calls along with the one that's incorrectly rejected.

$ cat u.c && /home/msebor/build/gcc-trunk-git/gcc/xgcc -B/home/msebor/build/gcc-trunk-git/gcc -Wall -Wextra -Wpedantic -xc++ u.c
constexpr int f0 ()
{
  return __builtin_strcmp ("a", "b");
}

constexpr int f1 ()
{
  const char a [] = "a";
  const char b [] = "b";
  return __builtin_strcmp (a, b);
}

constexpr int f2 (const char *a, const char *b)
{
  int d = 0;
  do {
    d = *b - *a;
  } while (*a++ && *b++);
  return d;
}

constexpr int f3 ()
{
  const char s [] = "a";
  const char t [] = "b";

  const char *a = s;
  const char *b = t;

  int d = 0;
  do {
    d = *b - *a;
  } while (*a++ && *b++);
  return d;
}

constexpr char a [] = "a";
constexpr char b [] = "b";

constexpr int i0 = __builtin_strcmp ("a", "b");
constexpr int i1 = __builtin_strcmp (a, b);
constexpr int i2 = f1 ();
constexpr int i3 = f2 (a, b);
constexpr int i4 = f3 ();

u.c:42:23:   in constexpr expansion of ‘f1()’
u.c:10:27: error: ‘__builtin_strcmp(((const char*)(& a)), ((const char*)(& b)))’ is not a constant expression
   return __builtin_strcmp (a, b);
          ~~~~~~~~~~~~~~~~~^~~~~~
Comment 1 Martin Sebor 2016-06-08 02:39:11 UTC
The same limitation affects other string builtins such as __builtin_strlen or __builtin_strchr.

$ cat cst.C && /home/msebor/build/gcc-6-branch/gcc/xgcc -B/home/msebor/build/gcc-6-branch/gcc -S -Wall -Wextra -Wpedantic cst.C -fdump-tree-optimized=/dev/stdout -o/dev/stdout
constexpr int chr (int c)
{
  const char a[] = "123";
  return __builtin_strchr (a, c) - a;
}

constexpr int i = chr ('3');

constexpr int cmp (const char *a)
{
  const char b[] = "123";
  return __builtin_strcmp (a, b);
}

constexpr int j = cmp ("345");

constexpr unsigned len ()
{
  const char s[] = "123";
  return __builtin_strlen (s);
}

constexpr unsigned n = len ();
	.file	"cst.C"
cst.C:7:23:   in constexpr expansion of ‘chr(51)’
cst.C:4:27: error: ‘__builtin_strchr(((const char*)(& a)), 51)’ is not a constant expression
   return __builtin_strchr (a, c) - a;
          ~~~~~~~~~~~~~~~~~^~~~~~
cst.C:15:23:   in constexpr expansion of ‘cmp(((const char*)"345"))’
cst.C:12:27: error: ‘__builtin_strcmp(((const char*)"345"), ((const char*)(& b)))’ is not a constant expression
   return __builtin_strcmp (a, b);
          ~~~~~~~~~~~~~~~~~^~~~~~
cst.C:23:28:   in constexpr expansion of ‘len()’
cst.C:20:27: error: ‘__builtin_strlen(((const char*)(& s)))’ is not a constant expression
   return __builtin_strlen (s);
          ~~~~~~~~~~~~~~~~~^~~
Comment 2 Arthur O'Dwyer 2021-03-14 21:15:19 UTC
Confirmed, I'm also seeing this in C++20 mode. This affects libc++'s
 `char_traits<char>::length(const char *)`.

Example test case: https://godbolt.org/z/MTq1ex
Comment 3 Louis Dionne 2021-12-15 22:16:30 UTC
We are having to add a workaround in libc++ to implement constexpr std::string: https://reviews.llvm.org/D115795

It would be awesome if this could be fixed! (if so, please drop us a line and we'll remove our workaround)
Comment 4 Jonathan Wakely 2021-12-15 23:50:11 UTC
Our std::char_traits has similar branches for constant evaluation (and the rest of the library does too for memcpy etc.)
Comment 5 Martin Sebor 2022-01-26 17:08:30 UTC
I'm not working on this anymore.