Add Q_IS_ENUM(), and provide as flag in QMetaType::typeFlags()
authorGlenn Watson <glenn.watson@nokia.com>
Tue, 7 Feb 2012 02:25:07 +0000 (12:25 +1000)
committerQt by Nokia <qt-info@nokia.com>
Sun, 11 Mar 2012 22:58:39 +0000 (23:58 +0100)
Add Q_IS_ENUM() macro to determine if a given type is an
enumeration. Use information from that in QMetaType::registerType()
to store whether custom registered metatypes are enums or not.
This information can then be accessed by calling
QMetaType::typeFlags(int type). This is used by the declarative
code to determine whether a custom type in a variant can be safely
cast to an integer, which is required to allow passing non-local
enums as signal/slot params.

Change-Id: I9733837f56af201fa3017b4a22b761437a3c0de4
Reviewed-by: Lars Knoll <lars.knoll@nokia.com>
src/corelib/global/global.pri
src/corelib/global/qisenum.h [new file with mode: 0644]
src/corelib/global/qtypetraits.h [new file with mode: 0644]
src/corelib/kernel/qmetatype.h
tests/auto/corelib/global/qglobal/tst_qglobal.cpp
tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp

index 4912837..58cff6b 100644 (file)
@@ -11,7 +11,9 @@ HEADERS +=  \
         global/qnumeric.h \
         global/qlogging.h \
         global/qtypeinfo.h \
-        global/qsysinfo.h
+        global/qsysinfo.h \
+        global/qisenum.h \
+        global/qtypetraits.h
 
 SOURCES += \
        global/qglobal.cpp \
