Problem with default member initialization and noexcept default constructor

I’m seeing an error that is similar to the question raised at https://stackoverflow.com/questions/43819314. That question seems to not have any consensus as to what the problem may be.

I would appreciate if someone could shed some light on my issue and let me know if this is a known compiler bug or if clang is working as intended.

The following code produces a compile-time error in clang++ 4.0.0 and later, but works fine in gcc as well as previous versions of clang.

#include

struct A {
A() noexcept = default;
A(const A&) noexcept = default;

std::shared_ptr _a {};
};

int main() {
return 0;
}

It’s worth noting that if I remove the copy constructor, this compiles fine. If I remove the noexcept qualification from the default constructor it also compiles fine.

The error I’m getting is as follows:

:4:5: error: default member initializer for '_a' needed within definition of enclosing class 'A' outside of member functions A() noexcept = default; ^ /opt/compiler-explorer/clang-4.0.0/bin/../include/c++/v1/type_traits:1306:29: note: in instantiation of template class 'std::__1::is_class' requested here template ::value> ^ /opt/compiler-explorer/clang-4.0.0/bin/../include/c++/v1/type_traits:1311:71: note: in instantiation of default argument for '__libcpp_abstract' required here template struct _LIBCPP_TEMPLATE_VIS is_abstract : public __libcpp_abstract<_Tp> {}; ^~~~~~~~~~~~~~~~~~~~~~ /opt/compiler-explorer/clang-4.0.0/bin/../include/c++/v1/type_traits:1384:39: note: in instantiation of template class 'std::__1::is_abstract' requested here !is_abstract<_T2>::value> {}; ^ /opt/compiler-explorer/clang-4.0.0/bin/../include/c++/v1/memory:3918:39: note: in instantiation of template class 'std::__1::is_convertible' requested here typename enable_if::value, __nat>::type = __nat()) ^ /opt/compiler-explorer/clang-4.0.0/bin/../include/c++/v1/memory:3883:28: note: while substituting deduced template arguments into function template 'shared_ptr' [with _Yp = int] class _LIBCPP_TEMPLATE_VIS shared_ptr ^ :7:26: note: default member initializer declared here std::shared_ptr _a {};

FYI, this looks like an issue in libc++. If I compile your sample with the latest and greatest clang, but point it to the g++ 7.1.1 libstdc++ headers, it works just fine.

-Dimitry

It is, but I’m not sure that libc++ is the cause or just points out the bug. If you look at the stack overflow link, you’ll see an example of different code that triggers a similar error without the use of any library stuff.

I went ahead and submitted a bug report. https://bugs.llvm.org/show_bug.cgi?id=33736

The shortest reduction I could come up with is this:

template <bool> struct a;
template <class> struct B {};
template <class b, bool = B<b>::f> struct g;
template <class c, class, int = g<c>::f> struct i;
template <class> class j {
public:
  j();
  template <class d> j(j<d>, typename a<i<d *, int *>::f>::e = int());
};
struct k {
  k() noexcept = default;
  k(k &) = default;
  j<int> h{};
};

All versions of g++ that I tried compile this without error, while clang says:

testcase.cpp:11:3: error: default member initializer for 'h' needed within definition of enclosing class 'k' outside of member functions
  k() noexcept = default;
  ^
testcase.cpp:3:27: note: in instantiation of template class 'B<int *>' requested here
template <class b, bool = B<b>::f> struct g;
                          ^
testcase.cpp:4:33: note: in instantiation of default argument for 'g<int *>' required here
template <class c, class, int = g<c>::f> struct i;
                                ^~~~
testcase.cpp:8:41: note: in instantiation of default argument for 'i<int *, int *>' required here
  template <class d> j(j<d>, typename a<i<d *, int *>::f>::e = int());
                                        ^~~~~~~~~~~~~
testcase.cpp:5:24: note: while substituting deduced template arguments into function template 'j' [with d = int]
template <class> class j {
                       ^
testcase.cpp:13:10: note: default member initializer declared here
  j<int> h{};
         ^
1 error generated.

-Dimitry

Please note this on the bug report

Richard has posted a much nicer variant already. :slight_smile:

-Dimitry