https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127693
Bug ID: 127693
Summary: [13/14/15/16/17] Miscompilation: __builtin_constant_p
branch removed then still apparently used
Product: gcc
Version: 16.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: ipa
Assignee: unassigned at gcc dot gnu.org
Reporter: thiago at kde dot org
Target Milestone: ---
Reference: https://qt-project.atlassian.net/browse/QTBUG-151050
Note: I used an AI to help me narrow down the QtCore crash to the reproducers
below, which I have reviewed for validity.
The following I am sure of:
Qt reproducer:
#include <QtCore/qstringview.h>
#include <cstdio>
// Reduced from NumericPattern::Scanner in
qtbase/src/corelib/time/qtimezoneprivate.cpp
struct Scanner
{
QStringView given;
int scanForToken(QStringView sought)
{
const qsizetype n = sought.size();
qsizetype idx = -n;
int tokensMatched = 0;
while ((idx = given.indexOf(sought, idx + n)) >= 0)
++tokensMatched;
return tokensMatched;
}
Q_NEVER_INLINE int scanForSigns()
{
return scanForToken(u"\u2212"); // Canonical minus sign
}
};
int main()
{
Scanner scanner{ u"1\u22122\u22123" };
std::printf("%d\n", scanner.scanForSigns()); // expected: 2
}
C-only reproducer:
struct SV { long m_size; };
long findString(long from, struct SV needle);
long findChar(long from);
static long indexOf(struct SV s, long from)
{
if (__builtin_constant_p(s.m_size) && s.m_size == 1)
return findChar(from);
return findString(from, s);
}
static int scan(struct SV sought)
{
long n = sought.m_size;
long idx = -n;
int matched = 0;
while ((idx = indexOf(sought, idx + n)) >= 0)
++matched;
return matched;
}
int f(void) { return scan((struct SV){1}); }
The Qt reproducer appears to work with GCC 13 and 14. The C-only reproducer
fails with all these versions:
* 13.5.0
* 14.4.0
* 15.3.0
* 16.2.0
* 17 as of today, Git commit 3b60e2204e225ea643fe54a999848f99d49a6659
The program has no UB: f() should loop calling findChar() or findString()
(either is ok but the intent is that one is selected at compile time) until it
returns a negative value. Clang 23 compiled f() to a function calling
findChar(), as expected.
Instead, under -O2 (and only -O2), this C reproducer appears to replace the
entire function with a __builtin_unreachable(). GCC 13-15 then just emit
nothing (no ret), so a call ends up at whatever is next in the executable. GCC
16 and 17 emit an ud2 on x86-64.
This was made worse by Qt recently adding a few [[assume]] calls. Now the Qt
reproducer fails with -O3 too.
It *looks* like -ftree-vrp is the culprit: without it (with -fno-tree-vrp), the
generated code is calling findChar() as expected.