QVariant: make many more QtCore types nothrow-copyable

All of those are implicitly-shared Qt data types whose copy constructors
can't throw and have wide contracts (there aren't even any assertions
for validity in any of them). These are all types with a QVariant
implicit constructor, except for QCborValue, which is updated on this
list so QJsonValue (which has a QVariant constructor) is also
legitimately noexcept.

To ensure we haven't made a mistake, the Private constructor checks
again.

Change-Id: I3859764fed084846bcb0fffd17044d8319a45e1f
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Thiago Macieira 2022-07-22 17:23:08 -07:00
parent 3fcb0237dc
commit e9c9e9225c
18 changed files with 71 additions and 94 deletions

View File

@ -1837,7 +1837,7 @@ QUrl::QUrl() : d(nullptr)
/*!
Constructs a copy of \a other.
*/
QUrl::QUrl(const QUrl &other) : d(other.d)
QUrl::QUrl(const QUrl &other) noexcept : d(other.d)
{
if (d)
d->ref.ref();
@ -3227,7 +3227,7 @@ bool QUrl::operator !=(const QUrl &url) const
/*!
Assigns the specified \a url to this object.
*/
QUrl &QUrl::operator =(const QUrl &url)
QUrl &QUrl::operator =(const QUrl &url) noexcept
{
if (!d) {
if (url.d) {

View File

@ -143,8 +143,8 @@ public:
#endif
QUrl();
QUrl(const QUrl &copy);
QUrl &operator =(const QUrl &copy);
QUrl(const QUrl &copy) noexcept;
QUrl &operator =(const QUrl &copy) noexcept;
#ifdef QT_NO_URL_CAST_FROM_STRING
explicit QUrl(const QString &url, ParsingMode mode = TolerantMode);
#else

View File

@ -335,13 +335,21 @@ template <typename T> inline
QVariant::Private::Private(std::piecewise_construct_t, const T &t)
: is_shared(!CanUseInternalSpace<T>), is_null(std::is_same_v<T, std::nullptr_t>)
{
// confirm noexceptness
static constexpr bool isNothrowQVariantConstructible = noexcept(QVariant(t));
static constexpr bool isNothrowCopyConstructible = std::is_nothrow_copy_constructible_v<T>;
static constexpr bool isNothrowCopyAssignable = std::is_nothrow_copy_assignable_v<T>;
const QtPrivate::QMetaTypeInterface *iface = QtPrivate::qMetaTypeInterfaceForType<T>();
Q_ASSERT((quintptr(iface) & 0x3) == 0);
packedType = quintptr(iface) >> 2;
if constexpr (CanUseInternalSpace<T>) {
static_assert(isNothrowQVariantConstructible == isNothrowCopyConstructible);
static_assert(isNothrowQVariantConstructible == isNothrowCopyAssignable);
new (data.data) T(t);
} else {
static_assert(!isNothrowQVariantConstructible); // we allocate memory, even if T doesn't
data.shared = QVariant::PrivateShared::create(QtPrivate::qMetaTypeInterfaceForType<T>());
new (data.shared->data()) T(t);
}
@ -705,7 +713,7 @@ QVariant::QVariant(const QVariant &p)
*/
/*!
\fn QVariant::QVariant(const QBitArray &val)
\fn QVariant::QVariant(const QBitArray &val) noexcept
Constructs a new variant with a bitarray value, \a val.
*/
@ -759,7 +767,7 @@ QVariant::QVariant(const QVariant &p)
*/
/*!
\fn QVariant::QVariant(const QUrl &val)
\fn QVariant::QVariant(const QUrl &val) noexcept
Constructs a new variant with a url value of \a val.
*/
@ -821,13 +829,13 @@ QVariant::QVariant(const QVariant &p)
*/
/*!
\fn QVariant::QVariant(const QLocale &l)
\fn QVariant::QVariant(const QLocale &l) noexcept
Constructs a new variant with a locale value, \a l.
*/
/*!
\fn QVariant::QVariant(const QRegularExpression &re)
\fn QVariant::QVariant(const QRegularExpression &re) noexcept
\since 5.0
@ -876,7 +884,7 @@ QVariant::QVariant(double val) noexcept : d(std::piecewise_construct_t{}, val) {
QVariant::QVariant(float val) noexcept : d(std::piecewise_construct_t{}, val) {}
QVariant::QVariant(const QByteArray &val) noexcept : d(std::piecewise_construct_t{}, val) {}
QVariant::QVariant(const QBitArray &val) : d(std::piecewise_construct_t{}, val) {}
QVariant::QVariant(const QBitArray &val) noexcept : d(std::piecewise_construct_t{}, val) {}
QVariant::QVariant(const QString &val) noexcept : d(std::piecewise_construct_t{}, val) {}
QVariant::QVariant(QChar val) noexcept : d(std::piecewise_construct_t{}, val) {}
QVariant::QVariant(const QStringList &val) noexcept : d(std::piecewise_construct_t{}, val) {}
@ -913,17 +921,19 @@ QVariant::QVariant(QSizeF s) noexcept(Private::FitsInInternalSize<sizeof(qreal)
: d(std::piecewise_construct_t{}, s) {}
#endif
#ifndef QT_BOOTSTRAPPED
QVariant::QVariant(const QUrl &u) : d(std::piecewise_construct_t{}, u) {}
QVariant::QVariant(const QUrl &u) noexcept : d(std::piecewise_construct_t{}, u) {}
#endif
QVariant::QVariant(const QLocale &l) : d(std::piecewise_construct_t{}, l) {}
QVariant::QVariant(const QLocale &l) noexcept : d(std::piecewise_construct_t{}, l) {}
#if QT_CONFIG(regularexpression)
QVariant::QVariant(const QRegularExpression &re) : d(std::piecewise_construct_t{}, re) {}
QVariant::QVariant(const QRegularExpression &re) noexcept : d(std::piecewise_construct_t{}, re) {}
#endif // QT_CONFIG(regularexpression)
QVariant::QVariant(QUuid uuid) noexcept(Private::FitsInInternalSize<16>) : d(std::piecewise_construct_t{}, uuid) {}
#ifndef QT_BOOTSTRAPPED
QVariant::QVariant(const QJsonValue &jsonValue) : d(std::piecewise_construct_t{}, jsonValue) {}
QVariant::QVariant(const QJsonObject &jsonObject) : d(std::piecewise_construct_t{}, jsonObject) {}
QVariant::QVariant(const QJsonArray &jsonArray) : d(std::piecewise_construct_t{}, jsonArray) {}
QVariant::QVariant(const QJsonValue &jsonValue) noexcept(Private::FitsInInternalSize<sizeof(CborValueStandIn)>)
: d(std::piecewise_construct_t{}, jsonValue)
{ static_assert(sizeof(CborValueStandIn) == sizeof(QJsonValue)); }
QVariant::QVariant(const QJsonObject &jsonObject) noexcept : d(std::piecewise_construct_t{}, jsonObject) {}
QVariant::QVariant(const QJsonArray &jsonArray) noexcept : d(std::piecewise_construct_t{}, jsonArray) {}
QVariant::QVariant(const QJsonDocument &jsonDocument) : d(std::piecewise_construct_t{}, jsonDocument) {}
#endif // QT_BOOTSTRAPPED
#if QT_CONFIG(itemmodel)

View File

@ -56,6 +56,7 @@ inline T qvariant_cast(const QVariant &);
class Q_CORE_EXPORT QVariant
{
struct CborValueStandIn { qint64 n; void *c; int t; };
public:
struct PrivateShared
{
@ -206,7 +207,7 @@ public:
QVariant(float f) noexcept;
QVariant(const QByteArray &bytearray) noexcept;
QVariant(const QBitArray &bitarray);
QVariant(const QBitArray &bitarray) noexcept;
QVariant(const QString &string) noexcept;
QVariant(const QStringList &stringlist) noexcept;
QVariant(QChar qchar) noexcept;
@ -226,19 +227,19 @@ public:
QVariant(QRect rect) noexcept(Private::FitsInInternalSize<sizeof(int) * 4>);
QVariant(QRectF rect) noexcept(Private::FitsInInternalSize<sizeof(qreal) * 4>);
#endif
QVariant(const QLocale &locale);
QVariant(const QLocale &locale) noexcept;
#if QT_CONFIG(regularexpression)
QVariant(const QRegularExpression &re);
QVariant(const QRegularExpression &re) noexcept;
#endif // QT_CONFIG(regularexpression)
#if QT_CONFIG(easingcurve)
QVariant(const QEasingCurve &easing);
#endif
QVariant(QUuid uuid) noexcept(Private::FitsInInternalSize<16>);
#ifndef QT_BOOTSTRAPPED
QVariant(const QUrl &url);
QVariant(const QJsonValue &jsonValue);
QVariant(const QJsonObject &jsonObject);
QVariant(const QJsonArray &jsonArray);
QVariant(const QUrl &url) noexcept;
QVariant(const QJsonValue &jsonValue) noexcept(Private::FitsInInternalSize<sizeof(CborValueStandIn)>);
QVariant(const QJsonObject &jsonObject) noexcept;
QVariant(const QJsonArray &jsonArray) noexcept;
QVariant(const QJsonDocument &jsonDocument);
#endif // QT_BOOTSTRAPPED
#if QT_CONFIG(itemmodel)

View File

@ -1805,7 +1805,7 @@ QCborValue::QCborValue(QCborTag tag, const QCborValue &tv)
/*!
Copies the contents of \a other into this object.
*/
QCborValue::QCborValue(const QCborValue &other)
QCborValue::QCborValue(const QCborValue &other) noexcept
: n(other.n), container(other.container), t(other.t)
{
if (container)
@ -1899,7 +1899,7 @@ void QCborValue::dispose()
/*!
Replaces the contents of this QCborObject with a copy of \a other.
*/
QCborValue &QCborValue::operator=(const QCborValue &other)
QCborValue &QCborValue::operator=(const QCborValue &other) noexcept
{
n = other.n;
assignContainer(container, other.container);

View File

@ -139,12 +139,12 @@ public:
// make sure const char* doesn't go call the bool constructor
QCborValue(const void *) = delete;
QCborValue(const QCborValue &other);
QCborValue(const QCborValue &other) noexcept;
QCborValue(QCborValue &&other) noexcept
: n(other.n), container(qExchange(other.container, nullptr)), t(qExchange(other.t, Undefined))
{
}
QCborValue &operator=(const QCborValue &other);
QCborValue &operator=(const QCborValue &other) noexcept;
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QCborValue)
void swap(QCborValue &other) noexcept

View File

@ -138,11 +138,13 @@ QJsonArray::QJsonArray(std::initializer_list<QJsonValue> args)
Since QJsonArray is implicitly shared, the copy is shallow
as long as the object doesn't get modified.
*/
QJsonArray::QJsonArray(const QJsonArray &other)
{
a = other.a;
}
QJsonArray::QJsonArray(const QJsonArray &other) noexcept = default;
/*!
\since 5.10
Move-constructs a QJsonArray from \a other.
*/
QJsonArray::QJsonArray(QJsonArray &&other) noexcept
: a(other.a)
{
@ -152,18 +154,7 @@ QJsonArray::QJsonArray(QJsonArray &&other) noexcept
/*!
Assigns \a other to this array.
*/
QJsonArray &QJsonArray::operator =(const QJsonArray &other)
{
a = other.a;
return *this;
}
/*!
\fn QJsonArray::QJsonArray(QJsonArray &&other)
\since 5.10
Move-constructs a QJsonArray from \a other.
*/
QJsonArray &QJsonArray::operator =(const QJsonArray &other) noexcept = default;
/*!
\fn QJsonArray &QJsonArray::operator =(QJsonArray &&other)

View File

@ -23,8 +23,8 @@ public:
~QJsonArray();
QJsonArray(const QJsonArray &other);
QJsonArray &operator =(const QJsonArray &other);
QJsonArray(const QJsonArray &other) noexcept;
QJsonArray &operator =(const QJsonArray &other) noexcept;
QJsonArray(QJsonArray &&other) noexcept;

View File

@ -122,11 +122,13 @@ QJsonObject::QJsonObject(std::initializer_list<QPair<QString, QJsonValue> > args
Since QJsonObject is implicitly shared, the copy is shallow
as long as the object does not get modified.
*/
QJsonObject::QJsonObject(const QJsonObject &other)
{
o = other.o;
}
QJsonObject::QJsonObject(const QJsonObject &other) noexcept = default;
/*!
\since 5.10
Move-constructs a QJsonObject from \a other.
*/
QJsonObject::QJsonObject(QJsonObject &&other) noexcept
: o(other.o)
{
@ -136,18 +138,8 @@ QJsonObject::QJsonObject(QJsonObject &&other) noexcept
/*!
Assigns \a other to this object.
*/
QJsonObject &QJsonObject::operator =(const QJsonObject &other)
{
o = other.o;
return *this;
}
QJsonObject &QJsonObject::operator =(const QJsonObject &other) noexcept = default;
/*!
\fn QJsonObject::QJsonObject(QJsonObject &&other)
\since 5.10
Move-constructs a QJsonObject from \a other.
*/
/*!
\fn QJsonObject &QJsonObject::operator =(QJsonObject &&other)

View File

@ -25,8 +25,8 @@ public:
~QJsonObject();
QJsonObject(const QJsonObject &other);
QJsonObject &operator =(const QJsonObject &other);
QJsonObject(const QJsonObject &other) noexcept;
QJsonObject &operator =(const QJsonObject &other) noexcept;
QJsonObject(QJsonObject &&other) noexcept;

View File

@ -247,15 +247,12 @@ QJsonValue::~QJsonValue() = default;
/*!
Creates a copy of \a other.
*/
QJsonValue::QJsonValue(const QJsonValue &other)
: value(other.value)
{
}
QJsonValue::QJsonValue(const QJsonValue &other) noexcept = default;
/*!
Assigns the value stored in \a other to this object.
*/
QJsonValue &QJsonValue::operator =(const QJsonValue &other)
QJsonValue &QJsonValue::operator =(const QJsonValue &other) noexcept
{
QJsonValue copy(other);
swap(copy);

View File

@ -51,8 +51,8 @@ public:
~QJsonValue();
QJsonValue(const QJsonValue &other);
QJsonValue &operator =(const QJsonValue &other);
QJsonValue(const QJsonValue &other) noexcept;
QJsonValue &operator =(const QJsonValue &other) noexcept;
QJsonValue(QJsonValue &&other) noexcept;

View File

@ -1072,10 +1072,7 @@ QLocale::QLocale(Language language, Script script, Territory territory)
Constructs a QLocale object as a copy of \a other.
*/
QLocale::QLocale(const QLocale &other)
{
d = other.d;
}
QLocale::QLocale(const QLocale &other) noexcept = default;
/*!
Destructor
@ -1090,11 +1087,7 @@ QLocale::~QLocale()
to this QLocale object.
*/
QLocale &QLocale::operator=(const QLocale &other)
{
d = other.d;
return *this;
}
QLocale &QLocale::operator=(const QLocale &other) noexcept = default;
/*!
\internal

View File

@ -896,9 +896,9 @@ public:
explicit QLocale(QStringView name);
QLocale(Language language, Territory territory);
QLocale(Language language, Script script = AnyScript, Territory territory = AnyTerritory);
QLocale(const QLocale &other);
QLocale(const QLocale &other) noexcept;
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QLocale)
QLocale &operator=(const QLocale &other);
QLocale &operator=(const QLocale &other) noexcept;
~QLocale();
void swap(QLocale &other) noexcept { d.swap(other.d); }

View File

@ -1354,10 +1354,7 @@ QRegularExpression::QRegularExpression(const QString &pattern, PatternOptions op
\sa operator=()
*/
QRegularExpression::QRegularExpression(const QRegularExpression &re)
: d(re.d)
{
}
QRegularExpression::QRegularExpression(const QRegularExpression &re) noexcept = default;
/*!
\fn QRegularExpression::QRegularExpression(QRegularExpression &&re)
@ -1386,11 +1383,7 @@ QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QRegularExpressionPrivate)
Assigns the regular expression \a re to this object, and returns a reference
to the copy. Both the pattern and the pattern options are copied.
*/
QRegularExpression &QRegularExpression::operator=(const QRegularExpression &re)
{
d = re.d;
return *this;
}
QRegularExpression &QRegularExpression::operator=(const QRegularExpression &re) noexcept = default;
/*!
\fn void QRegularExpression::swap(QRegularExpression &other)

View File

@ -50,10 +50,10 @@ public:
QRegularExpression();
explicit QRegularExpression(const QString &pattern, PatternOptions options = NoPatternOption);
QRegularExpression(const QRegularExpression &re);
QRegularExpression(const QRegularExpression &re) noexcept;
QRegularExpression(QRegularExpression &&re) = default;
~QRegularExpression();
QRegularExpression &operator=(const QRegularExpression &re);
QRegularExpression &operator=(const QRegularExpression &re) noexcept;
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QRegularExpression)
void swap(QRegularExpression &other) noexcept { d.swap(other.d); }

View File

@ -453,7 +453,7 @@ quint32 QBitArray::toUInt32(QSysInfo::Endian endianness, bool *ok) const noexcep
\overload
*/
/*! \fn QBitArray::QBitArray(const QBitArray &other)
/*! \fn QBitArray::QBitArray(const QBitArray &other) noexcept
Constructs a copy of \a other.
@ -465,7 +465,7 @@ quint32 QBitArray::toUInt32(QSysInfo::Endian endianness, bool *ok) const noexcep
\sa operator=()
*/
/*! \fn QBitArray &QBitArray::operator=(const QBitArray &other)
/*! \fn QBitArray &QBitArray::operator=(const QBitArray &other) noexcept
Assigns \a other to this bit array and returns a reference to
this bit array.

View File

@ -21,8 +21,8 @@ class Q_CORE_EXPORT QBitArray
public:
inline QBitArray() noexcept {}
explicit QBitArray(qsizetype size, bool val = false);
QBitArray(const QBitArray &other) : d(other.d) {}
inline QBitArray &operator=(const QBitArray &other) { d = other.d; return *this; }
QBitArray(const QBitArray &other) noexcept : d(other.d) {}
inline QBitArray &operator=(const QBitArray &other) noexcept { d = other.d; return *this; }
inline QBitArray(QBitArray &&other) noexcept : d(std::move(other.d)) {}
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QBitArray)