Date: Fri, 04 Sep 2026 10:30:37 -0300
On Friday, 4 September 2026 07:51:09 Brasilia Standard Time Frederick
Virchanza Gotham via Std-Proposals wrote:
> If you mark a function as 'noexcept(false)', it is free to throw an
> exception up to its caller.
>
> If you mark a function as 'noexcept' or 'noexcept(true)', it will
> never throw an exception up to its caller -- but only because
> 'std::terminate' gets called instead.
>
> If you mark a function as 'noexcept(static)', it will never throw an
> exception up to its caller -- because you'll get a compile-time error
> if any statement inside the function body might throw.
What's the enforcement in case one of them does, despite not being marked so?
Is it going to just call std::terminate()? If so, what's the difference?
How about non-exceptional unwinding mechanisms?
> In C++, when including a header from a C file, you usually do:
>
> extern "C" {
> #include "someClibrary.h"
> }
>
> but now you can also do:
>
> extern "C" noexcept(static) {
> #include "someClibrary.h"
> }
a) wrong
b) never going to happen
This is wrong because C functions *can* throw. Not all C functions are written
in C - they may actually be just C++ content under an extern "C". In fact,
both macOS and the modern Windows Universal C runtime are written in C++.
Further, there are certain C interfaces that are allowed to unwind the stack
through non-exceptional mechanisms and the de facto rule is that they just be
marked noexcept(false) when compiled in C++. Therefore, it's just wrong to
wrap any arbitrary header like that.
Not to mention that doing extern "C" { #include } is a blast from the past,
from the early 90s, and has hardly been needed in modern times. Headers from C
libraries have their own extern "C" wrapper, so adopting this method is just
not going to happen. It's too much work.
> Here's where I would use this new feature:
> (1) I would consistently mark destructors as 'noexcept(static)' --
> as you don't want an exception being thrown while the stack is being
> unwound.
That's an implementation detail. The interface does not need it, because from
the caller's perspective, it's no different than noexcept(true), which is
already the default for destructors.
> (2) When writing C++ code that uses a C library, you want to make
> sure all resources get freed, because you don't want an exception to
> be thrown between "OpenResource" and "CloseResource".
Very true... and irrelevant? How is this applicable to the discussion?
> (3) When calling a C++ function from C -- just for a little added
> assurance that std::terminate won't get called.
Unless you convince WG14 to add the syntax, this is a no-op. The C function
will never see the marker, so it makes no difference to them. In fact, you'll
need to have a different declaration from the definition, so this goes back to
"implementation detail".
> (4) On move-constructors and move-assignment operators. These get
> marked 'noexcept' so that vector reallocation takes the 'move' path,
> but you want to be sure that std::terminate doesn't get called.
Same thing, except that we prefer move constructors to be inline if possible.
> -- but that check is on the declaration, not on the body.
> 'noexcept(static)' is what actually verifies it.
No, the check is on the body.
Virchanza Gotham via Std-Proposals wrote:
> If you mark a function as 'noexcept(false)', it is free to throw an
> exception up to its caller.
>
> If you mark a function as 'noexcept' or 'noexcept(true)', it will
> never throw an exception up to its caller -- but only because
> 'std::terminate' gets called instead.
>
> If you mark a function as 'noexcept(static)', it will never throw an
> exception up to its caller -- because you'll get a compile-time error
> if any statement inside the function body might throw.
What's the enforcement in case one of them does, despite not being marked so?
Is it going to just call std::terminate()? If so, what's the difference?
How about non-exceptional unwinding mechanisms?
> In C++, when including a header from a C file, you usually do:
>
> extern "C" {
> #include "someClibrary.h"
> }
>
> but now you can also do:
>
> extern "C" noexcept(static) {
> #include "someClibrary.h"
> }
a) wrong
b) never going to happen
This is wrong because C functions *can* throw. Not all C functions are written
in C - they may actually be just C++ content under an extern "C". In fact,
both macOS and the modern Windows Universal C runtime are written in C++.
Further, there are certain C interfaces that are allowed to unwind the stack
through non-exceptional mechanisms and the de facto rule is that they just be
marked noexcept(false) when compiled in C++. Therefore, it's just wrong to
wrap any arbitrary header like that.
Not to mention that doing extern "C" { #include } is a blast from the past,
from the early 90s, and has hardly been needed in modern times. Headers from C
libraries have their own extern "C" wrapper, so adopting this method is just
not going to happen. It's too much work.
> Here's where I would use this new feature:
> (1) I would consistently mark destructors as 'noexcept(static)' --
> as you don't want an exception being thrown while the stack is being
> unwound.
That's an implementation detail. The interface does not need it, because from
the caller's perspective, it's no different than noexcept(true), which is
already the default for destructors.
> (2) When writing C++ code that uses a C library, you want to make
> sure all resources get freed, because you don't want an exception to
> be thrown between "OpenResource" and "CloseResource".
Very true... and irrelevant? How is this applicable to the discussion?
> (3) When calling a C++ function from C -- just for a little added
> assurance that std::terminate won't get called.
Unless you convince WG14 to add the syntax, this is a no-op. The C function
will never see the marker, so it makes no difference to them. In fact, you'll
need to have a different declaration from the definition, so this goes back to
"implementation detail".
> (4) On move-constructors and move-assignment operators. These get
> marked 'noexcept' so that vector reallocation takes the 'move' path,
> but you want to be sure that std::terminate doesn't get called.
Same thing, except that we prefer move constructors to be inline if possible.
> -- but that check is on the declaration, not on the body.
> 'noexcept(static)' is what actually verifies it.
No, the check is on the body.
-- Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org Principal Engineer - Intel Data Center - Platform & Sys. Eng.
Received on 2026-09-04 13:30:54
