summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2018-07-14 16:42:08 -0700
committerThiago Macieira <thiago.macieira@intel.com>2018-07-30 16:21:12 +0000
commit7cb5b324f05b3d9e530856bd0eb2ddf4e34b2f55 (patch)
treea96c2af38e7a2ef58b4acf3a4cd77cdfc60d53f8 /src
parent3cd9d6d19bc61f0b4e5228196e058bac5fd37ba3 (diff)
QCborValue: move the toDiagnosticNotation() function to its own file
If we ever need to add QCborValue to the bootstrap library, it's unlikely that we'll need this part. And by splitting it, I can make the code handle more cases, that hadn't been properly handled before. Change-Id: I2f630efbbce54f14bfa9fffd154160c0ad893695 Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/corelib/global/qnumeric_p.h52
-rw-r--r--src/corelib/serialization/qcbordiagnostic.cpp281
-rw-r--r--src/corelib/serialization/qcborvalue.cpp225
-rw-r--r--src/corelib/serialization/qcborvalue_p.h2
-rw-r--r--src/corelib/serialization/serialization.pri1
5 files changed, 336 insertions, 225 deletions
diff --git a/src/corelib/global/qnumeric_p.h b/src/corelib/global/qnumeric_p.h
index 5f8a124bcc..9c8514f5a3 100644
--- a/src/corelib/global/qnumeric_p.h
+++ b/src/corelib/global/qnumeric_p.h
@@ -163,6 +163,58 @@ Q_DECL_CONST_FUNCTION static inline bool qt_is_finite(float f)
#ifndef Q_CLANG_QDOC
namespace {
+/*!
+ Returns true if the double \a v can be converted to type \c T, false if
+ it's out of range. If the conversion is successful, the converted value is
+ stored in \a value; if it was not successful, \a value will contain the
+ minimum or maximum of T, depending on the sign of \a d. If \c T is
+ unsigned, then \a value contains the absolute value of \a v.
+
+ This function works for v containing infinities, but not NaN. It's the
+ caller's responsibility to exclude that possibility before calling it.
+*/
+template <typename T> static inline bool convertDoubleTo(double v, T *value)
+{
+ Q_STATIC_ASSERT(std::numeric_limits<T>::is_integer);
+
+ // The [conv.fpint] (7.10 Floating-integral conversions) section of the C++
+ // standard says only exact conversions are guaranteed. Converting
+ // integrals to floating-point with loss of precision has implementation-
+ // defined behavior whether the next higher or next lower is returned;
+ // converting FP to integral is UB if it can't be represented.
+ //
+ // That means we can't write UINT64_MAX+1. Writing ldexp(1, 64) would be
+ // correct, but Clang, ICC and MSVC don't realize that it's a constant and
+ // the math call stays in the compiled code.
+
+ double supremum;
+ if (std::numeric_limits<T>::is_signed) {
+ supremum = -1.0 * std::numeric_limits<T>::min(); // -1 * (-2^63) = 2^63, exact (for T = qint64)
+ *value = std::numeric_limits<T>::min();
+ if (v < std::numeric_limits<T>::min())
+ return false;
+ } else {
+ using ST = typename std::make_signed<T>::type;
+ supremum = -2.0 * std::numeric_limits<ST>::min(); // -2 * (-2^63) = 2^64, exact (for T = quint64)
+ v = fabs(v);
+ }
+
+ *value = std::numeric_limits<T>::max();
+ if (v >= supremum)
+ return false;
+
+ // Now we can convert, these two conversions cannot be UB
+ *value = T(v);
+
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_GCC("-Wfloat-equal")
+QT_WARNING_DISABLE_CLANG("-Wfloat-equal")
+
+ return *value == v;
+
+QT_WARNING_POP
+}
+
// Overflow math.
// This provides efficient implementations for int, unsigned, qsizetype and
// size_t. Implementations for 8- and 16-bit types will work but may not be as
diff --git a/src/corelib/serialization/qcbordiagnostic.cpp b/src/corelib/serialization/qcbordiagnostic.cpp
new file mode 100644
index 0000000000..8e641ff7cf
--- /dev/null
+++ b/src/corelib/serialization/qcbordiagnostic.cpp
@@ -0,0 +1,281 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Intel Corporation.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcborvalue.h"
+#include "qcborvalue_p.h"
+
+#include "qcborarray.h"
+#include "qcbormap.h"
+
+#include <private/qnumeric_p.h>
+#include <qstack.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+class DiagnosticNotation
+{
+public:
+ static QString create(const QCborValue &v, QCborValue::DiagnosticNotationOptions opts)
+ {
+ DiagnosticNotation dn(opts);
+ dn.appendValue(v);
+ return dn.result;
+ }
+
+private:
+ QStack<int> byteArrayFormatStack;
+ QString separator;
+ QString result;
+ QCborValue::DiagnosticNotationOptions opts;
+ int nestingLevel = 0;
+
+ struct Nest {
+ enum { IndentationWidth = 4 };
+ DiagnosticNotation *dn;
+ Nest(DiagnosticNotation *that) : dn(that)
+ {
+ ++dn->nestingLevel;
+ static const char indent[IndentationWidth + 1] = " ";
+ if (dn->opts & QCborValue::LineWrapped)
+ dn->separator += QLatin1String(indent, IndentationWidth);
+ }
+ ~Nest()
+ {
+ --dn->nestingLevel;
+ if (dn->opts & QCborValue::LineWrapped)
+ dn->separator.chop(IndentationWidth);
+ }
+ };
+
+ DiagnosticNotation(QCborValue::DiagnosticNotationOptions opts_)
+ : separator(QLatin1String(opts_ & QCborValue::LineWrapped ? "\n" : "")), opts(opts_)
+ {
+ byteArrayFormatStack.push(int(QCborKnownTags::ExpectedBase16));
+ }
+
+ void appendString(const QString &s);
+ void appendArray(const QCborArray &a);
+ void appendMap(const QCborMap &m);
+ void appendValue(const QCborValue &v);
+};
+}
+
+static QString makeFpString(double d)
+{
+ QString s;
+ quint64 v;
+ if (qt_is_inf(d)) {
+ s = (d < 0) ? QStringLiteral("-inf") : QStringLiteral("inf");
+ } else if (qt_is_nan(d)) {
+ s = QStringLiteral("nan");
+ } else if (convertDoubleTo(d, &v)) {
+ s = QString::fromLatin1("%1.0").arg(v);
+ if (d < 0)
+ s.prepend(QLatin1Char('-'));
+ } else {
+ s = QString::number(d, 'g', QLocale::FloatingPointShortest);
+ if (!s.contains(QLatin1Char('.')) && !s.contains('e'))
+ s += QLatin1Char('.');
+ }
+ return s;
+}
+
+static bool isByteArrayEncodingTag(QCborTag tag)
+{
+ switch (quint64(tag)) {
+ case quint64(QCborKnownTags::ExpectedBase16):
+ case quint64(QCborKnownTags::ExpectedBase64):
+ case quint64(QCborKnownTags::ExpectedBase64url):
+ return true;
+ }
+ return false;
+}
+
+void DiagnosticNotation::appendString(const QString &s)
+{
+ result += QLatin1Char('"')
+ + QString(s)
+ .replace(QLatin1Char('\\'), QLatin1String("\\\\"))
+ .replace(QLatin1Char('"'), QLatin1String("\\\""))
+ + QLatin1Char('"');
+}
+
+void DiagnosticNotation::appendArray(const QCborArray &a)
+{
+ result += QLatin1Char('[');
+
+ // length 2 (including the space) when not line wrapping
+ QLatin1String commaValue(", ", opts & QCborValue::LineWrapped ? 1 : 2);
+ {
+ Nest n(this);
+ QLatin1String comma;
+ for (auto v : a) {
+ result += comma + separator;
+ comma = commaValue;
+ appendValue(v);
+ }
+ }
+
+ result += separator + QLatin1Char(']');
+}
+
+void DiagnosticNotation::appendMap(const QCborMap &m)
+{
+ result += QLatin1Char('{');
+
+ // length 2 (including the space) when not line wrapping
+ QLatin1String commaValue(", ", opts & QCborValue::LineWrapped ? 1 : 2);
+ {
+ Nest n(this);
+ QLatin1String comma;
+ for (auto v : m) {
+ result += comma + separator;
+ comma = commaValue;
+ appendValue(v.first);
+ result += QLatin1String(": ");
+ appendValue(v.second);
+ }
+ }
+
+ result += separator + QLatin1Char('}');
+};
+
+void DiagnosticNotation::appendValue(const QCborValue &v)
+{
+ switch (v.type()) {
+ case QCborValue::Integer:
+ result += QString::number(v.toInteger());
+ return;
+ case QCborValue::ByteArray:
+ switch (byteArrayFormatStack.top()) {
+ case int(QCborKnownTags::ExpectedBase16):
+ result += QString::fromLatin1("h'" +
+ v.toByteArray().toHex(opts & QCborValue::ExtendedFormat ? ' ' : '\0') +
+ '\'');
+ return;
+ case int(QCborKnownTags::ExpectedBase64):
+ result += QString::fromLatin1("b64'" + v.toByteArray().toBase64() + '\'');
+ return;
+ default:
+ case int(QCborKnownTags::ExpectedBase64url):
+ result += QString::fromLatin1("b64'" +
+ v.toByteArray().toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals) +
+ '\'');
+ return;
+ }
+ case QCborValue::String:
+ return appendString(v.toString());
+ case QCborValue::Array:
+ return appendArray(v.toArray());
+ case QCborValue::Map:
+ return appendMap(v.toMap());
+ case QCborValue::False:
+ result += QLatin1String("false");
+ return;
+ case QCborValue::True:
+ result += QLatin1String("true");
+ return;
+ case QCborValue::Null:
+ result += QLatin1String("null");
+ return;
+ case QCborValue::Undefined:
+ result += QLatin1String("undefined");
+ return;
+ case QCborValue::Double:
+ result += makeFpString(v.toDouble());
+ return;
+ case QCborValue::Invalid:
+ result += QStringLiteral("<invalid>");
+ return;
+
+ default:
+ // Only tags, extended types, and simple types remain; see below.
+ break;
+ }
+
+ if (v.isTag()) {
+ // We handle all extended types as regular tags, so it won't matter
+ // whether we understand that tag or not.
+ bool byteArrayFormat = opts & QCborValue::ExtendedFormat && isByteArrayEncodingTag(v.tag());
+ if (byteArrayFormat)
+ byteArrayFormatStack.push(int(v.tag()));
+ result += QString::number(quint64(v.tag())) + QLatin1Char('(');
+ appendValue(v.taggedValue());
+ result += QLatin1Char(')');
+ if (byteArrayFormat)
+ byteArrayFormatStack.pop();
+ } else {
+ // must be a simple type
+ result += QString::fromLatin1("simple(%1)").arg(quint8(v.toSimpleType()));
+ }
+}
+
+/*!
+ Creates the diagnostic notation equivalent of this CBOR object and returns
+ it. The \a opts parameter controls the dialect of the notation. Diagnostic
+ notation is useful in debugging, to aid the developer in understanding what
+ value is stored in the QCborValue or in a CBOR stream. For that reason, the
+ Qt API provides no support for parsing the diagnostic back into the
+ in-memory format or CBOR stream, though the representation is unique and it
+ would be possible.
+
+ CBOR diagnostic notation is specified by
+ \l{https://tools.ietf.org/html/rfc7049#section-6}{section 6} of RFC 7049.
+ It is a text representation of the CBOR stream and it is very similar to
+ JSON, but it supports the CBOR types not found in JSON. The extended format
+ enabled by the \l{DiagnosticNotationOption}{ExtendedFormat} flag is
+ currently in some IETF drafts and its format is subject to change.
+
+ This function produces the equivalent representation of the stream that
+ toCbor() would produce, without any transformation option provided there.
+ This also implies this function may not produce a representation of the
+ stream that was used to create the object, if it was created using
+ fromCbor(), as that function may have applied transformations. For a
+ high-fidelity notation of a stream, without transformation, see the \c
+ cbordump example.
+
+ \sa toCbor(), toJsonDocument(), QJsonDocument::toJson()
+ */
+QString QCborValue::toDiagnosticNotation(DiagnosticNotationOptions opts) const
+{
+ return DiagnosticNotation::create(*this, opts);
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/serialization/qcborvalue.cpp b/src/corelib/serialization/qcborvalue.cpp
index 0ec84c12d1..4108418550 100644
--- a/src/corelib/serialization/qcborvalue.cpp
+++ b/src/corelib/serialization/qcborvalue.cpp
@@ -47,9 +47,7 @@
#include <qendian.h>
#include <qlocale.h>
#include <private/qnumeric_p.h>
-#include <qscopedvaluerollback.h>
#include <private/qsimd_p.h>
-#include <qstack.h>
#include <new>
@@ -768,58 +766,6 @@ using namespace QtCbor;
// in qcborstream.cpp
extern void qt_cbor_stream_set_error(QCborStreamReaderPrivate *d, QCborError error);
-/*!
- Returns true if the double \a v can be converted to type \c T, false if
- it's out of range. If the conversion is successful, the converted value is
- stored in \a value; if it was not successful, \a value will contain the
- minimum or maximum of T, depending on the sign of \a d. If \c T is
- unsigned, then \a value contains the absolute value of \a v.
-
- This function works for v containing infinities, but not NaN. It's the
- caller's responsibility to exclude that possibility before calling it.
-*/
-template <typename T> static inline bool convertDoubleTo(double v, T *value)
-{
- Q_STATIC_ASSERT(std::numeric_limits<T>::is_integer);
-
- // The [conv.fpint] (7.10 Floating-integral conversions) section of the C++
- // standard says only exact conversions are guaranteed. Converting
- // integrals to floating-point with loss of precision has implementation-
- // defined behavior whether the next higher or next lower is returned;
- // converting FP to integral is UB if it can't be represented.
- //
- // That means we can't write UINT64_MAX+1. Writing ldexp(1, 64) would be
- // correct, but only Clang, ICC and MSVC don't realize that it's a constant
- // and the math call stays in the compiled code.
-
- double supremum;
- if (std::numeric_limits<T>::is_signed) {
- supremum = -1.0 * std::numeric_limits<T>::min(); // -1 * (-2^63) = 2^63, exact (for T = qint64)
- *value = std::numeric_limits<T>::min();
- if (v < std::numeric_limits<T>::min())
- return false;
- } else {
- using ST = typename std::make_signed<T>::type;
- supremum = -2.0 * std::numeric_limits<ST>::min(); // -2 * (-2^63) = 2^64, exact (for T = quint64)
- v = fabs(v);
- }
-
- *value = std::numeric_limits<T>::max();
- if (v >= supremum)
- return false;
-
- // Now we can convert, these two conversions cannot be UB
- *value = T(v);
-
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_GCC("-Wfloat-equal")
-QT_WARNING_DISABLE_CLANG("-Wfloat-equal")
-
- return *value == v;
-
-QT_WARNING_POP
-}
-
static void writeDoubleToCbor(QCborStreamWriter &writer, double d, QCborValue::EncodingOptions opt)
{
if (qt_is_nan(d)) {
@@ -869,146 +815,6 @@ static inline int typeOrder(Element e1, Element e2)
return comparable(e1) - comparable(e2);
}
-namespace {
-class DiagnosticNotation
-{
-public:
- static QString create(const QCborValue &v, QCborValue::DiagnosticNotationOptions opts)
- {
- DiagnosticNotation dn(opts);
- return dn.createFromValue(v);
- }
-
-private:
- QStack<int> byteArrayFormatStack;
- QCborValue::DiagnosticNotationOptions opts;
- int nestingLevel = 0;
-
- DiagnosticNotation(QCborValue::DiagnosticNotationOptions opts_)
- : opts(opts_)
- {
- byteArrayFormatStack.push(int(QCborKnownTags::ExpectedBase16));
- }
-
- QString createFromValue(const QCborValue &v);
-};
-}
-
-QString DiagnosticNotation::createFromValue(const QCborValue &v)
-{
- QString indent(1, QLatin1Char(' '));
- QString indented = indent;
- if (opts & QCborValue::LineWrapped) {
- indent = QLatin1Char('\n') + QString(4 * nestingLevel, QLatin1Char(' '));
- indented = indent + QLatin1String(" ");
- }
- QScopedValueRollback<int> rollback(nestingLevel);
- ++nestingLevel;
-
- auto createFromArray = [=](const QCborArray &a) {
- QString result;
- QLatin1String comma;
- for (auto v : a) {
- result += comma + indented + createFromValue(v);
- comma = QLatin1String(",");
- }
- return result;
- };
- auto createFromMap = [=](const QCborMap &m) {
- QString result;
- QLatin1String comma;
- for (auto v : m) {
- result += comma + indented + createFromValue(v.first) +
- QLatin1String(": ") + createFromValue(v.second);
- comma = QLatin1String(",");
- }
- return result;
- };
- auto makeFpString = [](double d) {
- QString s;
- quint64 v;
- if (qt_is_inf(d)) {
- s = (d < 0) ? QStringLiteral("-inf") : QStringLiteral("inf");
- } else if (qt_is_nan(d)) {
- s = QStringLiteral("nan");
- } else if (convertDoubleTo(d, &v)) {
- s = QString::fromLatin1("%1.0").arg(v);
- if (d < 0)
- s.prepend(QLatin1Char('-'));
- } else {
- s = QString::number(d, 'g', QLocale::FloatingPointShortest);
- if (!s.contains(QLatin1Char('.')) && !s.contains('e'))
- s += QLatin1Char('.');
- }
- return s;
- };
- auto isByteArrayEncodingTag = [](QCborTag tag) {
- switch (quint64(tag)) {
- case quint64(QCborKnownTags::ExpectedBase16):
- case quint64(QCborKnownTags::ExpectedBase64):
- case quint64(QCborKnownTags::ExpectedBase64url):
- return true;
- }
- return false;
- };
-
- switch (v.type()) {
- case QCborValue::Integer:
- return QString::number(v.toInteger());
- case QCborValue::ByteArray:
- switch (byteArrayFormatStack.top()) {
- case int(QCborKnownTags::ExpectedBase16):
- return QString::fromLatin1("h'" +
- v.toByteArray().toHex(opts & QCborValue::ExtendedFormat ? ' ' : '\0') +
- '\'');
- case int(QCborKnownTags::ExpectedBase64):
- return QString::fromLatin1("b64'" + v.toByteArray().toBase64() + '\'');
- default:
- case int(QCborKnownTags::ExpectedBase64url):
- return QString::fromLatin1("b64'" +
- v.toByteArray().toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals) +
- '\'');
- }
- case QCborValue::String:
- // ### TODO: Needs escaping!
- return QLatin1Char('"') + v.toString() + QLatin1Char('"');
- case QCborValue::Array:
- return QLatin1Char('[') + createFromArray(v.toArray()) + indent + QLatin1Char(']');
- case QCborValue::Map:
- return QLatin1Char('{') + createFromMap(v.toMap()) + indent + QLatin1Char('}');
- case QCborValue::False:
- return QStringLiteral("false");
- case QCborValue::True:
- return QStringLiteral("true");
- case QCborValue::Null:
- return QStringLiteral("null");
- case QCborValue::Undefined:
- return QStringLiteral("undefined");
- case QCborValue::Double:
- return makeFpString(v.toDouble());
- case QCborValue::Invalid:
- return QStringLiteral("<invalid>");
-
- case QCborValue::Tag:
- case QCborValue::SimpleType:
- default: // tags and other simple types that are recognized
- break; // are all handled below
- }
-
- if (v.isTag()) {
- bool byteArrayFormat = opts & QCborValue::ExtendedFormat && isByteArrayEncodingTag(v.tag());
- if (byteArrayFormat)
- byteArrayFormatStack.push(int(v.tag()));
- QString result = QString::fromLatin1("%1(%2)").arg(quint64(v.tag())).arg(createFromValue(v.taggedValue()));
- if (byteArrayFormat)
- byteArrayFormatStack.pop();
- return result;
- }
-
- // must be a simple type
- return QString::fromLatin1("simple(%1)").arg(quint8(v.toSimpleType()));
-}
-
QCborContainerPrivate::~QCborContainerPrivate()
{
// delete our elements
@@ -2508,37 +2314,6 @@ Q_NEVER_INLINE void QCborValue::toCbor(QCborStreamWriter &writer, EncodingOption
}
}
-/*!
- Creates the diagnostic notation equivalent of this CBOR object and return
- it. The \a opts parameter controls the dialect of the notation. Diagnostic
- notation is useful in debugging, to aid the developer in understanding what
- value is stored in the QCborValue or in a CBOR stream. For that reason, the
- Qt API provides no support for parsing the diagnostic back into the
- in-memory format or CBOR stream, though the representation is unique and it
- would be possible.
-
- CBOR diagnostic notation is specified by
- \l{https://tools.ietf.org/html/rfc7049#section-6}{section 6} of RFC 7049.
- It is a text representation of the CBOR stream and it is very similar to
- JSON, but it supports the CBOR types not found in JSON. The extended format
- enabled by the \l{DiagnosticNotationOption}{ExtendedFormat} flag is
- currently in some IETF drafts and its format is subject to change.
-
- This function produces the equivalent representation of the stream that
- toCbor() would produce, without any transformation option provided there.
- This also implies this function may not produce a representation of the
- stream that was used to create the object, if it was created using
- fromCbor(), as that function may have applied transformations. For a
- high-fidelity notation of a stream, without transformation, see the \c
- cbordump example.
-
- \sa toCbor(), toJsonDocument(), QJsonDocument::toJson()
- */
-QString QCborValue::toDiagnosticNotation(DiagnosticNotationOptions opts) const
-{
- return DiagnosticNotation::create(*this, opts);
-}
-
void QCborValueRef::toCbor(QCborStreamWriter &writer, QCborValue::EncodingOptions opt)
{
concrete().toCbor(writer, opt);
diff --git a/src/corelib/serialization/qcborvalue_p.h b/src/corelib/serialization/qcborvalue_p.h
index 02aa05bcdb..3a28707056 100644
--- a/src/corelib/serialization/qcborvalue_p.h
+++ b/src/corelib/serialization/qcborvalue_p.h
@@ -56,6 +56,8 @@
#include <private/qglobal_p.h>
#include <private/qutfcodec_p.h>
+#include <math.h>
+
QT_BEGIN_NAMESPACE
namespace QtCbor {
diff --git a/src/corelib/serialization/serialization.pri b/src/corelib/serialization/serialization.pri
index 73b99b8e64..4f2dc64e4f 100644
--- a/src/corelib/serialization/serialization.pri
+++ b/src/corelib/serialization/serialization.pri
@@ -24,6 +24,7 @@ HEADERS += \
SOURCES += \
serialization/qcborstream.cpp \
+ serialization/qcbordiagnostic.cpp \
serialization/qcborvalue.cpp \
serialization/qdatastream.cpp \
serialization/qjson.cpp \