diff --git a/src/corelib/global/qisenum.h b/src/corelib/global/qisenum.h
new file mode 100644 (file)
index 0000000..c9b6ec6
--- /dev/null
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qglobal.h>
+
+#ifndef QISENUM_H
+#define QISENUM_H
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+#ifndef Q_IS_ENUM
+#  if defined(Q_CC_GNU) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
+#    define Q_IS_ENUM(x) __is_enum(x)
+#  elif defined(Q_CC_MSVC) && defined(_MSC_FULL_VER) && (_MSC_FULL_VER >=140050215)
+#    define Q_IS_ENUM(x) __is_enum(x)
+#  else
+#    include <QtCore/qtypetraits.h>
+#    define Q_IS_ENUM(x) QtPrivate::is_enum<x>::value
+#  endif
+#endif
+
+QT_END_HEADER
+QT_END_NAMESPACE
+
+#endif // QISENUM_H
diff --git a/src/corelib/global/qtypetraits.h b/src/corelib/global/qtypetraits.h
new file mode 100644 (file)
index 0000000..92bd949
--- /dev/null
@@ -0,0 +1,420 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ----
+//
+// This code is compiled directly on many platforms, including client
+// platforms like Windows, Mac, and embedded systems.  Before making
+// any changes here, make sure that you're not breaking any platforms.
+//
+// Define a small subset of tr1 type traits. The traits we define are:
+//   is_integral
+//   is_floating_point
+//   is_pointer
+//   is_enum
+//   is_reference
+//   is_pod
+//   has_trivial_constructor
+//   has_trivial_copy
+//   has_trivial_assign
+//   has_trivial_destructor
+//   remove_const
+//   remove_volatile
+//   remove_cv
+//   remove_reference
+//   add_reference
+//   remove_pointer
+//   is_same
+//   is_convertible
+// We can add more type traits as required.
+
+// Changes from the original implementation:
+//  - Move base types from template_util.h directly into this header.
+//  - Use Qt macros for long long type differences on Windows.
+//  - Enclose in QtPrivate namespace.
+
+#ifndef QTYPETRAITS_H
+#define QTYPETRAITS_H
+
+#include <utility>                  // For pair
+#include "QtCore/qglobal.h"
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+namespace QtPrivate {
+
+// Types small_ and big_ are guaranteed such that sizeof(small_) <
+// sizeof(big_)
+typedef char small_;
+
+struct big_ {
+  char dummy[2];
+};
+
+// Identity metafunction.
+template <class T>
+struct identity_ {
+  typedef T type;
+};
+
+// integral_constant, defined in tr1, is a wrapper for an integer
+// value. We don't really need this generality; we could get away
+// with hardcoding the integer type to bool. We use the fully
+// general integer_constant for compatibility with tr1.
+
+template<class T, T v>
+struct integral_constant {
+  static const T value = v;
+  typedef T value_type;
+  typedef integral_constant<T, v> type;
+};
+
+template <class T, T v> const T integral_constant<T, v>::value;
+
+
+// Abbreviations: true_type and false_type are structs that represent boolean
+// true and false values. Also define the boost::mpl versions of those names,
+// true_ and false_.
+typedef integral_constant<bool, true>  true_type;
+typedef integral_constant<bool, false> false_type;
+typedef true_type  true_;
+typedef false_type false_;
+
+// if_ is a templatized conditional statement.
+// if_<cond, A, B> is a compile time evaluation of cond.
+// if_<>::type contains A if cond is true, B otherwise.
+template<bool cond, typename A, typename B>
+struct if_{
+  typedef A type;
+};
+
+template<typename A, typename B>
+struct if_<false, A, B> {
+  typedef B type;
+};
+
+
+// type_equals_ is a template type comparator, similar to Loki IsSameType.
+// type_equals_<A, B>::value is true iff "A" is the same type as "B".
+//
+// New code should prefer base::is_same, defined in base/type_traits.h.
+// It is functionally identical, but is_same is the standard spelling.
+template<typename A, typename B>
+struct type_equals_ : public false_ {
+};
+
+template<typename A>
+struct type_equals_<A, A> : public true_ {
+};
+
+// and_ is a template && operator.
+// and_<A, B>::value evaluates "A::value && B::value".
+template<typename A, typename B>
+struct and_ : public integral_constant<bool, (A::value && B::value)> {
+};
+
+// or_ is a template || operator.
+// or_<A, B>::value evaluates "A::value || B::value".
+template<typename A, typename B>
+struct or_ : public integral_constant<bool, (A::value || B::value)> {
+};
+
+template <class T> struct is_integral;
+template <class T> struct is_floating_point;
+template <class T> struct is_pointer;
+// MSVC can't compile this correctly, and neither can gcc 3.3.5 (at least)
+#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
+// is_enum uses is_convertible, which is not available on MSVC.
+template <class T> struct is_enum;
+#endif
+template <class T> struct is_reference;
+template <class T> struct is_pod;
+template <class T> struct has_trivial_constructor;
+template <class T> struct has_trivial_copy;
+template <class T> struct has_trivial_assign;
+template <class T> struct has_trivial_destructor;
+template <class T> struct remove_const;
+template <class T> struct remove_volatile;
+template <class T> struct remove_cv;
+template <class T> struct remove_reference;
+template <class T> struct add_reference;
+template <class T> struct remove_pointer;
+template <class T, class U> struct is_same;
+#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
+template <class From, class To> struct is_convertible;
+#endif
+
+// is_integral is false except for the built-in integer types. A
+// cv-qualified type is integral if and only if the underlying type is.
+template <class T> struct is_integral : false_type { };
+template<> struct is_integral<bool> : true_type { };
+template<> struct is_integral<char> : true_type { };
+template<> struct is_integral<unsigned char> : true_type { };
+template<> struct is_integral<signed char> : true_type { };
+#if defined(_MSC_VER)
+// wchar_t is not by default a distinct type from unsigned short in
+// Microsoft C.
+// See http://msdn2.microsoft.com/en-us/library/dh8che7s(VS.80).aspx
+template<> struct is_integral<__wchar_t> : true_type { };
+#else
+template<> struct is_integral<wchar_t> : true_type { };
+#endif
+template<> struct is_integral<short> : true_type { };
+template<> struct is_integral<unsigned short> : true_type { };
+template<> struct is_integral<int> : true_type { };
+template<> struct is_integral<unsigned int> : true_type { };
+template<> struct is_integral<long> : true_type { };
+template<> struct is_integral<unsigned long> : true_type { };
+#if defined(Q_OS_WIN) && !defined(Q_CC_GNU)
+template<> struct is_integral<__int64> : true_type { };
+template<> struct is_integral<unsigned __int64> : true_type { };
+#else
+template<> struct is_integral<long long> : true_type { };
+template<> struct is_integral<unsigned long long> : true_type { };
+#endif
+template <class T> struct is_integral<const T> : is_integral<T> { };
+template <class T> struct is_integral<volatile T> : is_integral<T> { };
+template <class T> struct is_integral<const volatile T> : is_integral<T> { };
+
+// is_floating_point is false except for the built-in floating-point types.
+// A cv-qualified type is integral if and only if the underlying type is.
+template <class T> struct is_floating_point : false_type { };
+template<> struct is_floating_point<float> : true_type { };
+template<> struct is_floating_point<double> : true_type { };
+template<> struct is_floating_point<long double> : true_type { };
+template <class T> struct is_floating_point<const T>
+    : is_floating_point<T> { };
+template <class T> struct is_floating_point<volatile T>
+    : is_floating_point<T> { };
+template <class T> struct is_floating_point<const volatile T>
+    : is_floating_point<T> { };
+
+// is_pointer is false except for pointer types. A cv-qualified type (e.g.
+// "int* const", as opposed to "int const*") is cv-qualified if and only if
+// the underlying type is.
+template <class T> struct is_pointer : false_type { };
+template <class T> struct is_pointer<T*> : true_type { };
+template <class T> struct is_pointer<const T> : is_pointer<T> { };
+template <class T> struct is_pointer<volatile T> : is_pointer<T> { };
+template <class T> struct is_pointer<const volatile T> : is_pointer<T> { };
+
+#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
+
+namespace internal {
+
+template <class T> struct is_class_or_union {
+  template <class U> static small_ tester(void (U::*)());
+  template <class U> static big_ tester(...);
+  static const bool value = sizeof(tester<T>(0)) == sizeof(small_);
+};
+
+// is_convertible chokes if the first argument is an array. That's why
+// we use add_reference here.
+template <bool NotUnum, class T> struct is_enum_impl
+    : is_convertible<typename add_reference<T>::type, int> { };
+
+template <class T> struct is_enum_impl<true, T> : false_type { };
+
+}  // namespace internal
+
+// Specified by TR1 [4.5.1] primary type categories.
+
+// Implementation note:
+//
+// Each type is either void, integral, floating point, array, pointer,
+// reference, member object pointer, member function pointer, enum,
+// union or class. Out of these, only integral, floating point, reference,
+// class and enum types are potentially convertible to int. Therefore,
+// if a type is not a reference, integral, floating point or class and
+// is convertible to int, it's a enum. Adding cv-qualification to a type
+// does not change whether it's an enum.
+//
+// Is-convertible-to-int check is done only if all other checks pass,
+// because it can't be used with some types (e.g. void or classes with
+// inaccessible conversion operators).
+template <class T> struct is_enum
+    : internal::is_enum_impl<
+          is_same<T, void>::value ||
+              is_integral<T>::value ||
+              is_floating_point<T>::value ||
+              is_reference<T>::value ||
+              internal::is_class_or_union<T>::value,
+          T> { };
+
+template <class T> struct is_enum<const T> : is_enum<T> { };
+template <class T> struct is_enum<volatile T> : is_enum<T> { };
+template <class T> struct is_enum<const volatile T> : is_enum<T> { };
+
+#endif
+
+// is_reference is false except for reference types.
+template<typename T> struct is_reference : false_type {};
+template<typename T> struct is_reference<T&> : true_type {};
+
+
+// We can't get is_pod right without compiler help, so fail conservatively.
+// We will assume it's false except for arithmetic types, enumerations,
+// pointers and cv-qualified versions thereof. Note that std::pair<T,U>
+// is not a POD even if T and U are PODs.
+template <class T> struct is_pod
+ : integral_constant<bool, (is_integral<T>::value ||
+                            is_floating_point<T>::value ||
+#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
+                            // is_enum is not available on MSVC.
+                            is_enum<T>::value ||
+#endif
+                            is_pointer<T>::value)> { };
+template <class T> struct is_pod<const T> : is_pod<T> { };
+template <class T> struct is_pod<volatile T> : is_pod<T> { };
+template <class T> struct is_pod<const volatile T> : is_pod<T> { };
+
+
+// We can't get has_trivial_constructor right without compiler help, so
+// fail conservatively. We will assume it's false except for: (1) types
+// for which is_pod is true. (2) std::pair of types with trivial
+// constructors. (3) array of a type with a trivial constructor.
+// (4) const versions thereof.
+template <class T> struct has_trivial_constructor : is_pod<T> { };
+template <class T, class U> struct has_trivial_constructor<std::pair<T, U> >
+  : integral_constant<bool,
+                      (has_trivial_constructor<T>::value &&
+                       has_trivial_constructor<U>::value)> { };
+template <class A, int N> struct has_trivial_constructor<A[N]>
+  : has_trivial_constructor<A> { };
+template <class T> struct has_trivial_constructor<const T>
+  : has_trivial_constructor<T> { };
+
+// We can't get has_trivial_copy right without compiler help, so fail
+// conservatively. We will assume it's false except for: (1) types
+// for which is_pod is true. (2) std::pair of types with trivial copy
+// constructors. (3) array of a type with a trivial copy constructor.
+// (4) const versions thereof.
+template <class T> struct has_trivial_copy : is_pod<T> { };
+template <class T, class U> struct has_trivial_copy<std::pair<T, U> >
+  : integral_constant<bool,
+                      (has_trivial_copy<T>::value &&
+                       has_trivial_copy<U>::value)> { };
+template <class A, int N> struct has_trivial_copy<A[N]>
+  : has_trivial_copy<A> { };
+template <class T> struct has_trivial_copy<const T> : has_trivial_copy<T> { };
+
+// We can't get has_trivial_assign right without compiler help, so fail
+// conservatively. We will assume it's false except for: (1) types
+// for which is_pod is true. (2) std::pair of types with trivial copy
+// constructors. (3) array of a type with a trivial assign constructor.
+template <class T> struct has_trivial_assign : is_pod<T> { };
+template <class T, class U> struct has_trivial_assign<std::pair<T, U> >
+  : integral_constant<bool,
+                      (has_trivial_assign<T>::value &&
+                       has_trivial_assign<U>::value)> { };
+template <class A, int N> struct has_trivial_assign<A[N]>
+  : has_trivial_assign<A> { };
+
+// We can't get has_trivial_destructor right without compiler help, so
+// fail conservatively. We will assume it's false except for: (1) types
+// for which is_pod is true. (2) std::pair of types with trivial
+// destructors. (3) array of a type with a trivial destructor.
+// (4) const versions thereof.
+template <class T> struct has_trivial_destructor : is_pod<T> { };
+template <class T, class U> struct has_trivial_destructor<std::pair<T, U> >
+  : integral_constant<bool,
+                      (has_trivial_destructor<T>::value &&
+                       has_trivial_destructor<U>::value)> { };
+template <class A, int N> struct has_trivial_destructor<A[N]>
+  : has_trivial_destructor<A> { };
+template <class T> struct has_trivial_destructor<const T>
+  : has_trivial_destructor<T> { };
+
+// Specified by TR1 [4.7.1]
+template<typename T> struct remove_const { typedef T type; };
+template<typename T> struct remove_const<T const> { typedef T type; };
+template<typename T> struct remove_volatile { typedef T type; };
+template<typename T> struct remove_volatile<T volatile> { typedef T type; };
+template<typename T> struct remove_cv {
+  typedef typename remove_const<typename remove_volatile<T>::type>::type type;
+};
+
+
+// Specified by TR1 [4.7.2] Reference modifications.
+template<typename T> struct remove_reference { typedef T type; };
+template<typename T> struct remove_reference<T&> { typedef T type; };
+
+template <typename T> struct add_reference { typedef T& type; };
+template <typename T> struct add_reference<T&> { typedef T& type; };
+
+// Specified by TR1 [4.7.4] Pointer modifications.
+template<typename T> struct remove_pointer { typedef T type; };
+template<typename T> struct remove_pointer<T*> { typedef T type; };
+template<typename T> struct remove_pointer<T* const> { typedef T type; };
+template<typename T> struct remove_pointer<T* volatile> { typedef T type; };
+template<typename T> struct remove_pointer<T* const volatile> {
+  typedef T type; };
+
+// Specified by TR1 [4.6] Relationships between types
+template<typename T, typename U> struct is_same : public false_type { };
+template<typename T> struct is_same<T, T> : public true_type { };
+
+// Specified by TR1 [4.6] Relationships between types
+#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
+namespace internal {
+
+// This class is an implementation detail for is_convertible, and you
+// don't need to know how it works to use is_convertible. For those
+// who care: we declare two different functions, one whose argument is
+// of type To and one with a variadic argument list. We give them
+// return types of different size, so we can use sizeof to trick the
+// compiler into telling us which function it would have chosen if we
+// had called it with an argument of type From.  See Alexandrescu's
+// _Modern C++ Design_ for more details on this sort of trick.
+
+template <typename From, typename To>
+struct ConvertHelper {
+  static small_ Test(To);
+  static big_ Test(...);
+  static From Create();
+};
+}  // namespace internal
+
+// Inherits from true_type if From is convertible to To, false_type otherwise.
+template <typename From, typename To>
+struct is_convertible
+    : integral_constant<bool,
+                        sizeof(internal::ConvertHelper<From, To>::Test(
+                                  internal::ConvertHelper<From, To>::Create()))
+                        == sizeof(small_)> {
+};
+#endif
+
+}
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif  // QTYPETRAITS_H
index eacb840..0010c27 100644 (file)
@@ -45,6 +45,7 @@
 #include <QtCore/qglobal.h>
 #include <QtCore/qatomic.h>
 #include <QtCore/qbytearray.h>
