#include
struct foo
{
int x{0};
foo() noexcept = default;
void f() noexcept(noexcept(std::declval())) {}
};
int main()
Your code is fine from what I can tell. Clang seems to struggle with the = default
constructor rather than just defining a default constructor manually. It has the following spiel in its source code about it:
DR1351: If the brace-or-equal-initializer of a non-static data member invokes a defaulted default constructor of its class or of an enclosing class in a potentially evaluated subexpression, the program is ill-formed.
This resolution is unworkable: the exception specification of the default constructor can be needed in an unevaluated context, in particular, in the operand of a noexcept-expression, and we can be unable to compute an exception specification for an enclosed class.
Any attempt to resolve the exception specification of a defaulted default constructor before the initializer is lexically complete will ultimately come here at which point we can diagnose it.
I think it may be incorrectly picking up the error, personally. But it specifially mentions "defaulted default constructor".
The following seems to work:
#include <utility>
struct foo
{
int x{0};
foo() noexcept {} // = default;
void f() noexcept(noexcept(std::declval<foo&>())) {}
};
int main()
{
}
Your usage is fine.
int x{0}
clearly falls under the category non-static data member with initializer (C++11). declval
does not require a complete type--that's kind of the point of it, as explained in this nice exposition. What's left? Compiler bug, I guess. How about this for evidence? Use a complete type z
instead of foo
in your declval
.
#include <utility>
struct z{};
struct foo
{
int x{0};
foo() noexcept = default;
void f() noexcept( noexcept( std::declval<z>() ) ) {}
};
int main()
{
}
Clang 4.0.0 on godbolt still errors the same way. Unfortunately I do not have clang 4.0.0 available on a machine to test, so I cannot not say whether it is Clang or godbolt for certain.
This is correct syntactical way is I can say.
#include <utility>
struct foo
{
int x{0};
foo() noexcept {} // = default;
void f() noexcept(noexcept(std::declval<foo&>())) {}
};
int main()
{
}
As C++ 11 standard states
§ 5.3.7
The
noexcept
operator determines whether the evaluation of its operand, which is an unevaluated operand (Clause 5), can throw an exception (15.1).noexcept-expression: noexcept ( expression )
The result of the noexcept operator is a constant of type bool and is an rvalue. The result of the noexcept operator is false if in a potentially-evaluated context the expression would contain
— a potentially evaluated call to a function, member function, function pointer, or member function pointer that does not have a non-throwing exception-specification (15.4), unless the call is a constant expression (5.19),
— a potentially evaluated throw-expression (15.1),
— a potentially evaluated dynamic_cast expression dynamic_cast(v), where T is a reference type, that requires a run-time check (5.2.7), or
— a potentially evaluated typeid expression (5.2.8) applied to a glvalue expression whose type is a polymorphic class type (10.3).
Otherwise, the result is true.
and
template <class T> typename add_rvalue_reference<T>::type declval() noexcept; // as unevaluated operand
The add_rvalue_reference
is of type Transformation Trait and, not explicitly said, but does not require object/function definition to be instantiated.
From here it is clear that struct foo; ... noexcept(std::declval<foo>())
is a legal code. Where noexcept
part, by the way, is equivalent to noexcept(true)
that is equivalent to just noexcept
, and noexcept(noexcept
does not make sense, to get a constructor noexcept specifier you have to do this noexcept(foo())
. The latter is valid as well, but, unfortunately, compilers are not able to deal with it, probably because of the order how they build the unit for non C++11 code, and they have not transformed this model yet. This reflects the nature of the bug that you encounter in the particular libc++ implementation. For some reasons add_rvalue_reference
due to the presence of noexcept
specifier tries to use declaration of the constructor and since that happens outside of the member function, as mentioned before, it fails. So yes, this is a bug of the library.
This seems like it might be related to this commit in November. https://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20161121/177858.html
It must be a compiler bug. Has it been reported?