1. Overview
I propose to mark the function .
Currently, this can be done because there can never be an active exception during constant evaluation.  would always return zero during constant evaluation.
Similarly,  would always return a null pointer.
[P2996R1] recommends exceptions as an error handling mechanism for reflections,
during constant evaluation.
If exceptions were throwable in constant expresssions, marking these functions  would simply be part of exception support. However, [P2996R1] is not a prerequisite to this proposal.
2. Motivation
The motivation is the same as allowing - blocks in  functions,
a feature added to C++20 thanks to [P1002R1].
Allowing the use of  in constant expressions makes
metaprogramming easier and eliminates special  cases.
A common use case for  is in the implementation of RAII types which
execute a function upon destruction, but only if an exception was (not) thrown in the current
scope.
This is utilized by  and ; see [N4806].
For example, in the implementation of a  stack, one may write:
constexpr value_type pop () { // Only decrease the size of the stack if no exception was thrown during // copy/move construction of the returned object. // This ensures a strong exception guarantee. std :: scope_success _ {[ this ] { m_size -- ; }}; return std :: move ( top ()); } 
It is reasonable to mark such code , and ideally  would not be an
obstacle to this.
Furthermore, it makes sense to mark ' sister function, .
This is done purely for the purpose of consistency.
I am not aware of any concrete example of ’s
lack of  being an obstacle.
3. Possible implementation
3.1. constexpr  uncaught_exceptions 
constexpr int uncaught_exceptions () noexcept { if consteval { return 0 ; } else { return __uncaught_exceptions_impl (); } } 
It is obviously possible for the user to wrap  like this themselves (e.g. [ScopeLite]), but this is an unnecessary burden.
3.2. constexpr  current_exception 
constexpr exception_ptr current_exception () noexcept { if consteval { return exception_ptr ( nullptr ); } else { return __current_exception_impl (); } } 
3.3. constexpr  exception_ptr 
    would also need to be made a literal type.
All major three standard libraries implement  as a wrapper class for ,
which makes this easily possible.
- 
     
See MSVC STL, exception.
 
Simply mark all special member functions  and if necessary, guard their implementation
with an  block.
It is impossible to create an  that is not a null pointer during constant
evaluations.
3.4. Non-trivial implementations
[P2996R1] suggests allowing  in constant expressions.
This would mean that , ,
and  would no longer have such trivial implementations,
and further functions such as  may be marked .
The bare minimum compiler support needed for this is:
- 
     
The compiler must track all active exceptions "magically", so that
returns the correct amount, andstd :: active_exceptions () returns the current exception. This needs compiler support because such mutable global state normally doesn’t exist in constant expressions.std :: current_exception ()  - 
     
behaves like a type-erased, reference-counted smart pointer. [P2738R1] has been accepted into C++26, addingstd :: exception_ptr cast fromconstexpr . This makes the implementation of such type-erasure invoid * feasible.constexpr std :: exception_ptr  
3.5. Impact on ABI
Multiple functions, including member functions of  would become
inline functions if marked .
To remain ABI-compatible with existing software, it is necessary to emit these inline function
into the runtime library.
libstdc++ already conditionally does this by marking member functions of .
Therefore:
- 
     
libstdc++ is not affected.
 - 
     
MSVC STL already defines all member function of
as inline functions, and is also not affected.exception_ptr  - 
     
libc++ would need to apply similar compatibility measures as libstdc++.
 
4. Proposed wording
The proposed changes are relative to the working draft of the standard as of [N4917].
Update subclause 17.3.2 [version.syn], paragraph 2 as follows:
#define __cpp_lib_constexpr_current_exception 202401L // freestanding, also in <exception> [...] #define __cpp_lib_uncaught_exceptions 201411L 202401L // freestanding, also in <exception> 
Update subclause 17.9.6 [uncaught.exceptions] as follows:
constexpr int uncaught_exceptions () noexcept ; 
Update subclause 17.9.7 [propagation], paragraph 2 as follows:
is a literal type([basic.types.general]) which meets the requirements of Cpp17NullablePointer (Table 36). All expressions which must be valid for a Cpp17NullablePointer are constant expressions for a null value of typeexception_ptr .exception_ptr 
Note: This wording is slightly work-in-progress.
Update subclause 17.9.7 [propagation],  as follows:
constexpr exception_ptr current_exception () noexcept ; 
5. Acknowledgements
The original idea for this paper and a portion of its content have been adopted from a proposal draft by Morwenn.