nemequ / hedley

A C/C++ header to help move #ifdefs out of your code
https://nemequ.github.io/hedley/
Creative Commons Zero v1.0 Universal
774 stars 51 forks source link

Fix v13 build with old AppleClang (Travis "xcode7.3" and "xcode8") #41

Closed mnfdev closed 4 years ago

mnfdev commented 4 years ago

Min code sample:

HEDLEY_WARN_UNUSED_RESULT
HEDLEY_DEPRECATED(1.0.0)
int func()
{
  return 123;
}

Compilation fails in "xcode7.3" (clang-703.0.31) and "xcode8" (clang-800.0.38) Compilation succeeds in "xcode8.3" (clang-802.0.42) and later

Travis CI for this code sample before the patch: https://travis-ci.com/github/mnfdev/test-hedley/builds/175828066 Travis CI for this code sample after the patch: https://travis-ci.com/github/mnfdev/test-hedley/builds/175830179

Compile error:

/Users/travis/build/mnfdev/test-hedley/main.cpp:4:1: error: an attribute list cannot appear here
HEDLEY_DEPRECATED(1.0.0)
^~~~~~~~~~~~~~~~~~~~~~~~
/Users/travis/build/mnfdev/test-hedley/hedley.h:945:81: note: expanded from macro 'HEDLEY_DEPRECATED'
#  define HEDLEY_DEPRECATED(since) HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]])
                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Additional information: I found this compile error after nlohmann/json update from v3.7.3 to v3.8.0 (which uses hedley v13). "include only" code sample failed: https://travis-ci.com/github/mnfdev/test-json/builds/175732659

Preprocessed min code sample looks like this:

__attribute__((__warn_unused_result__))
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wc++98-compat"
[[deprecated("Since " "1.0.0")]]
#pragma clang diagnostic pop
int func()
{
    return 123;
}

and clang from xcode before 8.3 cannot compile it in c++14 mode:

bash-3.2$ xcrun clang --version
Apple LLVM version 8.0.0 (clang-800.0.38)
...
bash-3.2$ xcrun clang -std=c++14 test.cpp 
test.cpp:14:1: error: an attribute list cannot appear here
[[deprecated("Since " "1.0.0")]]
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.

The offered patch overrides HEDLEY_DEPRECATED and HEDLEY_DEPRECATED_FOR macros for xcode before 8.3 (which uses clang-802 from LLVM 3.9.0svn: https://en.wikipedia.org/wiki/Xcode) to use __attribute__(()) instead of [[deprecated]]. Then preprocessed min code sample looks like this:

__attribute__((__warn_unused_result__))
__attribute__((__deprecated__("Since " "1.0.0")))
int func()
{
    return 123;
}

and xcode 7.3 and 8.0 successfully compile it.

nemequ commented 4 years ago

Sorry it has taken so long for me to get to this.

Instead of adding a special case for ancient versions of apple clang, I think it would be better to re-order the definitions a bit so the GNU deprecated attribute is preferred over the C++ attribute.. From the commit message:

he GNU attribute has been supported for much longer, and compilers which claim to support C++14 but don't completely support it (such as xcode 7.3) do exist. GCC and clang have traditionally added flags to enable C and C++ standards and defined the relevant macros when they start working on supporting a standard, not when they finish.

This has the benefit of also covering ancient versions of clang which may have the same problem, and as far as I'm aware we can trust __has_extension(attribute_deprecated_with_message).