summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2021-03-23 22:29:53 +0100
committerFabian Kosmale <fabian.kosmale@qt.io>2021-04-05 12:39:28 +0200
commit687685f64928ed69b2161f9f2ff4f303bec04967 (patch)
treec9346defc76107534825b683ac70721c3439bcba /src/corelib
parent7304bce4aa0a82f6fdad75ddcc6b1f36165687e1 (diff)
QTypeInfo: Handle T::value_type being equal to T
Fix operator checks for containers whose value_type equals themselves. It does not make sense to recurse on value_type in that case. Thanks to std::disjunction having short-circuiting semantics, we can avoid that issue by checking first whether T is T::value_type. As a drive-by, check for value_type typedef before checking for begin/end in is_container. This works around an issue in gcc <= 8.1, which fails to correctly SFINAE the case where begin and end are private methods. Fixes: QTBUG-89456 Change-Id: I27305a7cfe050f13a279c07f00bc229c01daa25b Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> (cherry picked from commit ce83e56cfeb2806181ec1daade9690f4c90b901c) Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/global/qtypeinfo.h17
1 files changed, 13 insertions, 4 deletions
diff --git a/src/corelib/global/qtypeinfo.h b/src/corelib/global/qtypeinfo.h
index e5914414f2..ec43586765 100644
--- a/src/corelib/global/qtypeinfo.h
+++ b/src/corelib/global/qtypeinfo.h
@@ -227,8 +227,8 @@ template <typename, typename = void>
struct is_container : std::false_type {};
template <typename T>
struct is_container<T, std::void_t<
- std::is_convertible<decltype(std::declval<T>().begin() != std::declval<T>().end()), bool>,
- typename T::value_type
+ typename T::value_type,
+ std::is_convertible<decltype(std::declval<T>().begin() != std::declval<T>().end()), bool>
>> : std::true_type {};
@@ -258,7 +258,11 @@ struct expand_operator_equal_container : expand_operator_equal_tuple<T> {};
// if T::value_type exists, check first T::value_type, then T itself
template<typename T>
struct expand_operator_equal_container<T, true> :
- std::conjunction<expand_operator_equal<typename T::value_type>, expand_operator_equal_tuple<T>> {};
+ std::conjunction<
+ std::disjunction<
+ std::is_same<T, typename T::value_type>, // avoid endless recursion
+ expand_operator_equal<typename T::value_type>
+ >, expand_operator_equal_tuple<T>> {};
// recursively check the template arguments of a tuple like object
template<typename ...T>
@@ -294,7 +298,12 @@ template<typename T, bool>
struct expand_operator_less_than_container : expand_operator_less_than_tuple<T> {};
template<typename T>
struct expand_operator_less_than_container<T, true> :
- std::conjunction<expand_operator_less_than<typename T::value_type>, expand_operator_less_than_tuple<T>> {};
+ std::conjunction<
+ std::disjunction<
+ std::is_same<T, typename T::value_type>,
+ expand_operator_less_than<typename T::value_type>
+ >, expand_operator_less_than_tuple<T>
+ > {};
template<typename ...T>
using expand_operator_less_than_recursive = std::conjunction<expand_operator_less_than<T>...>;