+#include <QtCore/qisenum.h>
 
 #include <new>
 
@@ -209,7 +210,8 @@ public:
         NeedsConstruction = 0x1,
         NeedsDestruction = 0x2,
         MovableType = 0x4,
-        PointerToQObject = 0x8
+        PointerToQObject = 0x8,
+        IsEnumeration = 0x10
     };
     Q_DECLARE_FLAGS(TypeFlags, TypeFlag)
 
@@ -455,6 +457,8 @@ int qRegisterMetaType(const char *typeName
     }
     if (QtPrivate::IsPointerToTypeDerivedFromQObject<T>::Value)
         flags |= QMetaType::PointerToQObject;
+    if (Q_IS_ENUM(T))
+        flags |= QMetaType::IsEnumeration;
 
     return QMetaType::registerType(typeName, qMetaTypeDeleteHelper<T>,
                                    qMetaTypeCreateHelper<T>,
index 8fedaf4..b3d76be 100644 (file)
 
 
 #include <QtTest/QtTest>
+#include <QtCore/qtypetraits.h>
 
 class tst_QGlobal: public QObject
 {
     Q_OBJECT
+
 private slots:
     void qIsNull();
     void for_each();
@@ -53,6 +55,7 @@ private slots:
     void checkptr();
     void qstaticassert();
     void qConstructorFunction();
+    void isEnum();
 };
 
 void tst_QGlobal::qIsNull()
@@ -293,5 +296,124 @@ void tst_QGlobal::qConstructorFunction()
     QCOMPARE(qConstructorFunctionValue, 123);
 }
 
