This is an archive of the discontinued LLVM Phabricator instance.

[libc++] [P0849R8] Introduce _LIBCPP_AUTO_CAST(x) for auto(x)
ClosedPublic

Authored by Quuxplusone on Dec 13 2021, 4:59 PM.

Details

Summary

Clang is gaining auto(x) support in D113393, but sadly there seems to be no feature-test macro for it.

Use this where C++20 specifies we should use auto(x); stop using __decay_copy(x), which calls more move-constructors than it should.
Add regression tests.

Drive-by fix some places in std::ranges::size that were perfect-forwarding when they shouldn't; this affects one test case. Did this only because I was touching those lines already: __decay_copy(forward(x)) becomes just _LIBCPP_AUTO_CAST(x).

Diff Detail

Event Timeline

Quuxplusone requested review of this revision.Dec 13 2021, 4:59 PM
Herald added 1 blocking reviewer(s): Restricted Project. · View Herald TranscriptDec 13 2021, 4:59 PM
jloser added a subscriber: jloser.Dec 13 2021, 6:44 PM

That's a bit surprising there's no feature test macro for it - but I agree after reading the paper. :(

Fix generated files.

We should have an entry for P0849R8 in our status pages. It's a CWG paper but it does have some effects on the library -- can you add it and mark it as complete?

libcxx/include/__ranges/access.h
111

__t is "an lvalue that denotes the reified object for E", and that's why we don't want to use std::forward -- right?

Quuxplusone marked an inline comment as done.
Quuxplusone retitled this revision from [libc++] [ranges] Introduce _LIBCPP_AUTO_CAST(x) for auto(x) to [libc++] [P0849R8] Introduce _LIBCPP_AUTO_CAST(x) for auto(x).

Mark P0849 as "Complete," which means replacing the remaining __decay_copys e.g. in <thread> with _LIBCPP_AUTO_CAST. I believe these diffs end up being no-ops. Then, there are no __decay_copys left anywhere in the codebase, so just remove the helper entirely.

Now, P0849 goes out of its way to not remove the uses of decay-copy in http://eel.is/c++draft/range.all.general#2.1 and http://eel.is/c++draft/range.take#overview-2.1 , but that's just a specification hack. decay-copy(E) is the same thing as auto(forward<T>(t)) whenever E is of reference type T&&, and this hack is basically just saying "yes, LWG understands that for this particular usage there's going to be a perfect-forwarding."

libcxx/include/__ranges/access.h
111

Correct.

Re adding a status-page entry for P0849: Done! Of course, to mark it "complete," I had to expand the scope of this patch a tiny bit... :)

Now that C++11 future uses _LIBCPP_AUTO_CAST, that macro needs to stop using decay_t and use decay<T>::type instead.

ldionne accepted this revision.Dec 21 2021, 2:13 PM

Is there really no other place that uses decay-copy in the standard? If so, they forgot to remove it from http://eel.is/c++draft/expos.only.func#2.

This revision is now accepted and ready to land.Dec 21 2021, 2:13 PM

Is there really no other place that uses decay-copy in the standard? If so, they forgot to remove it from http://eel.is/c++draft/expos.only.func#2.

It's still used as a specification tool in a few places — notably even within Ranges, e.g. http://eel.is/c++draft/range.take#overview-2.1 "If T is a specialization of ranges​::​empty_view, then views​::​take(E, F) is expression-equivalent to ((void) F, decay-copy(E)), except that the evaluations of E and F are indeterminately sequenced." The Standard can't literally say it's expression-equivalent to ((void) F, (E)), because then if E were a prvalue then the return object of views::take(E, F) would have to work out to the exact same prvalue object as the function argument E... and that's physically impossible. So they specify it in terms of decay-copy. Also, they have to say "indeterminately sequenced" because E and F are really function arguments, and function arguments are indeterminately sequenced.

Basically, decay-copy(X) is now purely a specification tool. When LWG means return func(X), LWG can say "expression-equivalent to func(X)"; but when LWG means literally return X, then LWG must say "expression-equivalent to decay-copy(X)." However, as shown in D115686, my interpretation is that the library implementor never wants to use __decay_copy(X); when the standard says "expression-equivalent to decay-copy(X)", the library implementor should generally reverse-translate that into simply return X.

Quuxplusone added a subscriber: mstorsjo.

Change D112214's XFAIL to UNSUPPORTED, since it passes now (for some reason).

@mstorsjo writes:

I think it was technically undefined whether it fails or succeeds, so yeah it’s plausible that a random change could make it work again (it depended on which order the linker included some section pieces).