noexcept specifier mysteriously breaks compilation (clang, gcc disagree)

  • A+
Category:Languages

The code in question is

#include <functional> #include <utility>  template <typename F> void for_each(F&&) noexcept {}  template <typename F, typename T, typename... Us> void for_each(F&& f, T&& v, Us&&... us) {   std::invoke(std::forward<F>(f), std::forward<T>(v));   for_each(std::forward<F>(f), std::forward<Us>(us)...); }  void func(void*) noexcept {}  int main() {   for_each(func, nullptr); } 

It compiles on gcc 8, but fails on clang 6 with the following error:

/opt/wandbox/clang-6.0.0/include/c++/v1/type_traits:4198:19: error: invalid application of 'sizeof' to a function type     static_assert(sizeof(_Tp) > 0, "Type must be complete.");                   ^~~~~~~~~~~ /opt/wandbox/clang-6.0.0/include/c++/v1/type_traits:4203:15: note: in instantiation of template class 'std::__1::__check_complete<void (void *) noexcept>' requested here     : private __check_complete<_Tp>               ^ /opt/wandbox/clang-6.0.0/include/c++/v1/type_traits:4496:15: note: in instantiation of template class 'std::__1::__check_complete<void (&)(void *) noexcept>' requested here     : private __check_complete<_Fp>               ^ /opt/wandbox/clang-6.0.0/include/c++/v1/type_traits:4559:9: note: in instantiation of template class 'std::__1::__invokable_r<void, void (&)(void *) noexcept, nullptr_t &&>' requested here         __invokable<_Fp, _Args...>::value,         ^ /opt/wandbox/clang-6.0.0/include/c++/v1/type_traits:4568:14: note: in instantiation of template class 'std::__1::__invoke_of<void (&)(void *) noexcept, nullptr_t &&>' requested here     : public __invoke_of<_Fp, _Args...>              ^ /opt/wandbox/clang-6.0.0/include/c++/v1/type_traits:4573:22: note: in instantiation of template class 'std::__1::result_of<void (&(nullptr_t &&))(void *) noexcept>' requested here template <class _Tp> using result_of_t = typename result_of<_Tp>::type;                      ^ /opt/wandbox/clang-6.0.0/include/c++/v1/functional:2349:1: note: in instantiation of template type alias 'result_of_t' requested here result_of_t<_Fn&&(_Args&&...)> ^ prog.cc:9:3: note: while substituting deduced template arguments into function template 'invoke' [with _Fn = void (&)(void *) noexcept, _Args = <nullptr_t>]   std::invoke(std::forward<F>(f), std::forward<T>(v));   ^ prog.cc:16:3: note: in instantiation of function template specialization 'for_each<void (&)(void *) noexcept, nullptr_t>' requested here   for_each(func, nullptr);   ^ 1 error generated. 

Remove the noexcept specifier on func()

void func(void*) /* noexcept */ {} 

It then compiles. I don't get this. Is this a compiler bug?


Well no. libc++ fails to handle noexcept marked functions. It looks like its machinery fails for some reason when the function is noexcept and it takes the wrong partial specialization (the one for objects not for functions).

As you cannot take the sizeof of a function, clang rightly complains (and gcc would too).

As a workaround, pass in a function pointer:

for_each(&func, nullptr); 

I filled a bug report.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: