aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2021-06-08 08:47:54 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-06-09 13:02:06 +0000
commit91d8597a5d5f7b73f631da5c4d498e94ad7ce506 (patch)
tree301d03cc2907568fec9a904c97d1583eb82cc7f1
parent86422715110dc067a316ce4b8d9cbc37b52835c3 (diff)
shiboken6: Fix increment/decrement operators
For classes that have increment/decrement operators (++/--), shiboken6 generated operators +=/-= ( __iadd__/__isub__) by calling them n times. This was mainly intended for iterators. However, when both operator++/-- and operator+=/-= were present (as introduced by qtdeclarative/f8f31dd0e1f9425ba272691c79e719ebc4bcfb94 for QJSPrimitiveValue), duplicate code and errors were generated. This requires filtering of the operator functions. Introduce a separate function type for increment/decrement operators and remove them if operators +=/-= were found. Also, when both prefix and postfix version of the increment/decrement operators are found, remove one. Extend existing class IntWrapper from libsample for testing. Add explanatory comment and use prefix increment. Change-Id: I0f8a0c79a6f74974ba327d21f35fff74962ffd3a Reviewed-by: Christian Tismer <tismer@stackless.com> (cherry picked from commit 783720fdb308a686610b4f70e839930b60970362) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--sources/pyside6/PySide6/QtGui/typesystem_gui_common.xml6
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp6
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetafunction.cpp10
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetafunction.h3
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetalang.cpp11
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetalang.h1
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetalang_enums.h15
-rw-r--r--sources/shiboken6/ApiExtractor/parser/codemodel.cpp4
-rw-r--r--sources/shiboken6/ApiExtractor/parser/codemodel.h2
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator.cpp59
-rw-r--r--sources/shiboken6/tests/libsample/CMakeLists.txt1
-rw-r--r--sources/shiboken6/tests/libsample/collector.cpp2
-rw-r--r--sources/shiboken6/tests/libsample/collector.h9
-rw-r--r--sources/shiboken6/tests/libsample/intwrapper.cpp61
-rw-r--r--sources/shiboken6/tests/libsample/intwrapper.h87
-rw-r--r--sources/shiboken6/tests/samplebinding/intwrapper_test.py61
16 files changed, 305 insertions, 33 deletions
diff --git a/sources/pyside6/PySide6/QtGui/typesystem_gui_common.xml b/sources/pyside6/PySide6/QtGui/typesystem_gui_common.xml
index c54a7e5d7..ce546d9cc 100644
--- a/sources/pyside6/PySide6/QtGui/typesystem_gui_common.xml
+++ b/sources/pyside6/PySide6/QtGui/typesystem_gui_common.xml
@@ -1424,12 +1424,6 @@
</extra-includes>
<value-type name="iterator" >
<include file-name="QTextFrame" location="global"/>
- <!-- ### These operators where removed because they don't make sense in Python.
- Instead iterator methods (__iter__, next) should be implemented.
- See bug 688 -->
- <modify-function signature="operator++()" remove="all"/>
- <modify-function signature="operator--()" remove="all"/>
- <!-- ### -->
<add-function signature="__iter__()" return-type="PyObject*">
<inject-code class="target" position="beginning">
<insert-template name="__iter__"/>
diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp
index dafbed00e..cac311626 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp
+++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp
@@ -1730,6 +1730,12 @@ static inline AbstractMetaFunction::FunctionType functionTypeFromCodeModel(CodeM
case CodeModel::ArithmeticOperator:
result = AbstractMetaFunction::ArithmeticOperator;
break;
+ case CodeModel::IncrementOperator:
+ result = AbstractMetaFunction::IncrementOperator;
+ break;
+ case CodeModel::DecrementOperator:
+ result = AbstractMetaFunction::DecrementOperator;
+ break;
case CodeModel::BitwiseOperator:
result = AbstractMetaFunction::BitwiseOperator;
break;
diff --git a/sources/shiboken6/ApiExtractor/abstractmetafunction.cpp b/sources/shiboken6/ApiExtractor/abstractmetafunction.cpp
index 1b21b94b8..21677a3e5 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetafunction.cpp
+++ b/sources/shiboken6/ApiExtractor/abstractmetafunction.cpp
@@ -1044,6 +1044,12 @@ bool AbstractMetaFunction::isComparisonOperator() const
return d->m_functionType == ComparisonOperator;
}
+bool AbstractMetaFunction::isIncDecrementOperator() const
+{
+ return d->m_functionType == IncrementOperator
+ || d->m_functionType == DecrementOperator;
+}
+
bool AbstractMetaFunction::isLogicalOperator() const
{
return d->m_functionType == LogicalOperator;
@@ -1138,6 +1144,10 @@ bool AbstractMetaFunction::matches(OperatorQueryOptions query) const
case AbstractMetaFunction::ArithmeticOperator:
result = query.testFlag(OperatorQueryOption::ArithmeticOp);
break;
+ case AbstractMetaFunction::IncrementOperator:
+ case AbstractMetaFunction::DecrementOperator:
+ result = query.testFlag(OperatorQueryOption::IncDecrementOp);
+ break;
case AbstractMetaFunction::BitwiseOperator:
case AbstractMetaFunction::ShiftOperator:
result = query.testFlag(OperatorQueryOption::BitwiseOp);
diff --git a/sources/shiboken6/ApiExtractor/abstractmetafunction.h b/sources/shiboken6/ApiExtractor/abstractmetafunction.h
index 15192e6de..256a37e7e 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetafunction.h
+++ b/sources/shiboken6/ApiExtractor/abstractmetafunction.h
@@ -73,6 +73,8 @@ public:
ReferenceOperator, // operator &
ArrowOperator,
ArithmeticOperator,
+ IncrementOperator,
+ DecrementOperator,
BitwiseOperator,
LogicalOperator,
ShiftOperator,
@@ -204,6 +206,7 @@ public:
bool isArithmeticOperator() const;
bool isBitwiseOperator() const; // Includes shift operator
bool isComparisonOperator() const;
+ bool isIncDecrementOperator() const;
bool isLogicalOperator() const;
bool isSubscriptOperator() const;
bool isAssignmentOperator() const; // Assignment or move assignment
diff --git a/sources/shiboken6/ApiExtractor/abstractmetalang.cpp b/sources/shiboken6/ApiExtractor/abstractmetalang.cpp
index 20c4bb554..3c33f52bc 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetalang.cpp
+++ b/sources/shiboken6/ApiExtractor/abstractmetalang.cpp
@@ -282,6 +282,17 @@ bool AbstractMetaClass::hasArithmeticOperatorOverload() const
return false;
}
+bool AbstractMetaClass::hasIncDecrementOperatorOverload() const
+{
+ for (const auto & f: d->m_functions) {
+ if (f->ownerClass() == f->implementingClass()
+ && f->isIncDecrementOperator() && !f->isPrivate()) {
+ return true;
+ }
+ }
+ return false;
+}
+
bool AbstractMetaClass::hasBitwiseOperatorOverload() const
{
for (const auto & f: d->m_functions) {
diff --git a/sources/shiboken6/ApiExtractor/abstractmetalang.h b/sources/shiboken6/ApiExtractor/abstractmetalang.h
index f83062dd7..daa9eba1e 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetalang.h
+++ b/sources/shiboken6/ApiExtractor/abstractmetalang.h
@@ -166,6 +166,7 @@ public:
AbstractMetaFunctionCList operatorOverloads(OperatorQueryOptions query) const;
bool hasArithmeticOperatorOverload() const;
+ bool hasIncDecrementOperatorOverload() const;
bool hasBitwiseOperatorOverload() const;
bool hasComparisonOperatorOverload() const;
bool hasLogicalOperatorOverload() const;
diff --git a/sources/shiboken6/ApiExtractor/abstractmetalang_enums.h b/sources/shiboken6/ApiExtractor/abstractmetalang_enums.h
index d2e50acba..c78e84320 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetalang_enums.h
+++ b/sources/shiboken6/ApiExtractor/abstractmetalang_enums.h
@@ -58,13 +58,14 @@ Q_DECLARE_FLAGS(FunctionQueryOptions, FunctionQueryOption)
Q_DECLARE_OPERATORS_FOR_FLAGS(FunctionQueryOptions)
enum class OperatorQueryOption {
- ArithmeticOp = 0x01, // Arithmetic: +, -, *, /, %, +=, -=, *=, /=, %=, ++, --, unary+, unary-
- BitwiseOp = 0x02, // Bitwise: <<, <<=, >>, >>=, ~, &, &=, |, |=, ^, ^=
- ComparisonOp = 0x04, // Comparison: <, <=, >, >=, !=, ==
- LogicalOp = 0x08, // Logical: !, &&, ||
- ConversionOp = 0x10, // Conversion: operator [const] TYPE()
- SubscriptionOp = 0x20, // Subscription: []
- AssignmentOp = 0x40 // Assignment: =
+ ArithmeticOp = 0x01, // Arithmetic: +, -, *, /, %, +=, -=, *=, /=, %=, unary+, unary-
+ IncDecrementOp = 0x02, // ++, --
+ BitwiseOp = 0x04, // Bitwise: <<, <<=, >>, >>=, ~, &, &=, |, |=, ^, ^=
+ ComparisonOp = 0x08, // Comparison: <, <=, >, >=, !=, ==
+ LogicalOp = 0x10, // Logical: !, &&, ||
+ ConversionOp = 0x20, // Conversion: operator [const] TYPE()
+ SubscriptionOp = 0x40, // Subscription: []
+ AssignmentOp = 0x80 // Assignment: =
};
Q_DECLARE_FLAGS(OperatorQueryOptions, OperatorQueryOption)
diff --git a/sources/shiboken6/ApiExtractor/parser/codemodel.cpp b/sources/shiboken6/ApiExtractor/parser/codemodel.cpp
index 5dda974a7..82f5e1a2c 100644
--- a/sources/shiboken6/ApiExtractor/parser/codemodel.cpp
+++ b/sources/shiboken6/ApiExtractor/parser/codemodel.cpp
@@ -961,8 +961,8 @@ static const NameFunctionTypeHash &nameToOperatorFunction()
{u"operator/=", CodeModel::ArithmeticOperator},
{u"operator%", CodeModel::ArithmeticOperator},
{u"operator%=", CodeModel::ArithmeticOperator},
- {u"operator++", CodeModel::ArithmeticOperator},
- {u"operator--", CodeModel::ArithmeticOperator},
+ {u"operator++", CodeModel::IncrementOperator},
+ {u"operator--", CodeModel::DecrementOperator},
{u"operator&", CodeModel::BitwiseOperator},
{u"operator&=", CodeModel::BitwiseOperator},
{u"operator|", CodeModel::BitwiseOperator},
diff --git a/sources/shiboken6/ApiExtractor/parser/codemodel.h b/sources/shiboken6/ApiExtractor/parser/codemodel.h
index c3bda9ef5..75ad60aaf 100644
--- a/sources/shiboken6/ApiExtractor/parser/codemodel.h
+++ b/sources/shiboken6/ApiExtractor/parser/codemodel.h
@@ -73,6 +73,8 @@ public:
ReferenceOperator, // operator &
ArrowOperator,
ArithmeticOperator,
+ IncrementOperator,
+ DecrementOperator,
BitwiseOperator,
LogicalOperator,
ShiftOperator,
diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.cpp b/sources/shiboken6/generator/shiboken/cppgenerator.cpp
index 5a0d2a30f..2e9ea8d0b 100644
--- a/sources/shiboken6/generator/shiboken/cppgenerator.cpp
+++ b/sources/shiboken6/generator/shiboken/cppgenerator.cpp
@@ -209,21 +209,58 @@ QString CppGenerator::fileNameForContext(const GeneratorContext &context) const
return fileNameBase + fileNameSuffix();
}
+static bool isInplaceAdd(const AbstractMetaFunctionCPtr &func)
+{
+ return func->name() == u"operator+=";
+}
+
+static bool isIncrementOperator(const AbstractMetaFunctionCPtr &func)
+{
+ return func->functionType() == AbstractMetaFunction::IncrementOperator;
+}
+
+static bool isDecrementOperator(const AbstractMetaFunctionCPtr &func)
+{
+ return func->functionType() == AbstractMetaFunction::DecrementOperator;
+}
+
+// Filter predicate for operator functions
+static bool skipOperatorFunc(const AbstractMetaFunctionCPtr &func)
+{
+ if (func->isModifiedRemoved() || func->usesRValueReferences())
+ return true;
+ const auto &name = func->name();
+ return name == u"operator[]" || name == u"operator->" || name == u"operator!";
+}
+
QList<AbstractMetaFunctionCList>
CppGenerator::filterGroupedOperatorFunctions(const AbstractMetaClass *metaClass,
OperatorQueryOptions query)
{
// ( func_name, num_args ) => func_list
QMap<QPair<QString, int>, AbstractMetaFunctionCList> results;
- const auto &funcs = metaClass->operatorOverloads(query);
+
+ auto funcs = metaClass->operatorOverloads(query);
+ auto end = std::remove_if(funcs.begin(), funcs.end(), skipOperatorFunc);
+ funcs.erase(end, funcs.end());
+
+ // If we have operator+=, we remove the operator++/-- which would
+ // otherwise be used for emulating __iadd__, __isub__.
+ if (std::any_of(funcs.cbegin(), funcs.cend(), isInplaceAdd)) {
+ end = std::remove_if(funcs.begin(), funcs.end(),
+ [] (const AbstractMetaFunctionCPtr &func) {
+ return func->isIncDecrementOperator();
+ });
+ funcs.erase(end, funcs.end());
+ } else {
+ // If both prefix/postfix ++/-- are present, remove one
+ if (std::count_if(funcs.begin(), funcs.end(), isIncrementOperator) > 1)
+ funcs.erase(std::find_if(funcs.begin(), funcs.end(), isIncrementOperator));
+ if (std::count_if(funcs.begin(), funcs.end(), isDecrementOperator) > 1)
+ funcs.erase(std::find_if(funcs.begin(), funcs.end(), isDecrementOperator));
+ }
+
for (const auto &func : funcs) {
- if (func->isModifiedRemoved()
- || func->usesRValueReferences()
- || func->name() == QLatin1String("operator[]")
- || func->name() == QLatin1String("operator->")
- || func->name() == QLatin1String("operator!")) {
- continue;
- }
int args;
if (func->isComparisonOperator()) {
args = -1;
@@ -663,6 +700,7 @@ void CppGenerator::generateClass(TextStream &s, const GeneratorContext &classCon
const QList<AbstractMetaFunctionCList> opOverloads = filterGroupedOperatorFunctions(
metaClass,
OperatorQueryOption::ArithmeticOp
+ | OperatorQueryOption::IncDecrementOp
| OperatorQueryOption::LogicalOp
| OperatorQueryOption::BitwiseOp);
@@ -3524,9 +3562,10 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
if (func->isReverseOperator())
std::swap(firstArg, secondArg);
+ // Emulate operator+=/-= (__iadd__, __isub__) by using ++/--
if (((op == QLatin1String("++")) || (op == QLatin1String("--"))) && !func->isReverseOperator()) {
s << "\nfor (int i = 0; i < " << secondArg
- << "; ++i, " << firstArg << op << ");\n";
+ << "; ++i, " << op << firstArg << ");\n";
mc << firstArg;
} else {
mc << firstArg << ' ' << op << ' ' << secondArg;
@@ -4113,6 +4152,7 @@ bool CppGenerator::supportsMappingProtocol(const AbstractMetaClass *metaClass)
bool CppGenerator::supportsNumberProtocol(const AbstractMetaClass *metaClass) const
{
return metaClass->hasArithmeticOperatorOverload()
+ || metaClass->hasIncDecrementOperatorOverload()
|| metaClass->hasLogicalOperatorOverload()
|| metaClass->hasBitwiseOperatorOverload()
|| hasBoolCast(metaClass);
@@ -4495,6 +4535,7 @@ void CppGenerator::writeTypeAsNumberDefinition(TextStream &s, const AbstractMeta
const QList<AbstractMetaFunctionCList> opOverloads =
filterGroupedOperatorFunctions(metaClass,
OperatorQueryOption::ArithmeticOp
+ | OperatorQueryOption::IncDecrementOp
| OperatorQueryOption::LogicalOp
| OperatorQueryOption::BitwiseOp);
diff --git a/sources/shiboken6/tests/libsample/CMakeLists.txt b/sources/shiboken6/tests/libsample/CMakeLists.txt
index f734ab935..6e436ee1f 100644
--- a/sources/shiboken6/tests/libsample/CMakeLists.txt
+++ b/sources/shiboken6/tests/libsample/CMakeLists.txt
@@ -16,6 +16,7 @@ exceptiontest.cpp
functions.cpp
handle.cpp
implicitconv.cpp
+intwrapper.cpp
injectcode.cpp
listuser.cpp
modifications.cpp
diff --git a/sources/shiboken6/tests/libsample/collector.cpp b/sources/shiboken6/tests/libsample/collector.cpp
index 398f79918..aca24e355 100644
--- a/sources/shiboken6/tests/libsample/collector.cpp
+++ b/sources/shiboken6/tests/libsample/collector.cpp
@@ -57,6 +57,6 @@ int Collector::size()
Collector &operator<<(Collector &s, const IntWrapper &w)
{
- s << w.value;
+ s << w.toInt();
return s;
}
diff --git a/sources/shiboken6/tests/libsample/collector.h b/sources/shiboken6/tests/libsample/collector.h
index 6d51c624c..bc10a7481 100644
--- a/sources/shiboken6/tests/libsample/collector.h
+++ b/sources/shiboken6/tests/libsample/collector.h
@@ -32,6 +32,7 @@
#include <list>
#include "libsamplemacros.h"
+#include "intwrapper.h"
#include "objecttype.h"
class LIBSAMPLE_API Collector
@@ -57,14 +58,6 @@ private:
};
/* Helper for testing external operators */
-class IntWrapper
-{
-public:
- IntWrapper(int x=0):value(x){}
-
- int value;
-};
-
LIBSAMPLE_API Collector &operator<<(Collector&, const IntWrapper&);
#endif // COLLECTOR_H
diff --git a/sources/shiboken6/tests/libsample/intwrapper.cpp b/sources/shiboken6/tests/libsample/intwrapper.cpp
new file mode 100644
index 000000000..aa1a22874
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/intwrapper.cpp
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "intwrapper.h"
+
+int IntWrapper::toInt() const
+{
+ return m_number;
+}
+
+IntWrapper &IntWrapper::operator ++()
+{
+ ++m_number;
+ return *this;
+}
+
+IntWrapper IntWrapper::operator++(int)
+{
+ IntWrapper result(*this);
+ ++m_number;
+ return result;
+}
+
+IntWrapper &IntWrapper::operator--()
+{
+ --m_number;
+ return *this;
+}
+
+IntWrapper IntWrapper::operator--(int)
+{
+ IntWrapper result(*this);
+ --m_number;
+ return result;
+}
diff --git a/sources/shiboken6/tests/libsample/intwrapper.h b/sources/shiboken6/tests/libsample/intwrapper.h
new file mode 100644
index 000000000..158cff8e1
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/intwrapper.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INTWRAPPER_H
+#define INTWRAPPER_H
+
+#include "libsamplemacros.h"
+
+// Wrapper around int for testing operators
+class LIBSAMPLE_API IntWrapper
+{
+public:
+ constexpr explicit IntWrapper(int i) noexcept : m_number(i) {}
+ int toInt() const;
+
+ IntWrapper &operator++();
+ IntWrapper operator++(int); // Postfix
+
+ IntWrapper &operator--();
+ IntWrapper operator--(int); // Postfix
+
+ friend constexpr inline bool operator==(IntWrapper lhs, IntWrapper rhs) noexcept
+ { return lhs.m_number == rhs.m_number; }
+ friend constexpr inline bool operator!=(IntWrapper lhs, IntWrapper rhs) noexcept
+ { return lhs.m_number != rhs.m_number; }
+ friend constexpr inline bool operator<(IntWrapper lhs, IntWrapper rhs) noexcept
+ { return lhs.m_number < rhs.m_number; }
+ friend constexpr inline bool operator>(IntWrapper lhs, IntWrapper rhs) noexcept
+ { return lhs.m_number > rhs.m_number; }
+ friend constexpr inline bool operator<=(IntWrapper lhs, IntWrapper rhs) noexcept
+ { return lhs.m_number <= rhs.m_number; }
+ friend constexpr inline bool operator>=(IntWrapper lhs, IntWrapper rhs) noexcept
+ { return lhs.m_number >= rhs.m_number; }
+
+ constexpr inline IntWrapper &operator+=(IntWrapper i);
+ constexpr inline IntWrapper &operator-=(const IntWrapper i);
+
+ friend constexpr inline IntWrapper operator+(IntWrapper lhs, IntWrapper rhs) noexcept
+ { return IntWrapper(lhs.m_number + rhs.m_number); }
+ friend constexpr inline IntWrapper operator-(IntWrapper lhs, IntWrapper rhs) noexcept
+ { return IntWrapper(lhs.m_number - rhs.m_number); }
+
+ // FIXME: Test spaceship operator with C++ 20:
+ // auto operator<=>(IntWrapper) const = default;
+
+private:
+ int m_number;
+};
+
+constexpr inline IntWrapper &IntWrapper::operator+=(IntWrapper i)
+{
+ m_number += i.m_number;
+ return *this;
+}
+
+constexpr inline IntWrapper &IntWrapper::operator-=(const IntWrapper i)
+{
+ m_number -= i.m_number;
+ return *this;
+}
+
+#endif // INTWRAPPER_H
diff --git a/sources/shiboken6/tests/samplebinding/intwrapper_test.py b/sources/shiboken6/tests/samplebinding/intwrapper_test.py
new file mode 100644
index 000000000..a2fabf87f
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/intwrapper_test.py
@@ -0,0 +1,61 @@
+# -*- coding: utf-8 -*-
+#
+#############################################################################
+##
+## Copyright (C) 2021 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the test suite of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:GPL-EXCEPT$
+## 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 General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 3 as published by the Free Software
+## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+## 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-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import IntWrapper
+
+
+class IntWrapperTest(unittest.TestCase):
+
+ def testOperators(self):
+ ten1 = IntWrapper(10)
+ ten2 = IntWrapper(10)
+ twenty = IntWrapper(20)
+ self.assertTrue(ten1 == ten2)
+ self.assertTrue(ten1 != twenty)
+ self.assertTrue(ten1 + ten2 == twenty)
+ self.assertTrue(ten1 - ten2 == IntWrapper(0))
+ i = IntWrapper(ten1.toInt())
+ i += ten2
+ self.assertTrue(i == twenty)
+ i -= ten2
+ self.assertTrue(i == ten1)
+
+
+if __name__ == '__main__':
+ unittest.main()