This is an archive of the discontinued LLVM Phabricator instance.

[libcxx] Rewrite C++03 __invoke.
ClosedPublic

Authored by EricWF on Jul 27 2015, 9:58 PM.

Details

Summary

This patch rewrites the C++03 __invoke and related meta-programming. There are a number of major changes.

__invoke in C++03 now has a fallback overload for when the invoke expression is ill-formed (similar to C++11). This means that the __invoke_return traits will return __nat when __invoke(...) is ill formed. This would previously cause a compile error.

Bullets 1-4 of __invoke have been rewritten. In the old version __invoke had 32 overloads for bullets 1 and 2,
one for each possible cv-qualified function signature with arities 0-3. 64 overloads would be needed to support member functions
with varargs. Currently these overloads were fundamentally broken. An example overload looked like:

template <class Rp, class Tp, class T1, class A0>
Rp __invoke(Rp (Tp::*pm)(A0) const, T1&, A0&)

Because A0 appeared in two different deducible contexts it would have to deduce to be an exact match or the overload
would be rejected. This is made even worse because A0 appears without a reference qualifier in the member function signature
and with a reference qualifier as an __invoke parameter. This means that only member functions that took all
of their arguments by value could be matched.

One possible fix would be to make the second occurrence of A0 appear in a non-deducible context. This way
any type convertible to A0 could be passed as the first parameter. The benefit of this approach is that the
signature of the member function enforces the arity and types taken by the __invoke signature it generates. However
nothing in the INVOKE specification requires this behavior.

My solution is to use a __invoke_enable_if<PM_Type, Tp> metafunction to selectively enable the __invoke overloads for bullets 1, 2, 3 and 4. It uses __member_function_traits to inspect and extract the return type and class type of the pointer to member. Using __member_function_traits to inspect PM_Type also allows us to reduce the number of __invoke overloads from 32 to 8 and add
varargs support at the same time.

Because __invoke_enable_if knows the exact return type of __invoke for bullets 1-4 we no longer need to use decltype(__invoke(...)) to
compute the return type in the __invoke_return* traits. This will reduce the problems caused by #define decltype(X) __typeof__(X) in C++03.

Tests for this change have already been committed. All tests in test/std/utilities/function.objects now pass in C++03, previously there were 20 failures.

Diff Detail

Event Timeline

EricWF updated this revision to Diff 30774.Jul 27 2015, 9:58 PM
EricWF retitled this revision from to [libcxx] Rewrite C++03 __invoke..
EricWF updated this object.
EricWF updated this object.
EricWF updated this object.
EricWF updated this object.
EricWF added a subscriber: cfe-commits.
EricWF updated this object.Jul 27 2015, 10:12 PM
EricWF updated this object.

Add inline comment describing part of the change. Sorry about all the spam :S

include/functional
1266

This part of the change adds extra overloads in mem_fn so that the call operator can accept rvalues and temporaries as input.

A template argument Ax& will bind to any cv-qualified lvalue. However it will not bind to an rvalue. In order to accept an rvalue in C++03 we need to accept it as Ax const&. Therefore we need to enumerate every possible combination of const and non-const arguments for each operator()(...) function.

Unfortunately this solution isn't perfect. Non-const rvalues will be forwarded as const by __invoke(...) and anything that required the values to be non-const will not compile. However I think this is the best we can do.

This same change is made to reference_wrapper.

mclow.lists edited edge metadata.Aug 26 2015, 12:45 PM

So far, this looks good. I'm going to apply it locally and futz with it.

include/__functional_base_03
30

Let's be consistent. :-)

typedef _Bullet2 type;
EricWF updated this revision to Diff 33235.Aug 26 2015, 12:54 PM
EricWF edited edge metadata.

Address @mclow.lists note about consistency.

mclow.lists added inline comments.Aug 26 2015, 12:55 PM
include/__functional_base
521

I know you didn't change this, but how did we get away with an && w/o a #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES ?

Everything except __functional_03 LGTM. That's not to say that that file has problems, it's just that the diff display is not really helping :-)

mclow.lists accepted this revision.Aug 26 2015, 1:06 PM
mclow.lists edited edge metadata.

Ok, I think this is good to go. Thanks, Eric.

This revision is now accepted and ready to land.Aug 26 2015, 1:06 PM
EricWF closed this revision.Aug 26 2015, 1:16 PM