Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-109602

Qt's __has_feature definition causes false negative on feature detection in gcc

    XMLWordPrintable

Details

    • Bug
    • Resolution: Unresolved
    • P2: Important
    • None
    • 6.4.1
    • Core: Other
    • None
    • Linux/Wayland, Linux/X11, Linux/Yocto

    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
      

      https://github.com/abseil/abseil-cpp/blob/c814d4e28b65bb4c492b4d897105971de85c1b6e/absl/base/config.h#L205

      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.

      peppe
      vestbo

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            thiago Thiago Macieira
            simon_gamache Simon Gamache
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

            Dates

              Created:
              Updated:

              Gerrit Reviews

                There are no open Gerrit changes