facebook / folly

An open-source C++ library developed and used at Facebook.
https://groups.google.com/forum/?fromgroups#!forum/facebook-folly
Apache License 2.0
28.34k stars 5.56k forks source link

Folly doesn't compile with Clang 8 and libc++ #1081

Closed JoeLoser closed 5 years ago

JoeLoser commented 5 years ago

With Clang 8 and libc++, so far, I have seen at least a few tests (ForeachTest.cpp line 277 and SynchronizedTest.cpp).

Stack trace for ForeachTest.cpp:

../folly/container/Foreach-inl.h:274:15: note: in instantiation of template type alias 'ForEachImplTag' requested here
  using tag = ForEachImplTag<Func, type, void>;

../folly/container/Foreach-inl.h:319:8: note: in instantiation of function template specialization 'folly::for_each_detail::for_each_impl<std::__1::tuple<folly::test::TestRValueConstruct, folly::test::TestRValueConstruct>, (lambda at ../folly/container/test/ForeachTest.cpp:277:7)>' requested here
  fed::for_each_impl(tag{}, std::forward<Sequence>(sequence), func);
       ^
/usr/local/Cellar/llvm/8.0.0/bin/../include/c++/v1/type_traits:4254:6: note: candidate template ignored: substitution failure [with _Args = <folly::test::TestRValueConstruct, std::__1::integral_constant<unsigned long, 0>, void>]: cannot form a reference to 'void'
auto __invoke(__any, _Args&& ...__args) -> __nat;
     ^                    ~~
/usr/local/Cellar/llvm/8.0.0/bin/../include/c++/v1/type_traits:4265:1: note: candidate template ignored: substitution failure [with _Fp = (lambda at ../folly/container/test/ForeachTest.cpp:277:7), _A0 = folly::test::TestRValueConstruct, _Args = <std::__1::integral_constant<unsigned long, 0>, void>]: no type named 'type' in 'std::__1::__member_pointer_class_type<(lambda at ../folly/container/test/ForeachTest.cpp:277:7)>'
__invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
^
/usr/local/Cellar/llvm/8.0.0/bin/../include/c++/v1/type_traits:4279:1: note: candidate template ignored: requirement 'is_member_function_pointer<(lambda at ../folly/container/test/ForeachTest.cpp:277:7)>::value' was not satisfied [with
_Fp = (lambda at ../folly/container/test/ForeachTest.cpp:277:7), _A0 = folly::test::TestRValueConstruct, _Args = <std::__1::integral_constant<unsigned long, 0>, void>]
__invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
^
/usr/local/Cellar/llvm/8.0.0/bin/../include/c++/v1/type_traits:4293:1: note: candidate template ignored: substitution failure [with _Fp = (lambda at ../folly/container/test/ForeachTest.cpp:277:7), _A0 = folly::test::TestRValueConstruct, _Args = <std::__1::integral_constant<unsigned long, 0>, void>]: no type named 'type' in 'std::__1::__member_pointer_class_type<(lambda at ../folly/container/test/ForeachTest.cpp:277:7)>'
__invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
^
/usr/local/Cellar/llvm/8.0.0/bin/../include/c++/v1/type_traits:4352:1: note: candidate template ignored: substitution failure [with _Fp = (lambda at ../folly/container/test/ForeachTest.cpp:277:7), _Args = <folly::test::TestRValueConstruct, std::__1::integral_constant<unsigned long, 0>, void>]: cannot form a reference to 'void'
__invoke(_Fp&& __f, _Args&& ...__args)
^                        ~~
/usr/local/Cellar/llvm/8.0.0/bin/../include/c++/v1/type_traits:4309:1: note: candidate function template not viable: requires 2 arguments, but 4 were provided
__invoke(_Fp&& __f, _A0&& __a0)
^
/usr/local/Cellar/llvm/8.0.0/bin/../include/c++/v1/type_traits:4323:1: note: candidate function template not viable: requires 2 arguments, but 4 were provided
__invoke(_Fp&& __f, _A0&& __a0)
^
/usr/local/Cellar/llvm/8.0.0/bin/../include/c++/v1/type_traits:4337:1: note: candidate function template not viable: requires 2 arguments, but 4 were provided
__invoke(_Fp&& __f, _A0&& __a0)
^
In file included from ../folly/container/test/ForeachTest.cpp:17:
In file included from ../folly/container/Foreach.h:255:
../folly/container/Foreach-inl.h:276:3: error: no matching function for call to 'for_each_tuple_impl'
  for_each_tuple_impl(tag{}, std::forward<Sequence>(range), func);
  ^~~~~~~~~~~~~~~~~~~
