Search code examples
c++clinuxclangstandards

Does clang++ treat system headers in a more relaxed way?


The following struct is defined in the Linux system header file /usr/include/sys/inotify.h:

struct inotify_event
{
    int wd;
    uint32_t mask;
    uint32_t cookie;
    uint32_t len;
    char name __flexarr;
};

Please note the last field name, which is a zero-length array. C++17 does not support zero-length array, so, if using struct inotify_event in a C++17 project and compiling it with -pedantic, a compiler warning should be raised.

However, the following code doesn't raise any warning for struct inotify_event. More weird, if I define a struct using zero-length array the same way, the warning is raised as expected.

Compiler options: clang++ -std=c++17 -pedantic main.cpp

#include <sys/inotify.h>

struct inotify_event* p = nullptr; // no warning

struct A
{
    int x;
    char name __flexarr; // warning: flexible array members are a C99 feature
};

int main()
{}

Is there any magic behind clang++ that treats system headers in a more relaxed way?


Solution

  • Is there any magic behind clang++ that treats system-defined headers in a more relaxed way?

    Yes, if we look at the clang documentation for Controlling Diagnostics in System Headers it says:

    Warnings are suppressed when they occur in system headers. By default, an included file is treated as a system header if it is found in an include path specified by -isystem, but this can be overridden in several ways.

    The system_header pragma can be used to mark the current file as being a system header. No warnings will be produced from the location of the pragma onwards within the same file.

    #if foo
    #endif foo // warning: extra tokens at end of #endif directive
    
    #pragma clang system_header
    
    #if foo
    #endif foo // no warning
    

    The –system-header-prefix= and –no-system-header-prefix= command-line arguments can be used to override whether subsets of an include path are treated as system headers. When the name in a #include directive is found within a header search path and starts with a system prefix, the header is treated as a system header. The last prefix on the command-line which matches the specified header name takes precedence.

    For instance:

    $ clang -Ifoo -isystem bar --system-header-prefix=x/ \
        --no-system-header-prefix=x/y/
    

    Here, #include "x/a.h" is treated as including a system header, even if the header is found in foo, and #include "x/y/b.h" is treated as not including a system header, even if the header is found in bar.

    A #include directive which finds a file relative to the current directory is treated as including a system header if the including file is treated as a system header.