microsoft / STL

MSVC's implementation of the C++ Standard Library.
Other
10.1k stars 1.49k forks source link

P0533R9 `constexpr` For `<cmath>` And `<cstdlib>` #2530

Open StephanTLavavej opened 2 years ago

StephanTLavavej commented 2 years ago

P0533R9 constexpr For <cmath> And <cstdlib> LWG-3834 Missing constexpr for std::intmax_t math functions in <cinttypes>

Feature-test macro:

#define __cpp_lib_constexpr_cmath 202202L
CaseyCarter commented 2 years ago

We need to investigate this sooner rather than later to determine exactly how we're going to make UCRT functions constexpr. I suspect we'll have to teach the compiler(s) to recognize e.g. ::ldexp and std::ldexp, at least when they appear in constant expressions, and constant-fold them. This is going to involve a lot of joint work and communication with our compiler teams.

AlexGuteniev commented 2 years ago

I think it is implementable without compiler support. You have constexpr bit_cast, you know the representation of floats, you do the math.

Compiler support looks better though. Be sure to have it in clang-cl either.

frederick-vs-ja commented 2 years ago

I don't think compiler support is essentially needed (but may be nice to have). We can ask UCRT not to declare these functions, but to provide some equivalent functions with different names (e.g. __cstd_fabs, which may be suitable to be called at runtime) in C++23 mode. The definitions of existing UCRT functions can be unchanged.

Perhaps we can provide "some equivalent functions with different names" in MSVC STL only, by [[__gnu__::__alias__("...")]] (for clang) or #pragma comment(linker, "/alternatename:...") (for MSVC, see this). For example, we might be able to change our ldexp to have "C++" language linkage in C++23 mode, and hence it will be mangled and won't conflict to the ldexp in UCRT (which has "C" language linkage). And it may call __cstd_ldexp at runtime, where __cstd_ldexp is an alias for the ldexp in UCRT.

fsb4000 commented 2 years ago

a few initial thoughts from LLVM discord: https://discord.com/channels/636084430946959380/636732781086638081/942850475752062989

@ldionne wrote:

Oh! Of course.


// inside <math.h>
int abs(int);

// inside namespace std { constexpr int abs(int) {...} }

// user code: using namespace std; abs(1); // which one is meant?



>Okay.. yeah this is messed up
>
>Geez I don't know how to solve that problem, actually
>
>Well the only way would be for the C standard library version to be constexpr
>
>Either by means of them defining it as such, or the compiler doing some extra nasty magic when it sees these names
>
>However, asking the C library folks to implement something based on something like std::is_constant_evaluated() is not a happy story
StephanTLavavej commented 2 years ago

I've contacted the compiler team about getting support for this.

StephanTLavavej commented 1 year ago

We should ask the compiler team to consider implementing #3789 at the same time to save work.

blackninja9939 commented 3 months ago

The attribute [[msvc::constexpr]] allows "extended constexpr" in C++20 such as calling placement new from within a constexpr function for std::construct_at, could that attribute be extended to allow using these blessed functions in a constant expression?

Seems like the least painful approach in terms of existing blessed constexpr and without needing to reimplement every function manually again

frederick-vs-ja commented 3 months ago

Seems like the least painful approach in terms of existing blessed constexpr and without needing to reimplement every function manually again

I think the crux is the UCRT headers (mainly <math.h> in the case of this issue) - they seem somehow "freezed", so it's unclear whether we can even add attributes to declarations in them. As a result, compiler frontends seemingly need work around this when such a function calls is encountered in constant evaluation.