Q_DECL_NOTHROW: stronger and more widely available version of Q_DECL_NOEXCEPT
authorMarc Mutz <marc.mutz@kdab.com>
Mon, 6 Aug 2012 23:54:13 +0000 (01:54 +0200)
committerQt by Nokia <qt-info@nokia.com>
Tue, 7 Aug 2012 19:11:55 +0000 (21:11 +0200)
Commit 1adca807 defined Q_DECL_NOEXCEPT to be the same as throw() for the
Microsoft compiler. However, the two are not equivalent:

- C++11 noexcept is defined to call std::terminate() if a noexcept
  function nevertheless encounters an exception.
- MSVC throw() has essentially undefined behaviour in this situation:
  http://msdn.microsoft.com/en-us/library/wfa0edys%28v=vs.100%29
   "Due to code optimizations that might be performed by the C++
    compiler [...] if a function does throw an exception, the program
    may not execute correctly."

So define two macros:

1. Q_DECL_NOEXCEPT/Q_DECL_NOEXCEPT_EXPR always have C++11 behaviour.
   This is expected to be the more efficient implementation if the
   function can actually throw.
2. Q_DECL_NOTHROW means that the function gives the nothrow
   guarantee. It is stronger than noexcept, but not all functions
   that can be marked Q_DECL_NOEXCEPT can be marked Q_DECL_NOTHROW.
   In general Q_DECL_NOTHROW functions need to use a try/catch block
   in order to prevent exceptions from leaving the functions, unless
   you can proove that none of the operations can throw.

For the caller, both macros are equivalent: it can be relied on that
no exception leaves the function.

Change-Id: I32f822a82e06a31cb71d38db438387aee5ec3334
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Marius Storm-Olsen <marius.storm-olsen@nokia.com>
src/corelib/global/qcompilerdetection.h
src/corelib/global/qglobal.cpp

index 64aae8a..be167f2 100644 (file)
 #    define Q_COMPILER_VARIADIC_MACROS
 #  endif
 
-// make sure that these aren't defined when Q_COMPILER_NOEXCEPT is defined
-#  define Q_DECL_NOEXCEPT  throw()
-#  define Q_DECL_NOEXCEPT_EXPR(x)
+/* only defined for MSVC since that's the only compiler that actually optimizes for this */
+/* might get overridden further down when Q_COMPILER_NOEXCEPT is detected */
+#  define Q_DECL_NOTHROW  throw()
 
 #elif defined(__BORLANDC__) || defined(__TURBOC__)
 #  define Q_CC_BOR
 #ifdef Q_COMPILER_NOEXCEPT
 # define Q_DECL_NOEXCEPT noexcept
 # define Q_DECL_NOEXCEPT_EXPR(x) noexcept(x)
-#elif !defined(Q_DECL_NOEXCEPT)
+# ifdef Q_DECL_NOTHROW
+#  undef Q_DECL_NOTHROW /* override with C++11 noexcept if available */
+# endif
+#else
 # define Q_DECL_NOEXCEPT
 # define Q_DECL_NOEXCEPT_EXPR(x)
 #endif
+#ifndef Q_DECL_NOTHROW
+# define Q_DECL_NOTHROW Q_DECL_NOEXCEPT
+#endif
 
 #if defined(Q_COMPILER_ALIGNOF) && !defined(Q_ALIGNOF)
 #  define Q_ALIGNOF(x)  alignof(x)
index 087e33b..61ae53b 100644 (file)
@@ -3014,4 +3014,67 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters)
     otherwise.
 */
 
+/*!
+    \macro Q_DECL_NOTHROW
+    \relates <QtGlobal>
+    \since 5.0
+
+    This macro marks a function as never throwing, under no
+    circumstances. If the function does nevertheless throw, the
+    behaviour is undefined.
+
+    The macro expands to either "throw()", if that has some benefit on
+    the compiler, or to C++11 noexcept, if available, or to nothing
+    otherwise.
+
+    If you need C++11 noexcept semantics, don't use this macro, use
+    Q_DECL_NOEXCEPT/Q_DECL_NOEXCEPT_EXPR instead.
+
+    \sa Q_DECL_NOEXCEPT, Q_DECL_NOEXCEPT_EXPR
+*/
+
+/*!
+    \macro Q_DECL_NOEXCEPT
+    \relates <QtGlobal>
+    \since 5.0
+
+    This macro marks a function as never throwing. If the function
+    does nevertheless throw, the behaviour is defined:
+    std::terminate() is called.
+
+    The macro expands to C++11 noexcept, if available, or to nothing
+    otherwise.
+
+    If you need the operator version of C++11 noexcept, use
+    Q_DECL_NOEXCEPT_EXPR(x).
+
+    If you don't need C++11 noexcept semantics, e.g. because your
+    function can't possibly throw, don't use this macro, use
+    Q_DECL_NOTHROW instead.
+
+    \sa Q_DECL_NOTHROW, Q_DECL_NOEXCEPT_EXPR
+*/
+
+/*!
+    \macro Q_DECL_NOEXCEPT_EXPR(x)
+    \relates <QtGlobal>
+    \since 5.0
+
+    This macro marks a function as non-throwing if \a x is true. If
+    the function does nevertheless throw, the behaviour is defined:
+    std::terminate() is called.
+
+    The macro expands to C++11 noexcept(x), if available, or to
+    nothing otherwise.
+
+    If you need the always-true version of C++11 noexcept, use
+    Q_DECL_NOEXCEPT.
+
+    If you don't need C++11 noexcept semantics, e.g. because your
+    function can't possibly throw, don't use this macro, use
+    Q_DECL_NOTHROW instead.
+
+    \sa Q_DECL_NOTHROW, Q_DECL_NOEXCEPT_EXPR
+*/
+
 QT_END_NAMESPACE