Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Program with "noexcept" constructor accepted by gcc, rejected by clang

Tags:

The code:

struct T { T() {} };

struct S
{
    T t;

    S() noexcept = default;
};

int main()
{
//    S s;
}

g++ 4.9.2 accepts this with no errors or warnings, however clang 3.6 and 3.7 report for line 7:

error: exception specification of explicitly defaulted default constructor does not match the calculated one

However, if the line S s; is not commented out, g++ 4.9.2 now reports:

noex.cc: In function 'int main()':
noex.cc:12:7: error: use of deleted function 'S::S()'
     S s;
       ^
noex.cc:7:5: note: 'S::S() noexcept' is implicitly deleted because its  exception-specification does not match the implicit exception-specification ''
     S() noexcept = default;
     ^

Which compiler is right for the original code?


Background:

g++ even allows the following to be added to main:

std::cout << std::is_constructible<S>::value << '\n';

which outputs 0. I encountered this problem when using clang to compile some complicated code that made heavy use of templates, SFINAE and noexcept. In that code S and T are template classes; so the behaviour depends on which types S was instantiated with. Clang rejects it with this error for some types, whereas g++ permits it and the SFINAE works based on is_constructible and similar traits.

like image 564
M.M Avatar asked Apr 07 '15 03:04

M.M


1 Answers

Depends on the version of the standard you are consulting.

N3337 [dcl.fct.def.default]/p2:

An explicitly-defaulted function [...] may have an explicit exception-specification only if it is compatible (15.4) with the exception-specification on the implicit declaration.

which renders your original code ill-formed.

This was changed by CWG issue 1778 to read (N4296 [dcl.fct.def.default]/p3):

If a function that is explicitly defaulted is declared with an exception-specification that is not compatible (15.4) with the exception specification on the implicit declaration, then

  • if the function is explicitly defaulted on its first declaration, it is defined as deleted;
  • otherwise, the program is ill-formed.

which means that the constructor is now merely defined as deleted. (The above wording incorporated changes made by N4285, a post-C++14 paper making some cleanup changes intended to be purely editorial. The N3936 version is substantively the same.)

Presumably GCC implements CWG1778's resolution, while Clang doesn't.

like image 145
T.C. Avatar answered Sep 20 '22 11:09

T.C.