moc: use C++ constexpr to generate the meta object string data
This avoids having to rely on moc precalculating everything and getting
its sums right, as the main integer table only has a string index
(unlike my original 5.0 plan which would have stored the offset).
For example, for:
struct Object : QObject { Q_OBJECT signals: void changed(const QVariant &v); }
moc now generates:
struct qt_meta_stringdata_Object_t {};
static constexpr auto qt_meta_stringdata_Object = QtMocHelpers::stringData(
"Object",
"foobar",
"",
"v"
);
Notes on the implementation:
* the old code is retained because we need moc 6.5 to generate code
compatible with QtCore 6.2-6.4. It's marked for removal in Qt 6.9.
* the struct qt_meta_stringdata_%s_t remains because we need a
TU-specific type for QtPrivate::is_complete (via
qt_incomplete_metaTypeArray). This can be cleaned up.
* after this change, GDB complains while loading QtCore:
warning: internal error: string "StringData<long sequence of numbers>" failed to be canonicalized
but debugging does not appear to be impacted. It's just annoying
because it shows up when QtTest detects a crash too.
Change-Id: Id0fb9ab0089845ee8843fffd16f9d5493e9bd708
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
bb10
parent
c23b595769
commit
7ceba9c472
|
|
@ -23,6 +23,59 @@
|
|||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace QtMocHelpers {
|
||||
template <uint... Nx> struct StringData
|
||||
{
|
||||
static constexpr size_t calculateStringSize()
|
||||
{
|
||||
// same as:
|
||||
// return (0 + ... + Nx);
|
||||
// but not using the fold expression to avoid exceeding compiler limits
|
||||
size_t total = 0;
|
||||
uint sizes[] = { Nx... };
|
||||
for (uint n : sizes)
|
||||
total += n;
|
||||
return total;
|
||||
}
|
||||
|
||||
// The maximum Size of a string literal is 2 GB on 32-bit and 4 GB on 64-bit
|
||||
// (but the compiler is likely to give up before you get anywhere near that much)
|
||||
static constexpr size_t MaxStringSize =
|
||||
(std::min)(size_t((std::numeric_limits<uint>::max)()),
|
||||
size_t((std::numeric_limits<qsizetype>::max)()));
|
||||
|
||||
static constexpr size_t StringSize = calculateStringSize();
|
||||
static_assert(StringSize <= MaxStringSize, "Meta Object data is too big");
|
||||
|
||||
uint offsetsAndSizes[2 * sizeof...(Nx)] = {};
|
||||
char stringdata0[StringSize] = {};
|
||||
constexpr StringData() = default;
|
||||
};
|
||||
|
||||
template <uint... Nx> constexpr auto stringData(const char (&...strings)[Nx])
|
||||
{
|
||||
StringData<Nx...> result;
|
||||
const char *inputs[] = { strings... };
|
||||
uint sizes[] = { Nx... };
|
||||
|
||||
uint offset = 0;
|
||||
char *output = result.stringdata0;
|
||||
for (size_t i = 0; i < sizeof...(Nx); ++i) {
|
||||
// copy the input string, including the terminating null
|
||||
uint len = sizes[i];
|
||||
for (uint j = 0; j < len; ++j)
|
||||
output[offset + j] = inputs[i][j];
|
||||
result.offsetsAndSizes[2 * i] = offset + sizeof(result.offsetsAndSizes);
|
||||
result.offsetsAndSizes[2 * i + 1] = len - 1;
|
||||
offset += len;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if !defined(Q_CC_GNU_ONLY) || Q_CC_GNU_ONLY >= 1000
|
||||
// It looks like there's a bug in GCC 9
|
||||
# define QT_MOC_HAS_STRINGDATA 1
|
||||
#endif
|
||||
|
||||
} // namespace QtMocHelpers
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -256,9 +256,33 @@ void Generator::generateCode()
|
|||
// ensure the qt_meta_stringdata_XXXX_t type is local
|
||||
fprintf(out, "namespace {\n");
|
||||
|
||||
//
|
||||
// Build the strings using QtMocHelpers::StringData
|
||||
//
|
||||
|
||||
fprintf(out, "\n#ifdef QT_MOC_HAS_STRINGDATA\n"
|
||||
"struct qt_meta_stringdata_%s_t {};\n"
|
||||
"static constexpr auto qt_meta_stringdata_%s = QtMocHelpers::stringData(",
|
||||
qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData());
|
||||
{
|
||||
char comma = 0;
|
||||
for (const QByteArray &str : strings) {
|
||||
if (comma)
|
||||
fputc(comma, out);
|
||||
printStringWithIndentation(out, str);
|
||||
comma = ',';
|
||||
}
|
||||
}
|
||||
fprintf(out, "\n);\n"
|
||||
"#else // !QT_MOC_HAS_STRING_DATA\n");
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
|
||||
fprintf(out, "#error \"qtmochelpers.h not found or too old.\"\n");
|
||||
#else
|
||||
//
|
||||
// Build stringdata struct
|
||||
//
|
||||
|
||||
fprintf(out, "struct qt_meta_stringdata_%s_t {\n", qualifiedClassNameIdentifier.constData());
|
||||
fprintf(out, " uint offsetsAndSizes[%d];\n", int(strings.size() * 2));
|
||||
for (int i = 0; i < strings.size(); ++i) {
|
||||
|
|
@ -302,7 +326,9 @@ void Generator::generateCode()
|
|||
// Terminate stringdata struct
|
||||
fprintf(out, "\n};\n");
|
||||
fprintf(out, "#undef QT_MOC_LITERAL\n");
|
||||
#endif // Qt 6.9
|
||||
|
||||
fprintf(out, "#endif // !QT_MOC_HAS_STRING_DATA\n");
|
||||
fprintf(out, "} // unnamed namespace\n\n");
|
||||
|
||||
//
|
||||
|
|
|
|||
Loading…
Reference in New Issue