REPRODUCIBILITY: 100%
OS VERSION: 5.1.0.7
HARDWARE: -
UI LANGUAGE: -
REGRESSION: Yes
DESCRIPTION:
Qt 5 moc in the Sailfish OS 5.1 build environment appears to misparse C++14 digit separators in integer literals inside an included C++ header. After parsing such a construct inside namespace absl, moc incorrectly believes the following QObject class is also inside namespace absl.
This causes moc to generate invalid code such as:
void absl::AbslMocTest::qt_static_metacall(...)
even though AbslMocTest is declared in the global namespace.
The normal C++ compiler accepts the code. The failure is specific to moc-generated code.
This was originally found when including S2Geometry/Abseil headers from a header containing Q_OBJECT. The include chain reached absl/hash/internal/hash.h, where this construct exists:
static constexpr uint64_t kStaticRandomData[] = {
0x243f'6a88'85a3'08d3,
...
};
Guarding the include from moc with #ifndef Q_MOC_RUN avoids the problem.
For some reason, in earlier SFOS versions this error wasn’t triggered.
PRECONDITIONS:
A Sailfish OS 5.1 Qt 5 build environment with qmake/moc.
A Qt/QML application with a QObject-derived C++ class processed by moc.
STEPS TO REPRODUCE:
STEPS TO REPRODUCE:
- Create a header included before a
QObjectclass processed by moc, e.g.minerror.h:
#ifndef MINERROR_H
#define MINERROR_H
namespace absl {
class MinimalMocTrigger
{
enum : unsigned long long {
kValue = 0x243f'6a88'85a3'08d3
};
};
} // namespace absl
#endif // MINERROR_H
- Include it from a header containing a global
QObjectclass:
#include <QObject>
#include "minerror.h"
class AbslMocTest : public QObject
{
Q_OBJECT
public:
explicit AbslMocTest(QObject *parent = nullptr);
};
- Add the header to qmake
HEADERSso moc processes it and build the project.
EXPECTED RESULT:
Compiled and working code
ACTUAL RESULT:
moc generates code as if the class were inside namespace absl:
moc_abslmoctest.cpp:55:12: error: 'absl::AbslMocTest' has not been declared
55 | void absl::AbslMocTest::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
| ^~~~~~~~~~~
moc_abslmoctest.cpp:63:25: error: 'absl::AbslMocTest' has not been declared
63 | const QMetaObject absl::AbslMocTest::staticMetaObject = {
| ^~~~~~~~~~~
moc_abslmoctest.cpp:69:26: error: 'absl::AbslMocTest' has not been declared
69 | const QMetaObject *absl::AbslMocTest::metaObject() const
| ^~~~~~~~~~~
moc_abslmoctest.cpp:69:52: error: non-member function 'const QMetaObject* metaObject()' cannot have cv-qualifier
69 | const QMetaObject *absl::AbslMocTest::metaObject() const
| ^~~~~
moc_abslmoctest.cpp: In function 'const QMetaObject* metaObject()':
moc_abslmoctest.cpp:71:21: error: 'QScopedPointer<QObjectData> QObject::d_ptr' is protected within this context
71 | return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
| ^~~~~
If the digit separators are removed (0x243f6a8885a308d3ULL) then the project compiles.
Likewise, wrapping the problematic real-world include with:
#ifndef Q_MOC_RUN
#include "s2/mutable_s2shape_index.h"
#endif
also avoids the problem.
MODIFICATIONS:
None. Was observed initially in Pure Maps and OSM Scout Server code
ADDITIONAL INFORMATION:
This bug has been triggered by code importing abseil headers. I have tracked it to /usr/include/absl/hash/internal/hash.h .