Il 04/09/23 08:13, Yexuan Xiao via Std-Proposals ha scritto:

Abstract

This paper proposes a new syntax for noexcept-specification, noexcept(auto), which deduces the exception specification of a function from its body or member initializer list. This feature aims to simplify the use of conditional noexcept and avoid the redundancy and ugliness of manually writing noexcept expressions.


This idea has been raised a few times in the past, cf. N4473, N3202 and others.


The problems and objections raised by those papers need to be reviewed and analysed for any new proposal to go forward.



Motivation

Since C++11 introduced the noexcept specifier, conditional noexcept has been widely used in the standard library. It is undeniable that noexcept can avoid the compiler generating code to handle exceptions and improve performance (both at compile time and run time). Therefore, [P2517] and [P2401] added conditional noexcept for some simple functions. However, there are still many functions that do not use conditional noexcept, but potentially-throwing, such as ranges algorithms, std::min, std::greater, etc.

I noticed that Microsoft STL orginally added conditional noexcept for std::greater::operator(): [snip]



(P2401 author here)


MS-STL seems to be a bit more generous than other stdlib implementation at sprinkling noexcept; when doing research for P2401 it seems that the presence of a conditional noexcept improves MSVC's debug codegen. Implementations are anyhow allowed to do so by [res.on.exception.handling]/5 .



Proposal

I propose to add noexcept(auto) as a placeholder for noexcept-specification, which is equivalent to noexcept(false), except in the following cases where it is equivalent to noexcept(true):


I don't understand what this means.



This is a classification which is way too simple. What if you re-throw from a catch?


I suspect you really need a long and detailed list, along the lines of [expr.const], to determine what would make a function noexcept(false).



Furthermore, in constexpr if and consteval if, the discarded branch does not participate in this deduction.

Design Decisions

The motivations for this proposal is to simplify the use of conditional noexcept in the standard library and user code.


As noted before, this simplification has to consider a bunch of things:


1) Is it implementable? Does it require full-program analysis? Does it risk hitting implementation-defined limits? Do you run into Rice's theorem? A POC would be very much desirable.


Consider:


void a(int i) noexcept(auto) { if (i > 0) b(i-1); }

void b(int i) noexcept(auto) { if (i > 0) a(i-1); }


What is the compiler supposed to deduce here?




2) Would be acceptable that a "minor" modification of a noexcept(auto) function does, in fact, change its noexcept-ness, with possibly massive consequences for callers?


Say you have a move constructor defined as such:


MyClass::MyClass(MyClass &&other) noexcept(auto)

   data(std::exchange(other.data), nullptr)

{

   countObjectCreated();    // add this for debugging reasons

}



If someone forgets to add noexcept(true) to countObjectCreated(), or simply cannot add it (it's a C function; it's in another library; ...), then now the whole move constructor is noexcept(false) with terrible consequences on algorithms and so on.



My 2 c,

-- 
Giuseppe D'Angelo | giuseppe.dangelo@kdab.com | Senior Software Engineer
KDAB (France) S.A.S., a KDAB Group company
Tel. France +33 (0)4 90 84 08 53, http://www.kdab.com