-
Notifications
You must be signed in to change notification settings - Fork 109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add macros for conditional constexpr #152
Conversation
Codecov ReportBase: 97.39% // Head: 97.94% // Increases project coverage by
Additional details and impacted files@@ Coverage Diff @@
## master #152 +/- ##
==========================================
+ Coverage 97.39% 97.94% +0.55%
==========================================
Files 131 133 +2
Lines 10248 10865 +617
==========================================
+ Hits 9981 10642 +661
+ Misses 267 223 -44
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. ☔ View full report at Codecov. |
src/Corrade/configure.h.cmake
Outdated
#define CORRADE_CXX14_CONSTEXPR constexpr | ||
#else | ||
#define CORRADE_CXX14_CONSTEXPR | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's already CORRADE_CONSTEXPR14 in Corrade/Utility/Macros.h
, and I'd like the other two to follow a similar naming and be in the same header.
But also please see my comment in mosra/magnum#597 about having a special macro for C++14+ constexpr only if a "is constant evaluated" builtin is available.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright. Seems like my original proposal wasn't sufficient for what we're trying to achieve. It's not too useful for any of CORRADE_CONSTEXPR{17,20,23}
to be defined -- C++14 relaxed constexpr is already enough for anything Vector has to handle. But CORRADE_CONSTEXPR14
needs to reflect whether it works in practice (__cpp_constexpr
is accurate here). Then we have several kinds of constexpr functions:
- C++11 semantics --
constexpr
- constexpr with C++14 rules, no need for inline asm or intrinsics --
CORRADE_CONSTEXPR14
- ones that need SIMD --
CORRADE_CONSTEVAL14
, #ifndefCORRADE_CONSTEVAL
The last case can be used like that:
template<typename T>
CORRADE_CONSTEVAL14 inline T foo(T x)
{
#ifdef CORRADE_CONSTEVAL
if CORRADE_CONSTEVAL
{
// do something traditional to 'x'
}
else
#endif
{
// do something funny to 'x'
}
}
If you want to enable constexpr when lacking CORRADE_CONSTEVAL
but when SIMD has been disabled, then it could be set to constexpr(true)
as long as __cpp_if_constexpr >= 201606
holds (aka C++17).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's better to remove CORRADE_CONSTEVAL14
from this pull request and put it in Magnum with a name such as MAGNUM_VECTOR_CONSTEVAL14
. It's too specialized for a global definition. Here it is for reference:
#ifdef CORRADE_CONSTEVAL
#define CORRADE_CONSTEVAL14 CORRADE_CONSTEXPR14
#else
#define CORRADE_CONSTEVAL14
#endif
a727881
to
7220cb9
Compare
38044a3
to
5723da7
Compare
src/Corrade/Utility/Macros.h
Outdated
@@ -394,12 +394,19 @@ Expands to @cpp constexpr @ce on C++14 and newer, empty on C++11. Useful for | |||
selectively marking functions that make use of C++14 relaxed constexpr rules. | |||
@see @ref CORRADE_CXX_STANDARD | |||
*/ | |||
#if CORRADE_CXX_STANDARD >= 201402 | |||
#if defined __cpp_constexpr && __cpp_constexpr >= 201304 || \ | |||
defined CORRADE_TARGET_MSVC && _MSC_VER >= 1910 && CORRADE_CXX_STANDARD >= 201402L |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this contain a bunch of parentheses, to ensure &&
and ||
are evaluated in the correct order? Same below.
Also, TIL that defined
can be without parentheses. Nevertheless, could you add them there, just for consistency with all other occurences of defined()
? Thanks.
What's the L
needed for? I don't think it's essential. Or do you get some compiler warnings without?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this contain a bunch of parentheses, to ensure && and || are evaluated in the correct order?
It always binds tightest in the order: >=
, &&
, ||
. I'm going to add the parentheses anyway.
What's the L needed for? I don't think it's essential.
Good to know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to add the parentheses anyway.
Thank you :) I can never remember the order, and GCC sometimes warns about "|| within &&" and such if I forget the braces, so I suspect it's always different that I would expect :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This table always helps: https://en.cppreference.com/w/cpp/language/operator_precedence.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait so the second MSVC-specific part is no longer needed? I don't see it in the last revision.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! It was only in the Magnum PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is still missing the parentheses...
src/Corrade/Utility/Macros.h
Outdated
@@ -394,12 +394,19 @@ Expands to @cpp constexpr @ce on C++14 and newer, empty on C++11. Useful for | |||
selectively marking functions that make use of C++14 relaxed constexpr rules. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the macro is quite a bit more complex now, I'm thinking a test could be a good idea -- there's src/Corrade/Utility/MacrosCppXYTest.cpp
which currently test C++17 and 20 features, so a new MacrosCpp14Test.cpp
(built only on C++14-capable compilers) would contain a test for this macro:
...
CORRADE_CONSTEXPR14 int sumInAStupidWay(int number) {
int sum = 0;
for(int i = 0; i != number; ++i)
sum += i;
return sum;
}
void MacrosCpp14Test::constexpr14() {
#ifndef CORRADE_CONSTEXPR14 // errr, test if it's actually non-empty, in some way
CORRADE_SKIP("CORRADE_CONSTEXPR14 not available on this compiler.");
#else
constexpr int sum = sumInAStupidWay(17);
CORRADE_COMPARE(sum, 153);
#endif
}
}}}}
CORRADE_TEST_MAIN(Corrade::Utility::Test::MacrosCpp14Test)
Because without the test it's hard to verify that the macro is actually correctly defined only where C++14 constexpr works.
And the docs should be extended to mention the compiler versions on which the macro is defined.
Oh, and similar test for the other macro, there's already a MacrosCpp20Test.cpp
so just add a new case there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally when testing constexpr functions I recommend putting the compiler in a situation where it can't weasel out of performing the computation at compile-time. Hence the static assert.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, good idea. Except that now you're using the C++17 variant of it ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I managed to test whether the function is constexpr through SFINAE.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still needs the documentation update...
9f1acfa
to
ba036e1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👀
MacrosCpp14Test::MacrosCpp14Test() { | ||
addTests({&MacrosCpp14Test::constexpr14}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you follow the same method order as in other tests? Constructor first, helper functions defined next to where they get used, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🆗
template<int> struct sfinae : std::true_type{}; | ||
template<class T> sfinae<(T::sumInAStupidWay(0), 0)> check(int); | ||
template<class> std::false_type check(...); | ||
template<class T> struct hasRelaxedConstexpr : decltype(check<T>(0)){}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But this way you're not testing if the macro is actually defined to constexpr
when it should be, no? Like, the test would pass even if CORRADE_CONSTEXPR14
would be empty always, or if you wouldn't use it at all.
... and you're not using the static assert anymore :P
There really needs to be something based on whether the macro is empty or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, so I added an #if 0
so that it can be verified. Sadly static assert broke the build.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like this solution, to be honest. Because it requires manual fiddling with the #if 0
, it's impossible to test on the CI, and thus it's the same as if the whole test file wouldn't be here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What then, you want the test to fail rather than skip?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test would pass even if CORRADE_CONSTEXPR14
wasn't used anywhere in it, that's the problem I have with it. It's not testing the thing it should be testing, so it's useless.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'll skip on an old compiler, that's why that sfinae logic is there in the first place. Toggle the #if 0
and see.
302d124
to
6d68526
Compare
Actually, I'm still not sure what is the main reason the change to Apart from MSVC, are there any relevant compilers that report C++14 as supported via the Then, for MSVC, isn't it just about excluding MSVC 2015? It would boil down to #if CORRADE_CXX_STANDARD >= 201402 && !defined(CORRADE_MSVC2015_COMPATIBILITY)
#define CORRADE_CONSTEXPR14 constexpr
...
#endif and using void MacrosCpp14Test::constexpr14() {
#ifdef CORRADE_MSVC2015_COMPATIBILITY
CORRADE_SKIP("CORRADE_CONSTEXPR14 not available on MSVC2015.");
#else
constexpr int sum = sumInAStupidWay(17);
CORRADE_COMPARE(sum, 153);
#endif
} [Sorry for the accidental close, pressed too many buttons at once.] |
Compilers tend to expose https://gcc.gnu.org/projects/cxx-status.html -- 4.3 -> 5.0*
The whole point is to handle that for cases such as Magnum vector code. Or am I meant to litter it with |
Yes, I'm not trying to solve the general case of "is feature X supported completely and without bugs on compiler Y", here it's just about having the simplest possible condition for "is C++14 constexpr supported on compilers we care about", and since C++14 is rather old and the relevant compilers are dying out, it can be coarser than, say, checking for
What? Why? The whole point here is to define the macro in a way that does the right thing without a need for extra checks every time it's used, and have a test that verifies it indeed does the right thing. I guess easiest is if I just do the thing instead of talking about it. The |
src/Corrade/Utility/Macros.h
Outdated
#if (defined(__clang__) && __clang_major__ >= 9) || (defined(__GNUG__) && __GNUG__ >= 9) || (defined(_MSC_VER) && _MSC_VER >= 1931) | ||
#define CORRADE_CONSTEVAL (__builtin_is_constant_evaluated()) | ||
#elif CORRADE_CXX_STANDARD >= 202002 | ||
#define CORRADE_CONSTEVAL (std::is_constant_evaluated()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this depends on <type_traits>
, I'm thinking the macro should go to TypeTraits.h
instead. The Macros.h
header deliberately doesn't pull in any STL headers.
src/Corrade/Utility/Macros.h
Outdated
extension. In which case it may be used under C++14 relaxed constexpr rules. | ||
*/ | ||
#if (defined(__clang__) && __clang_major__ >= 9) || (defined(__GNUG__) && __GNUG__ >= 9) || (defined(_MSC_VER) && _MSC_VER >= 1931) | ||
#define CORRADE_CONSTEVAL (__builtin_is_constant_evaluated()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm thinking CORRADE_IS_CONSTANT_EVALUATED
would be a less confusing name.
src/Corrade/Utility/Macros.h
Outdated
This support is available on all C++20 capable compilers, but also certain | ||
ones (Clang 9, GCC 9, MSVC 17.1) that expose the feature as a non-portable | ||
extension. In which case it may be used under C++14 relaxed constexpr rules. | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the docs, now it's just a test missing :) TypeTraitsCpp20Test.cpp
c95cbd4
to
e6c22d0
Compare
Note, it's specifically not meant to be used as |
This is useful for future SIMD support in Magnum vectors. v2: Add test.
e6c22d0
to
a0a1601
Compare
This is going to be used in Magnum vectors.