Details
-
Bug
-
Resolution: Unresolved
-
P2: Important
-
None
-
6.4.1
-
None
Description
The qcompilerdetection.h header file defines the __has_feature macro function if it's not already defined by having it systematically return 0 whenever it's called. This was implemented in the following commit: https://github.com/qt/qtbase/commit/c3bd5ffdc8a3b459f18ba6e35fca93e29f3b0ab0
However, __has_feature is a clangism not defined for gcc. Defining __has_feature to systematically return false whenever it is used can be misleading and cause some part of a code base to believe it doesn't have certain features when they are in fact available.
Consider the following:
#include <QObject> #if defined(__has_feature) #if defined(__cpp_exceptions) && !__has_feature(cxx_exceptions) #error "You both have and don't have exceptions enabled." #endif #endif int main() { return 0; }
On gcc, this code will not compile, regardless of whether or not exceptions are present. Removing the QObject include is one way to make the problem go away. This is because QObject transitively make qcompilerdetection.h visible, and thus __has_feature is defined to always return false. (Another would be to compile with clang.)
Under gcc, Qt core collapses the distinction between __has_feature not being defined and some particular c++ feature (like exceptions) not being there.
Where did it cause problems?
Client code or a third party library on which clients have little control may rely on the fact that __has_feature is clang specific to guard against using the macro when using certain tool chains. Qt's definition short circuit this.
This happens in the immer library, at this location: https://github.com/arximboldi/immer/blob/master/immer/config.hpp#L25
Getting a false negative on __has_feature(cxx_exceptions) in gcc causes the library to think it should operate in no exception mode and use assert statements instead of throws. It does so in a way I would argue is surprising. Having a #include <QObject> statement probably shouldn't be synonymous with turning off exceptions in any part of a system. (One could perhaps argue that the client code is at fault here but I doubt it.)
Irrespective of whether or not this plays nicely with client code or the third party libraries clients may use, the idea that the macro
!__has_feature(cxx_exceptions) && __cpp_exceptions
could evaluate to true – as it does in the code snippet provided above – is bizarre.
Possible fix
The abseil library does something similar but with a twist:
#ifdef __has_feature #define ABSL_HAVE_FEATURE(f) __has_feature(f) #else #define ABSL_HAVE_FEATURE(f) 0 #endif
Defining and using __has_feature in this manner means that client code doesn't see its macro "name space" polluted by a spurious __has_feature definition which, arguably, ought to be under the sole control of clang.
The Qt code base could use a QT_HAVE_FEATURE(f) macro.