../folly/container/Foreach-inl.h:319:8: note: in instantiation of function template specialization 'folly::for_each_detail::for_each_impl<std::__1::tuple<folly::test::TestRValueConstruct, folly::test::TestRValueConstruct>, (lambda at ../folly/container/test/ForeachTest.cpp:277:7)>' requested here
  fed::for_each_impl(tag{}, std::forward<Sequence>(sequence), func);
       ^
../folly/container/Foreach-inl.h:244:6: note: candidate function template not viable: no known conversion from 'tag' (aka 'int') to 'index_constant<2>' (aka 'integral_constant<unsigned long, 2UL>') for 1st argument
void for_each_tuple_impl(index_constant<2>, Sequence&& seq, Func& func) {
     ^
../folly/container/Foreach-inl.h:254:6: note: candidate function template not viable: no known conversion from 'tag' (aka 'int') to 'index_constant<1>' (aka 'integral_constant<unsigned long, 1UL>') for 1st argument
void for_each_tuple_impl(index_constant<1>, Sequence&& seq, Func& func) {
     ^
../folly/container/Foreach-inl.h:209:6: note: candidate template ignored: could not match 'integer_sequence<unsigned long, Indices...>' against 'int'
void for_each_tuple_impl(
     ^

SynchronizedTest.cpp stack trace:

In file included from ../folly/test/SynchronizedTest.cpp:20:
In file included from ../folly/Synchronized.h:27:
In file included from ../folly/Function.h:220:
In file included from /usr/local/Cellar/llvm/8.0.0/bin/../include/c++/v1/functional:491:
/usr/local/Cellar/llvm/8.0.0/bin/../include/c++/v1/type_traits:4371:9: error: no matching function for call to '__invoke'
        _VSTD::__invoke(_VSTD::declval<_Fp>(), _VSTD::declval<_Args>()...));
        ^~~~~~~~~~~~~~~
/usr/local/Cellar/llvm/8.0.0/bin/../include/c++/v1/__config:816:15: note: expanded from macro '_VSTD'
#define _VSTD std::_LIBCPP_ABI_NAMESPACE
              ^
/usr/local/Cellar/llvm/8.0.0/bin/../include/c++/v1/type_traits:4465:31: note: in instantiation of template class 'std::__1::__invokable_r<void, (lambda at ../folly/Synchronized.h:936:23), folly::detail::SynchronizedLocker<const folly::S
ynchronized<int, folly::(anonymous namespace)::TestSharedMutex>, (lambda at ../folly/Synchronized.h:988:7), (lambda at ../folly/Synchronized.h:991:7)> &, std::__1::integral_constant<unsigned long, 0>, void>' requested here
    : integral_constant<bool, __invokable<_Fn, _Args...>::value> {};
                              ^
../folly/container/Foreach-inl.h:136:5: note: in instantiation of template class 'std::__1::is_invocable<(lambda at ../folly/Synchronized.h:936:23), folly::detail::SynchronizedLocker<const folly::Synchronized<int, folly::(anonymous name
space)::TestSharedMutex>, (lambda at ../folly/Synchronized.h:988:7), (lambda at ../folly/Synchronized.h:991:7)> &, std::__1::integral_constant<unsigned long, 0>, void>' requested here
    is_invocable<Func, Item, index_constant<0>, Iter>::value,
    ^
../folly/container/Foreach-inl.h:274:15: note: in instantiation of template type alias 'ForEachImplTag' requested here
  using tag = ForEachImplTag<Func, type, void>;
              ^
../folly/container/Foreach-inl.h:319:8: note: in instantiation of function template specialization 'folly::for_each_detail::for_each_impl<std::__1::tuple<folly::detail::SynchronizedLocker<const folly::Synchronized<int, folly::(anonymous
 namespace)::TestSharedMutex>, (lambda at ../folly/Synchronized.h:988:7), (lambda at ../folly/Synchronized.h:991:7)> &> &, (lambda at ../folly/Synchronized.h:936:23)>' requested here
  fed::for_each_impl(tag{}, std::forward<Sequence>(sequence), func);
       ^
../folly/Synchronized.h:1643:7: note: in instantiation of function template specialization 'folly::detail::lock<folly::detail::SynchronizedLocker<const folly::Synchronized<int, folly::(anonymous namespace)::TestSharedMutex>, (lambda at
../folly/Synchronized.h:988:7), (lambda at ../folly/Synchronized.h:991:7)> >' requested here
      lock(std::forward<SynchronizedLockers>(lockers)...));
      ^
/usr/local/Cellar/llvm/8.0.0/bin/../include/c++/v1/type_traits:4254:6: note: candidate template ignored: substitution failure [with _Args = <folly::detail::SynchronizedLocker<const folly::Synchronized<int, folly::(anonymous namespace)::
TestSharedMutex>, (lambda at ../folly/Synchronized.h:988:7), (lambda at ../folly/Synchronized.h:991:7)> &, std::__1::integral_constant<unsigned long, 0>, void>]: cannot form a reference to 'void'
auto __invoke(__any, _Args&& ...__args) -> __nat;
     ^                    ~~
/usr/local/Cellar/llvm/8.0.0/bin/../include/c++/v1/type_traits:4265:1: note: candidate template ignored: substitution failure [with _Fp = (lambda at ../folly/Synchronized.h:936:23), _A0 = folly::detail::SynchronizedLocker<const folly::S
ynchronized<int, folly::(anonymous namespace)::TestSharedMutex>, (lambda at ../folly/Synchronized.h:988:7), (lambda at ../folly/Synchronized.h:991:7)> &, _Args = <std::__1::integral_constant<unsigned long, 0>, void>]: no type named 'typ
e' in 'std::__1::__member_pointer_class_type<(lambda at ../folly/Synchronized.h:936:23)>'
__invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
^
/usr/local/Cellar/llvm/8.0.0/bin/../include/c++/v1/type_traits:4279:1: note: candidate template ignored: requirement 'is_member_function_pointer<(lambda at ../folly/Synchronized.h:936:23)>::value' was not satisfied [with _Fp = (lambda a
t ../folly/Synchronized.h:936:23), _A0 = folly::detail::SynchronizedLocker<const folly::Synchronized<int, folly::(anonymous namespace)::TestSharedMutex>, (lambda at ../folly/Synchronized.h:988:7), (lambda at ../folly/Synchronized.h:991:
7)> &, _Args = <std::__1::integral_constant<unsigned long, 0>, void>]
__invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
^
/usr/local/Cellar/llvm/8.0.0/bin/../include/c++/v1/type_traits:4293:1: note: candidate template ignored: substitution failure [with _Fp = (lambda at ../folly/Synchronized.h:936:23), _A0 = folly::detail::SynchronizedLocker<const folly::S
ynchronized<int, folly::(anonymous namespace)::TestSharedMutex>, (lambda at ../folly/Synchronized.h:988:7), (lambda at ../folly/Synchronized.h:991:7)> &, _Args = <std::__1::integral_constant<unsigned long, 0>, void>]: no type named 'typ
e' in 'std::__1::__member_pointer_class_type<(lambda at ../folly/Synchronized.h:936:23)>'
__invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)

I have a small patch for folly/test/SingletonTestStructs.h which fails due to

../folly/test/SingletonTestStructs.h:46:13: error: explicitly defaulted move assignment operator is implicitly deleted [-Werror,-Wdefaulted-function-deleted]
  Watchdog& operator=(Watchdog&&) noexcept = default;
            ^
../folly/test/SingletonTestStructs.h:38:16: note: move assignment operator of 'Watchdog' is implicitly deleted because field 'serial_number' is of const-qualified type 'const size_t' (aka 'const unsigned long')
  const size_t serial_number;
               ^
1 error generated.
JoeLoser commented 5 years ago

@yfeldblum @Orvid has anyone looked at the remaining Clang 8 compilation issues? It's not obvious to me what the issue(s) are.

yfeldblum commented 5 years ago

