Bug 59526

Summary: [C++11] Defaulted special member functions don't accept noexcept if a member has a non-trivial noexcept operator in the corresponding special member function
Product: gcc Reporter: Philipp Moeller <bootsarehax>
Component: c++Assignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED FIXED    
Severity: normal CC: daniel.kruegler
Priority: P3    
Version: 4.8.2   
Target Milestone: 5.0   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2014-02-09 00:00:00

Description Philipp Moeller 2013-12-16 13:36:32 UTC
The following code fails for struct X on gcc 4.8.2 with:

bla.cpp:15:3: error: function ‘X::X()’ defaulted on its first declaration with an exception-specification that differs from the implicit declaration ‘X::X()’
   X() noexcept = default;

bla.cpp:16:6: error: function ‘X& X::operator=(X&&)’ defaulted on its first declaration with an exception-specification that differs from the implicit declaration ‘X& X::operator=(X&&)’
   X& operator=(X&&) noexcept = default;

#include <type_traits>

template<bool b>
struct F {
  F() noexcept(b) {}
  F& operator=(F&&) noexcept(b) {return *this;}
};

struct Simple {
  Simple() noexcept {}
  Simple& operator=(Simple&&) noexcept {return *this;}
};

struct X {
  X() noexcept = default;
  X& operator=(X&&) noexcept = default;
  F<true> f;
};
struct X2 {
  X2() /* noexcept */ = default;
  X2& operator=(X2&&) /* noexcept */ = default;
  F<true> f;
};
struct X3 {
  X3() noexcept = default;
  X3& operator=(X3&&) noexcept = default;
  Simple f;
};

static_assert(std::is_nothrow_constructible<X>::value, "");
static_assert(std::is_nothrow_move_assignable<X>::value, "");
static_assert(std::is_nothrow_constructible<X2>::value, "");
static_assert(std::is_nothrow_move_assignable<X2>::value, "");
static_assert(std::is_nothrow_constructible<X3>::value, "");
static_assert(std::is_nothrow_move_assignable<X3>::value, "");

X2 shows that a noexcept function is implicitly generated. X3 shows that it is necessary for the noexcept operator to depend on a template parameter to trigger this behavior.
Comment 1 Jonathan Wakely 2014-02-09 15:11:43 UTC
Trunk doesn't give the same errors, but fails two of the assertions:

n.cc:30:1: error: static assertion failed: 
 static_assert(std::is_nothrow_constructible<X>::value, "");
 ^
n.cc:31:1: error: static assertion failed: 
 static_assert(std::is_nothrow_move_assignable<X>::value, "");
 ^
Comment 2 Daniel Krügler 2014-02-09 15:22:52 UTC
(In reply to Jonathan Wakely from comment #1)
> Trunk doesn't give the same errors, but fails two of the assertions:
> 
> n.cc:30:1: error: static assertion failed: 
>  static_assert(std::is_nothrow_constructible<X>::value, "");

The reason seems to be that the compiler makes this a deleted function, arguing 

"'X::X() noexcept' is implicitly deleted because its exception-specification does not match the implicit exception-specification 'noexcept (<uninstantiated>)' X() noexcept = default;"

This looks incorrect to me.
Comment 3 Paolo Carlini 2015-03-19 10:20:47 UTC
This is fixed for 5.0.