---
title: A conservative fix for constexpr
document: P3842R2
audience: LWG
date: 2026-03-26
reply-to:
  - "Ville Voutilainen"
paper-type: proposal
---

*[Ville Voutilainen](mailto:ville.voutilainen@gmail.com)* *2026-03-26*

# A conservative fix for constexpr

## Abstract

The papers [P3818](https://open-std.org/JTC1/SC22/WG21/docs/papers/2025/p3818r1.html) and [P3820](https://open-std.org/JTC1/SC22/WG21/docs/papers/2025/p3820r1.html) explain the background of the problem we have making uncaught_exceptions() and current_exception(). In short, having those function constexpr is a breaking change in some cases.

Due to timing and lateness thereof, it's deemed prudent to just roll back adding constexpr to those functions, and figure out a solution in C++29 for allowing those functionalities in constant expression evaluation. That was the outcome of an LEWG discussion in a September 2025 teleconference.

## Wording

In [exception.syn], remove the constexpr decl-specifiers from these functions:

:::wording

<del>constexpr</del> int uncaught_exceptions() noexcept; using exception_ptr = unspecified ; <ins>constexpr exception_ptr current-exception() noexcept; // exposition only</ins> <del>constexpr</del> exception_ptr current_exception() noexcept; ... template<class T> [[noreturn]] <del>constexpr</del> void throw_with_nested(T&& t); template<class E> <del>constexpr</del> void rethrow_if_nested(const E& e);

:::

Before [uncaught.exceptions]/1, remove the constexpr decl-specifier:

:::wording-remove

<del>constexpr</del> int uncaught_exceptions() noexcept;

:::

Before [propagation]/9, add a new definition above, and remove the constexpr declspecifier:

:::wording

<ins>constexpr exception_ptr current-exception() noexcept; // exposition only</ins> <del>constexpr</del> <ins>exception_ptr current_exception() noexcept;</ins>

:::

In [propagation]/12, edit as follows:

:::wording

template<class E> constexpr exception_ptr make_exception_ptr(E e) noexcept; Effects: Creates an exception_ptr object that refers to a copy of e, as if: try { throw e; } catch(...) { return <del>current_exception</del><ins>current-exception</ins>(); }

:::

Strike the note In [propagation]/13:

:::wording-remove

<del>[Note 5: This function is provided for convenience and efficiency reasons. — end note]</del>

:::

In [except.nested], remove all constexprs:

:::wording-remove

namespace std { class nested_exception { public: <del>constexpr</del> nested_exception() noexcept; <del>constexpr</del> nested_exception(const nested_exception&) noexcept = default; <del>constexpr</del> nested_exception& operator=(const nested_exception&) noexcept = default; <del>constexpr</del> virtual ~nested_exception() = default; // access functions [[noreturn]] <del>constexpr</del> void rethrow_nested() const; <del>constexpr</del> exception_ptr nested_ptr() const noexcept; }; template<class T> [[noreturn]] <del>constexpr</del> void throw_with_nested(T&& t); template<class E> <del>constexpr</del> void rethrow_if_nested(const E& e); }

:::

Before [except.nested]/3, remove the constexpr decl-specifier:

:::wording-remove

<del>constexpr</del> nested_exception() noexcept;

:::

Before [except.nested]/4, remove the constexpr decl-specifier:

:::wording-remove

[[noreturn]] <del>constexpr</del> void rethrow_nested() const;

:::

Before [except.nested]/5, remove the constexpr decl-specifier:

:::wording-remove

<del>constexpr</del> exception_ptr nested_ptr() const noexcept;

:::

Before [except.nested]/6, remove the constexpr decl-specifier:

:::wording-remove

template<class T> [[noreturn]] <del>constexpr</del> void throw_with_nested(T&& t);

:::

Before [except.nested]/9, remove the constexpr decl-specifier:

:::wording-remove

template<class E> <del>constexpr</del> void rethrow_if_nested(const E& e);

:::
