Date: Sun, 27 Apr 2025 13:20:00 +0100
On Sun, 27 Apr 2025, 00:17 Frederick Virchanza Gotham via Std-Proposals, <
std-proposals_at_[hidden]> wrote:
> The whole 'noexcept' thing has gotten a bit hairy in C++. We've
> already thrown 'throw' specifiers out the window, but even now in
> C++26 the situation isn't ideal, given that people are now writing
> code as follows:
>
> template<typename T>
> bool Func(T &arg) noexcept ( noexcept(++arg) && noexcept((bool)!!arg) )
> {
> ++arg;
> return !!arg;
> }
>
> . . .which is why some people are now asking for:
>
> template<typename T>
> bool Func(T &arg) noexcept(auto)
> {
> ++arg;
> return !!arg;
> }
>
> But anyway let's bring it back to basics for a minute. Consider the
> following program:
>
> int Func1(int const arg)
> {
> throw -1;
> }
>
> int Func2(int const arg) noexcept
> {
> return Func1(arg);
> }
>
> int main(int const argc, char **const argv)
> {
> Func2(42);
> }
>
> I don't know about the rest of you, but I wouldn't want this program
> to compile successfully. I would like a compiler error for the line
> "Func1(arg)" because you're calling a "noexcept(false)" function from
> a "noexcept(true)" function. To force the compiler to reject this
> program, you can add one line to the body of "Func2" as follows:
>
> int Func2(int const arg) noexcept
> {
> static_assert( noexcept( Func1(arg) ) );
> return Func1(arg);
> }
>
> but similar to the first example I gave in this post, things gets a
> bit hairy when you have to duplicate lines of code, something like:
>
> int Func2(int const arg) noexcept
> {
> static_assert( noexcept( Func1(arg & global1 | global2) ) );
> return Func1(arg & global1 | global2);
> }
>
> I think we should have a way of marking a function so that the
> compiler will refuse to compile it if it:
> (1) throws an exception (e.g. by using 'throw' or
> 'std::rethrow_exception')
> or
> (2) calls another function that isn't marked as 'noexcept'
>
> I think this would also allow the compiler to optimise more aggressively.
>
How? The compiler can already see whether the function calls anything which
can throw. It seems to me that with this suggested feature, every function
is either compiled identically to how it's compiled today, or it becomes
ill-formed and doesn't compile at all.
When would this help optimisation?
> Now this is the part where I would suggest a new syntax or a new
> keyword, but I don't want to get too caught up in the little things
> just yet as I'm afraid JW will tear apart my new syntax or new keyword
> without giving much consideration to the essence of the new feature
> I'm trying to invent. But anyway . . . how about the following:
>
> int Func2(int const arg) noexcept(explicit)
> {
> return Func1(arg & global1 | global2);
> }
>
> When the compiler encounters "noexcept(explicit)" tagged onto a
> function definition, it will refuse to compile the function if the
> function satisfies any of the two criteria I mentioned above.
>
> Then there would be a few more little things to consider, such as:
>
> (a) Should we allow the throwing of an exception so long as it's
> caught before leaving the function? (This would have implications for
> the optimiser)
> (b) What happens if 'Func1' is in a 3rd party library compiled by a
> different compiler which has produced a function which _can_ actually
> throw an exception even though it's marked as noexcept? Should this
> just be undefined behaviour?
> (c) Will the name mangling systems have to be extended?
> (d) What happens if the function is given C linkage with extern "C"?
> Or what if some of the called functions have C linkage?
> (e) What about functions like "std::strcmp" that are really "noexcept"
> but aren't marked as such?
>
> But the main thing I'm talking about here is as follows:
> In some instances we want to see a compiler error rather than see
> a runtime error to say that std::terminate was called, in particular
> when writing template functions.
>
> I fed my idea in ChatGPT and asked it to produce one concise paragraph
> describing the benefits this new feature could bring, and it gave me
> back:
>
> "This new feature would be invaluable for writing highly reliable,
> high-performance C++ code by allowing developers to enforce at compile
> time that certain critical functions are truly exception-free. It
> would eliminate hidden runtime risks caused by unexpected exceptions,
> enabling better compiler optimizations, more predictable program
> behavior, and safer use of noexcept functions in performance-sensitive
> contexts like real-time systems, embedded programming, and low-latency
> applications. By making exception guarantees explicit and enforceable,
> it would significantly strengthen the trustworthiness and
> maintainability of large, complex C++ codebases."
>
> Sounds good to me.
>
Well it would do, because you asked chatgpt to summarise your suggested
feature. It didn't evaluate whether any of that (e.g. better optimisations
or more predictable behaviour) is actually true or achievable with this
idea. So this adds nothing of value.
std-proposals_at_[hidden]> wrote:
> The whole 'noexcept' thing has gotten a bit hairy in C++. We've
> already thrown 'throw' specifiers out the window, but even now in
> C++26 the situation isn't ideal, given that people are now writing
> code as follows:
>
> template<typename T>
> bool Func(T &arg) noexcept ( noexcept(++arg) && noexcept((bool)!!arg) )
> {
> ++arg;
> return !!arg;
> }
>
> . . .which is why some people are now asking for:
>
> template<typename T>
> bool Func(T &arg) noexcept(auto)
> {
> ++arg;
> return !!arg;
> }
>
> But anyway let's bring it back to basics for a minute. Consider the
> following program:
>
> int Func1(int const arg)
> {
> throw -1;
> }
>
> int Func2(int const arg) noexcept
> {
> return Func1(arg);
> }
>
> int main(int const argc, char **const argv)
> {
> Func2(42);
> }
>
> I don't know about the rest of you, but I wouldn't want this program
> to compile successfully. I would like a compiler error for the line
> "Func1(arg)" because you're calling a "noexcept(false)" function from
> a "noexcept(true)" function. To force the compiler to reject this
> program, you can add one line to the body of "Func2" as follows:
>
> int Func2(int const arg) noexcept
> {
> static_assert( noexcept( Func1(arg) ) );
> return Func1(arg);
> }
>
> but similar to the first example I gave in this post, things gets a
> bit hairy when you have to duplicate lines of code, something like:
>
> int Func2(int const arg) noexcept
> {
> static_assert( noexcept( Func1(arg & global1 | global2) ) );
> return Func1(arg & global1 | global2);
> }
>
> I think we should have a way of marking a function so that the
> compiler will refuse to compile it if it:
> (1) throws an exception (e.g. by using 'throw' or
> 'std::rethrow_exception')
> or
> (2) calls another function that isn't marked as 'noexcept'
>
> I think this would also allow the compiler to optimise more aggressively.
>
How? The compiler can already see whether the function calls anything which
can throw. It seems to me that with this suggested feature, every function
is either compiled identically to how it's compiled today, or it becomes
ill-formed and doesn't compile at all.
When would this help optimisation?
> Now this is the part where I would suggest a new syntax or a new
> keyword, but I don't want to get too caught up in the little things
> just yet as I'm afraid JW will tear apart my new syntax or new keyword
> without giving much consideration to the essence of the new feature
> I'm trying to invent. But anyway . . . how about the following:
>
> int Func2(int const arg) noexcept(explicit)
> {
> return Func1(arg & global1 | global2);
> }
>
> When the compiler encounters "noexcept(explicit)" tagged onto a
> function definition, it will refuse to compile the function if the
> function satisfies any of the two criteria I mentioned above.
>
> Then there would be a few more little things to consider, such as:
>
> (a) Should we allow the throwing of an exception so long as it's
> caught before leaving the function? (This would have implications for
> the optimiser)
> (b) What happens if 'Func1' is in a 3rd party library compiled by a
> different compiler which has produced a function which _can_ actually
> throw an exception even though it's marked as noexcept? Should this
> just be undefined behaviour?
> (c) Will the name mangling systems have to be extended?
> (d) What happens if the function is given C linkage with extern "C"?
> Or what if some of the called functions have C linkage?
> (e) What about functions like "std::strcmp" that are really "noexcept"
> but aren't marked as such?
>
> But the main thing I'm talking about here is as follows:
> In some instances we want to see a compiler error rather than see
> a runtime error to say that std::terminate was called, in particular
> when writing template functions.
>
> I fed my idea in ChatGPT and asked it to produce one concise paragraph
> describing the benefits this new feature could bring, and it gave me
> back:
>
> "This new feature would be invaluable for writing highly reliable,
> high-performance C++ code by allowing developers to enforce at compile
> time that certain critical functions are truly exception-free. It
> would eliminate hidden runtime risks caused by unexpected exceptions,
> enabling better compiler optimizations, more predictable program
> behavior, and safer use of noexcept functions in performance-sensitive
> contexts like real-time systems, embedded programming, and low-latency
> applications. By making exception guarantees explicit and enforceable,
> it would significantly strengthen the trustworthiness and
> maintainability of large, complex C++ codebases."
>
> Sounds good to me.
>
Well it would do, because you asked chatgpt to summarise your suggested
feature. It didn't evaluate whether any of that (e.g. better optimisations
or more predictable behaviour) is actually true or achievable with this
idea. So this adds nothing of value.
Received on 2025-04-27 12:20:18