3

I'm currently reimplementing std::invoke in C++11 (i.e. understanding and adapting libc++/libstdc++ code), and I stumbled upon an issue related to noexcept.

This can be demonstrated with the following snippet:

#include <functional>

void nothrow_method(int, int) noexcept
{
}

int main(int argc, char const *argv[])
{
  static_assert(noexcept(std::__invoke(nothrow_method, 2, 3)), "");
  static_assert(std::__is_nothrow_invocable<decltype(nothrow_method), int, int>::value, "");
}

I'm on Debian Jessie, my library is libstdc++.

Compiling with -std=c++14 fails with clang 4.0.1, both static_assert trigger. There is no problem with GCC 7.1.0 however.

I looked at how libc++ implemented std::invoke, and I copied their way of detecting noexcept in my own implementation, but it still failed to compile.

Since there is only one error line because of the static_assert, I really have no idea what is going on, could it be related to what's explained in this blog post?

I've had some issues with noexcept and template instantiation points in the past, but I'm quite sure it's not related here.

EDIT:

I've downloaded libcxx trunk, built with apple-clang 8.1.0 on macOS 10.12.6, the static_assert still trigger, despite their code having noexcept(noexcept()) on __invoke.

EDIT2:

std::__* are used for tests, I know they are private, but I didn't want to post my invoke implementation.

Dante
  • 404
  • 2
  • 10
  • 2
    From the article you linked: `Note: clang currently has a bug where noexcept does not yield true even though the expression checked is a constant-expression. A workaround is available in the appendix of this post.` – tkausl Aug 24 '17 at 22:50
  • 1
    Before C++17 `noexcept` is not part of the function type, so `void nothrow_method(int, int) noexcept;` and `void throwing_method(int, int);` have the same type. – cpplearner Aug 25 '17 at 05:53
  • @tkausl I don't see how it could be linked to that issue, since I'm not dealing with constant expressions. – Dante Aug 25 '17 at 06:59
  • @cpplearner Indeed, but I've seen `__invoke` being used internally by both libc++ and libstdc++ since C++03 (for the former at least). I checked again and there is a macro `_LIBCXX_INVOKE_RETURN` that handles the `noexcept(noexcept(...))` clause, the trailing return type, and the call in itself. I've seen `noexcept` tests in the libcxx test suite with `invoke`, I'm sure their implementation is correct... I will try to compile with clang on macOS and post my results. – Dante Aug 25 '17 at 07:05
  • Aren't std::__* private to the implementation of the stl, and std::invoke() and std::is_no_throw_invokable c++17 features? Calling metafunctions outside of the standard is bordering on UB, This can not help understanding.... – Michaël Roy Aug 25 '17 at 16:00

1 Answers1

0

This seems to be a bug with the Clang standard library, probably in the definitions of std::invoke<> and std::__is_nothrow_invocable<>... GCC correctly doesn't assert on both statements, and VS2017 does exhibit the bug.

As an aside, you should avoid the std::__*<> templates — they are not part of the standard and are meant to be private to the standard library.

Here's a workaround: you can use the following syntax, which is more correct, since it tests the actual statement you will use in the app.

#include <functional>

void nothrow_method(int, int) noexcept { }

int main()
{
    static_assert(noexcept(nothrow_method(2, 3)), "");
    return 0;
}
Michaël Roy
  • 6,338
  • 1
  • 15
  • 19
  • I know one should never do that, that's just for testing purposes, since I am reimplementing `invoke` as I mentioned at the top of my post (I should have insisted on that sorry for the confusion). So the point that is of interest to me here is specifically `invoke`'s noexcept-ness. I'm currently building the latests clang/libcxx to see if it's fixed, it might be because of a compiler internal trait that this works on GCC. – Dante Aug 25 '17 at 21:05
  • I've checked vs2017's invoke, since it also fails the static_assert. It does have a noexcept clause, which is odd. Correction: `std::invoke` does _not_ have a noexcept clause. – Michaël Roy Aug 25 '17 at 22:25
  • Thanks for checking on VS! I had no success with latest libc++/clang... I'm leaning towards a compiler internal that is making GCC works. – Dante Aug 26 '17 at 00:47