+struct isEnum_A {
+    int n_;
+};
+
+enum isEnum_B_Byte { isEnum_B_Byte_x = 63 };
+enum isEnum_B_Short { isEnum_B_Short_x = 1024 };
+enum isEnum_B_Int { isEnum_B_Int_x = 1 << 20 };
+
+union isEnum_C {};
+
+class isEnum_D {
+public:
+    operator int() const;
+};
+
+class isEnum_E {
+private:
+    operator int() const;
+};
+
+class isEnum_F {
+public:
+    enum AnEnum {};
+};
+
+#if defined (Q_COMPILER_CLASS_ENUM)
+enum class isEnum_G : qint64 {};
+#endif
+
+void tst_QGlobal::isEnum()
+{
+#if defined (Q_CC_MSVC)
+#define IS_ENUM_TRUE(x)     (Q_IS_ENUM(x) == true)
+#define IS_ENUM_FALSE(x)    (Q_IS_ENUM(x) == false)
+#else
+#define IS_ENUM_TRUE(x)     (Q_IS_ENUM(x) == true && QtPrivate::is_enum<x>::value == true)
+#define IS_ENUM_FALSE(x)    (Q_IS_ENUM(x) == false && QtPrivate::is_enum<x>::value == false)
+#endif
+
+    QVERIFY(IS_ENUM_TRUE(isEnum_B_Byte));
+    QVERIFY(IS_ENUM_TRUE(const isEnum_B_Byte));
+    QVERIFY(IS_ENUM_TRUE(volatile isEnum_B_Byte));
+    QVERIFY(IS_ENUM_TRUE(const volatile isEnum_B_Byte));
+
+    QVERIFY(IS_ENUM_TRUE(isEnum_B_Short));
+    QVERIFY(IS_ENUM_TRUE(const isEnum_B_Short));
+    QVERIFY(IS_ENUM_TRUE(volatile isEnum_B_Short));
+    QVERIFY(IS_ENUM_TRUE(const volatile isEnum_B_Short));
+
+    QVERIFY(IS_ENUM_TRUE(isEnum_B_Int));
+    QVERIFY(IS_ENUM_TRUE(const isEnum_B_Int));
+    QVERIFY(IS_ENUM_TRUE(volatile isEnum_B_Int));
+    QVERIFY(IS_ENUM_TRUE(const volatile isEnum_B_Int));
+
+    QVERIFY(IS_ENUM_TRUE(isEnum_F::AnEnum));
+    QVERIFY(IS_ENUM_TRUE(const isEnum_F::AnEnum));
+    QVERIFY(IS_ENUM_TRUE(volatile isEnum_F::AnEnum));
+    QVERIFY(IS_ENUM_TRUE(const volatile isEnum_F::AnEnum));
+
+    QVERIFY(IS_ENUM_FALSE(void));
+    QVERIFY(IS_ENUM_FALSE(isEnum_B_Byte &));
+    QVERIFY(IS_ENUM_FALSE(isEnum_B_Byte[1]));
+    QVERIFY(IS_ENUM_FALSE(const isEnum_B_Byte[1]));
+    QVERIFY(IS_ENUM_FALSE(isEnum_B_Byte[]));
+    QVERIFY(IS_ENUM_FALSE(int));
+    QVERIFY(IS_ENUM_FALSE(float));
+    QVERIFY(IS_ENUM_FALSE(isEnum_A));
+    QVERIFY(IS_ENUM_FALSE(isEnum_A *));
+    QVERIFY(IS_ENUM_FALSE(const isEnum_A));
+    QVERIFY(IS_ENUM_FALSE(isEnum_C));
+    QVERIFY(IS_ENUM_FALSE(isEnum_D));
+    QVERIFY(IS_ENUM_FALSE(isEnum_E));
+    QVERIFY(IS_ENUM_FALSE(void()));
+    QVERIFY(IS_ENUM_FALSE(void(*)()));
+    QVERIFY(IS_ENUM_FALSE(int isEnum_A::*));
+    QVERIFY(IS_ENUM_FALSE(void (isEnum_A::*)()));
+
+    QVERIFY(IS_ENUM_FALSE(size_t));
+    QVERIFY(IS_ENUM_FALSE(bool));
+    QVERIFY(IS_ENUM_FALSE(wchar_t));
+
+    QVERIFY(IS_ENUM_FALSE(char));
+    QVERIFY(IS_ENUM_FALSE(unsigned char));
+    QVERIFY(IS_ENUM_FALSE(short));
+    QVERIFY(IS_ENUM_FALSE(unsigned short));
+    QVERIFY(IS_ENUM_FALSE(int));
+    QVERIFY(IS_ENUM_FALSE(unsigned int));
+    QVERIFY(IS_ENUM_FALSE(long));
+    QVERIFY(IS_ENUM_FALSE(unsigned long));
+
+    QVERIFY(IS_ENUM_FALSE(qint8));
+    QVERIFY(IS_ENUM_FALSE(quint8));
+    QVERIFY(IS_ENUM_FALSE(qint16));
+    QVERIFY(IS_ENUM_FALSE(quint16));
+    QVERIFY(IS_ENUM_FALSE(qint32));
+    QVERIFY(IS_ENUM_FALSE(quint32));
+    QVERIFY(IS_ENUM_FALSE(qint64));
+    QVERIFY(IS_ENUM_FALSE(quint64));
+
+    QVERIFY(IS_ENUM_FALSE(void *));
+    QVERIFY(IS_ENUM_FALSE(int *));
+
+#if defined (Q_COMPILER_UNICODE_STRINGS)
+    QVERIFY(IS_ENUM_FALSE(char16_t));
+    QVERIFY(IS_ENUM_FALSE(char32_t));
+#endif
+
+#if defined (Q_COMPILER_CLASS_ENUM)
+    // Strongly type class enums are not handled by the
+    // fallback type traits implementation. Any compiler
+    // supported by Qt that supports C++0x class enums
+    // should also support the __is_enum intrinsic.
+    QVERIFY(Q_IS_ENUM(isEnum_G) == true);
+#endif
+
+#undef IS_ENUM_TRUE
+#undef IS_ENUM_FALSE
+}
+
 QTEST_MAIN(tst_QGlobal)
 #include "tst_qglobal.moc"
