3

I am learning C++ using the books listed here. In particular, I recently learnt about noexcept using the book C++ Primer. Now, to further clear my concept of the topic and to confirm that I've understood things correctly, I am writing simple programs. One such program that compiles with MSVC and Clang but not with GCC is given below. Demo.

void f() noexcept(5) //accepted by msvc but rejected by gcc
{

}

So my question is which compiler is right here(if any)?

Here are the results for some of the major compilers:

Compiler C++ Version Accepts-Code
GCC C++17 No
GCC C++20 No
Clang C++17 Yes
Clang C++20 No
MSVC C++17 Yes
MSVC C++20 Yes

As we can see the program works with some compilers but not with others. The error in gcc says: error: narrowing conversion of '5' from 'int' to 'bool'

Jason
  • 36,170
  • 5
  • 26
  • 60
Alex
  • 318
  • 1
  • 14
  • 1
    What is 5 supposed to mean? – Macmade Oct 06 '22 at 15:39
  • Looks like ill-formed and compilers accepting code are wrong. – Jason Oct 06 '22 at 15:39
  • 1
    One might assume that 5 is being interpreted as true. – EvilTeach Oct 06 '22 at 15:52
  • This was changed after C++17 from well-formed to ill-formed with [CWG 2039](https://cplusplus.github.io/CWG/issues/2039.html). Cppreference lists it as DR against C++11. Clang implements it as such as well if you use the later version in both your test cases. MSVC seems to have not implemented this. – user17732522 Oct 06 '22 at 18:13
  • https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87724 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95564 related – Language Lawyer Oct 07 '22 at 14:07

1 Answers1

9

TLDR

The program is ill-formed and the respective compilers are wrong in accepting the code because the int prvalue expression 5 is not a contextually converted constant expression of type bool which(if supplied) is required to be a contextually converted constant expression by the noexcept-specifier. Basically, the reason for the program being ill-formed is the same for why bool b{5}; is ill-formed as well i.e., this involves a narrowing conversion.


From exception specification documentation:

1) The exception specification is either defined implicitly, or defined explicitly by using a noexcept-specifier as a suffix of a function declarator

noexcept-specifier:
  noexcept ( constant-expression )
  noexcept
  throw ( )

2) In a noexcept-specifier, the constant-expression, if supplied, shall be a contextually converted constant expression of type bool; that constant expression is the exception specification of the function type in which the noexcept-specifier appears.

(emphasis mine)

This means that for the program to be well-formed the supplied constant expression(which is 5 in our example) needs to be a contextually converted constant expression of type bool.

Now lets see from expr.const#4 whether 5 is a contextually converted constant expression or not:

4.10) A contextually converted constant expression of type bool is an expression, contextually converted to bool, where the converted expression is a constant expression and the conversion sequence contains only the conversions above.

4.7) integral conversions other than narrowing conversions,

And from narrowing conversion

A narrowing conversion is an implicit conversion

  • from an integer type or unscoped enumeration type to an integer type that cannot represent all the values of the original type, except where the source is a constant expression whose value after integral promotions will fit into the target type.

(emphasis mine)

This means that the conversion from int prvalue 5 to bool true is a narrowing conversion and so 5 is not a contextually converted constant expression of type bool and so the program is ill-formed and the respective compilers are wrong in accepting the code.

Basically, the reason for the program being ill-formed is that same as to why bool b{3}; is ill-formed. You can even see the you'll get the same error. Demo


Here is the msvc bug report:

MSVC accepts invalid narrowing conversion

Here is the clang bug report:

Clang accepts invalid narrowing conversion

Jason
  • 36,170
  • 5
  • 26
  • 60