2

When compiling my program using a recent version of OpenVDB library by Clang in C++20 mode, I get the error:

error: use of the 'assume' attribute is a C++23 extension

I see that it is due to the macro OPENVDB_ASSUME conditionally defined as (simplified):

#ifdef __has_cpp_attribute
  #if __has_cpp_attribute(assume) >= 202207L
    #define OPENVDB_ASSUME(...) [[assume(__VA_ARGS__)]]
  #endif
#endif
#ifndef OPENVDB_ASSUME
  #define OPENVDB_ASSUME(...) __builtin_assume(__VA_ARGS__)
#endif

Despite the condition __has_cpp_attribute(assume) >= 202207L, the macro still expands in [[assume]] in C++20 mode. Online demo: https://gcc.godbolt.org/z/fEY5GWc9P

How one has to modify the condition to prevent it, and get C++20 compatible __builtin_assume(__VA_ARGS__) expansion instead?

1
  • 1
    #if __has_cpp_attribute(assume) >= 202207L && __cplusplus >= __has_cpp_attribute(assume) Commented Sep 30 at 19:51

3 Answers 3

5

__has_cpp_attribute(attr) expands to either 0 if the attribute doesn't exist, or the year and month when the specified attribute was introduced.

To check that a specified attribute is available, you want to check that it exists and that the current version of C++ is at least as high as the one when the attribute was introduced, so you want something like

# if __has_cpp_attribute(assume) && __cplusplus >= __has_cpp_attribute(assume)
Sign up to request clarification or add additional context in comments.

Comments

3

It is really unfortunate that Clang decided to put users in this position. Since the intent of

#if __has_cpp_attribute(attr)

Was that if that returns non-zero, that you can... actually use the attribute. Warning after a check means that you suddenly need far more information to do a proper check.

Now, this answer suggests writing:

#if __has_cpp_attribute(assume) && __cplusplus >= __has_cpp_attribute(assume)

This is actually incorrect. The problem here is that the value that __has_cpp_attribute(attr) returns isn't fixed. It might change. For instance, [[nodiscard]] was an attribute that was added in C++17, initially with the value 201603. Then, during C++20, you were allowed to add a reason to it, so it now uses the value 201907.

Imagine I applied the above check to [[nodiscard]]:

#if __has_cpp_attribute(nodiscard) && __cplusplus >= __has_cpp_attribute(nodiscard)
#  define NODISCARD [[nodiscard]]
#else
#  define NODISCARD
#endif

If I'm compiling with clang 9 in c++17 mode, I would get [[nodiscard]]. But with clang 10 in c++17 mode, I would suddenly get nothing — because clang 10 implemented the added [[nodiscard]] functionality, so now our check fails. And we don't get any [[nodiscard]] at all! For example:

#if __has_cpp_attribute(nodiscard) && __cplusplus >= __has_cpp_attribute(nodiscard)
#  define NODISCARD [[nodiscard]]
#else
#  define NODISCARD
#endif

NODISCARD int f() { return 0; }

int main() {
    f(); // warns with clang 9, not with clang 10+
}

Instead, you just have to know.

That is, the specific check you need to write for [[nodiscard]] is this:

#if __has_cpp_attribute(nodiscard) && __cplusplus >= 201603

And likewise the specific check you have to write for assume is

#if __has_cpp_attribute(assume) && __cplusplus >= 202207

Thankfully, you can at least easily find these values in the feature-test document (also via the link wg21.link/sd6). But it would have been nice to not have to do this.

1 Comment

That famous duality "Attributes are ignorable", but actually we don't want that so we get warnings when we encounter that case... I've seen an interesting discussion on a third-party blog post about that recently, with very sensible suggestions regarding that matter.
3

The predefined macro that denotes the version for C++23 is 202302L.

To process code in C++23, you could use the following.

// C++23 (and later) code
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 202302L) || __cplusplus >= 202302L)
        /* code for C++23 or later */
#endif

Changing '202207L' to '202302L' may also work.

Reference: https://en.cppreference.com/w/cpp/preprocessor/replace.html#Predefined_macros

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.