index 3c21a50..bc5fa27 100644 (file)
@@ -94,6 +94,7 @@ private slots:
     void isRegistered();
     void isRegisteredStaticLess_data();
     void isRegisteredStaticLess();
+    void isEnum();
     void registerStreamBuiltin();
     void automaticTemplateRegistration();
 };
@@ -1042,6 +1043,39 @@ void tst_QMetaType::isRegistered()
     QCOMPARE(QMetaType::isRegistered(typeId), registered);
 }
 
+enum isEnumTest_Enum0 {};
+struct isEnumTest_Struct0 { enum A{}; };
+
+enum isEnumTest_Enum1 {};
+struct isEnumTest_Struct1 {};
+
+Q_DECLARE_METATYPE(isEnumTest_Struct1)
+Q_DECLARE_METATYPE(isEnumTest_Enum1)
+
+void tst_QMetaType::isEnum()
+{
+    int type0 = qRegisterMetaType<int>("int");
+    QVERIFY((QMetaType::typeFlags(type0) & QMetaType::IsEnumeration) == 0);
+
+    int type1 = qRegisterMetaType<isEnumTest_Enum0>("isEnumTest_Enum0");
+    QVERIFY((QMetaType::typeFlags(type1) & QMetaType::IsEnumeration) == QMetaType::IsEnumeration);
+
+    int type2 = qRegisterMetaType<isEnumTest_Struct0>("isEnumTest_Struct0");
+    QVERIFY((QMetaType::typeFlags(type2) & QMetaType::IsEnumeration) == 0);
+
+    int type3 = qRegisterMetaType<isEnumTest_Enum0 *>("isEnumTest_Enum0 *");
+    QVERIFY((QMetaType::typeFlags(type3) & QMetaType::IsEnumeration) == 0);
+
+    int type4 = qRegisterMetaType<isEnumTest_Struct0::A>("isEnumTest_Struct0::A");
+    QVERIFY((QMetaType::typeFlags(type4) & QMetaType::IsEnumeration) == QMetaType::IsEnumeration);
+
+    int type5 = ::qMetaTypeId<isEnumTest_Struct1>();
+    QVERIFY((QMetaType::typeFlags(type5) & QMetaType::IsEnumeration) == 0);
+
+    int type6 = ::qMetaTypeId<isEnumTest_Enum1>();
+    QVERIFY((QMetaType::typeFlags(type6) & QMetaType::IsEnumeration) == QMetaType::IsEnumeration);
+}
+
 void tst_QMetaType::isRegisteredStaticLess_data()
 {
     isRegistered_data();