Bug 59526 - [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
Summary: [C++11] Defaulted special member functions don't accept noexcept if a member ...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.8.2
: P3 normal
Target Milestone: 5.0
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-12-16 13:36 UTC by Philipp Moeller
Modified: 2015-03-19 10:20 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2014-02-09 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
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.