I haven't seen these internally. Are these build failures related to using libc++ (clang's c++ std lib) instead of libstdc++ (gcc's c++ std lib)?

JoeLoser commented 5 years ago

I have only tried with clang 8 and libc++. Since internally I believe you're using clang 8 with libstdc++, it's likely a libcpp issue.

Are you able to reproduce it internally when using libc++?

yfeldblum commented 5 years ago

I haven't tried with libc++.

Betting this is related: https://godbolt.org/z/_8vhHg. Possibly libc++'s std::invoke doesn't handle void args quite like libstdc++'s in some unknown magical way. Relevant to the definition of ForEachImplTag, which is using folly::is_invocable which looks like it should be using folly::invoke, but which is using std::invoke because one of the arguments is std::integral_constant.

JoeLoser commented 5 years ago

I think you're definitely on the right track with the handling of the void arg. When we change Invoke.h to always use the backported invoke rather than std::invoke for Clang 8 with libc++, we run into SFINAE errors in invokeForward (which is SFINAEing on whether the invoke call is well-formed). This seems different than the trying to form reference to void.

[449/617] Building CXX object CMakeFiles/partial_test.dir/folly/functional/test/PartialTest.cpp.o
FAILED: CMakeFiles/partial_test.dir/folly/functional/test/PartialTest.cpp.o
/usr/local/Cellar/llvm/8.0.0/bin/clang++  -DFOLLY_XLOG_STRIP_PREFIXES=\"/Users/joe/dev/folly:/Users/joe/dev/folly/_build\" -DGFLAGS_IS_A_DLL=0 -D_GNU_SOURCE -D_REENTRANT -I../ -I. -I/usr/local/boost-1.68.0/include -I/usr/local/Cellar/openssl/1.0.2r/include -isystem /usr/local/include -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk   -g -std=gnu++1z -finput-charset=UTF-8 -fsigned-char -Wall -Wno-deprecated -Wno-deprecated-declarations -Wno-sign-compare -Wno-unused -Wunused-label -Wunused-result -Wno-noexcept-type -Wno-nullability-completeness -Wno-inconsistent-missing-override -faligned-new -fopenmp -MD -MT CMakeFiles/partial_test.dir/folly/functional/test/PartialTest.cpp.o -MF CMakeFiles/partial_test.dir/folly/functional/test/PartialTest.cpp.o.d -o CMakeFiles/partial_test.dir/folly/functional/test/PartialTest.cpp.o -c ../folly/functional/test/PartialTest.cpp
../folly/functional/test/PartialTest.cpp:129:17: error: no matching function for call to object of type 'typename remove_reference<Partial<unique_ptr<int, default_delete<int> > (*)(unique_ptr<int, default_delete<int> >, unique_ptr<int,
default_delete<int> >), tuple<unique_ptr<int, default_delete<int> > > > &>::type' (aka 'folly::detail::partial::Partial<std::__1::unique_ptr<int, std::__1::default_delete<int> > (*)(std::__1::unique_ptr<int, std::__1::default_delete<int> >, std::__1::unique_ptr<int, std::__1::default_delete<int> >), std::__1::tuple<std::__1::unique_ptr<int, std::__1::default_delete<int> > > >')
  auto result = std::move(p)(std::move(six));
                ^~~~~~~~~~~~
../folly/functional/Partial.h:58:8: note: candidate function template not viable: no known conversion from 'Partial<...>' to 'Partial<...>' for object argument
  auto operator()(CArgs&&... cargs) & -> decltype(invokeForward(
       ^
../folly/functional/Partial.h:65:8: note: candidate template ignored: substitution failure [with CArgs = <std::__1::unique_ptr<int, std::__1::default_delete<int> >>]: use of undeclared identifier 'invokeForward'
  auto operator()(CArgs&&... cargs) const& -> decltype(invokeForward(
       ^                                               ~~~~~~~~~~~~~
../folly/functional/Partial.h:72:8: note: candidate template ignored: substitution failure [with As = <std::__1::unique_ptr<int, std::__1::default_delete<int> >>]: use of undeclared identifier 'invokeForward'
  auto operator()(As&&... a) && -> decltype(invokeForward(
       ^                                    ~~~~~~~~~~~~~
../folly/functional/Partial.h:79:8: note: candidate template ignored: substitution failure [with As = <std::__1::unique_ptr<int, std::__1::default_delete<int> >>]: use of undeclared identifier 'invokeForward'
  auto operator()(As&&... as) const&& -> decltype(invokeForward(
       ^                                          ~~~~~~~~~~~~~
JoeLoser commented 5 years ago

I would expect this to be fixed with https://github.com/llvm-mirror/libcxx/commit/a32a775e66e7141185ef83ca225cbc4799cb70bf#diff-48f5ee43879b5ad38888f0a6ead10113

Your example doesn't quite work, but the ones below should: https://wandbox.org/permlink/p0nTOwhj13P6gqyL -> shows failure with Clang 8 and -stdlib=libc++ https://wandbox.org/permlink/8gOgOAF6jqDEuR1V -> shows success with Clang trunk and -stdlib=libc++

I'll check if the Folly code builds fine tomorrow with Clang trunk and libc++ and circle back.

JoeLoser commented 5 years ago

Folly builds fine when I use libc++ trunk, proving this was a libc++ quirk compared to libstdc++.

In my opinion, it is probably not worth designing a workaround which would only be for Clang 8 and libc++ considering Clang 8.0.1 will come out not too far from now. This issue does not arise when using Clang 7 and libc++.

In any regard, closing this issue.