However, there's a problem on both GCC and Clang: they can't mangle `__is_same(T,U)` if it appears anywhere that affects mangling. That's a hard error. And it turns out that GCC puts dependent return types into the mangling more aggressively than Clang, so for GCC's benefit we need to avoid using raw `_IsSame` in the return type of `swap(tuple&, tuple&)`. Therefore, make `__all` into a named type instead of an alias.
Details
- Reviewers
ldionne EricWF - Group Reviewers
Restricted Project - Commits
- rG5c0ea7488bc0: [libc++] Enable the optimized _IsSame on GCC as well as Clang.
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
However, there's a problem on both GCC and Clang: they can't mangle `__is_same(T,U)` if it appears anywhere that affects mangling. That's a hard error. And it turns out that GCC puts dependent return types into the mangling more aggressively than Clang, so we need to avoid using raw `_IsSame` (or type aliases such as `__all` that expand into `_IsSame`) in one return type, for GCC's benefit.
libcxx/include/tuple | ||
---|---|---|
1120 ↗ | (On Diff #391883) | Instead, I really feel like we could redefine __all to be: template <bool ..._Pred> struct __all : _IsSame<__all_dummy<_Pred...>, __all_dummy<((void)_Pred, true)...>> { }; After all, we will generally instantiate __all with several types, however we probably won't instantiate __all itself several times. What I'm trying to say is that since __all is variadic, we will probably instantiate it some factor less than the number of types that we're passing into it, so it might be reasonable to define it as a struct despite the additional costs. That would fix our mangling problem without needing a definition for __all_are_swappable, which IMO is kind of weird. |
libcxx/include/type_traits | ||
552–553 | Do we support any compilers where this is false? I don't think so -- we could probably just drop the #if altogether. |
libcxx/include/tuple | ||
---|---|---|
1120 ↗ | (On Diff #391883) | That would fix the mangling problem for __all specifically, but that's an O(n) patch for an O(n^2) problem (doesn't fix things that aren't __all), whereas what I've done here is the O(1) patch for the O(n^2) problem. |
libcxx/include/type_traits | ||
552–553 | It appeared to me that MSVC doesn't support __has_builtin at all, so it ends up nerfed to false by default. |
libcxx/include/tuple | ||
---|---|---|
1120 ↗ | (On Diff #391883) | The problem I have with fixing it locally is that we'll eventually hit the same problem if we use __all in another place. It seems cleaner to me to fix __all and add a comment explaining the GCC bug. Then, file a bug with GCC and reference it in the comment. That way, we pessimize __all but we reduce the likelihood of hitting the bug again to the maximum, and eventually we'll remove the pessimization when the GCC bug is fixed. |
libcxx/include/type_traits | ||
552–553 | AFAICT we have CI for all our supported platforms. If CI is happy without #if, I think that means we're good. If not, then let's keep the #if. |
libcxx/include/type_traits | ||
---|---|---|
571 | Any appetite for adding a libcxx test for this behavior? It is a "private" type trait, but useful property in helping compile times, so I think a simple test doesn't hurt. | |
941 | Why move this below the // is_class comment? It's a standalone helper type unrelated to is_class AFAICT, right? I recommend moving it above the // is_class comment. Maybe even add the // helper class: comment above the struct __two {char __lx[2];};. Alternatively, revert the diff entirely as it's not needed for this patch. :) |
libcxx/include/type_traits | ||
---|---|---|
941 | is_class is the first one who needs it, although yeah this was path-dependent and I should just move it below the old // helper class: comment. (Not sure how it wound up above it in the first place, and haven't looked.) |
Updated with @ldionne's suggestion. Let's see if buildkite is happy with this; if so, then I'm ready to land it and forget it. :)
LGTM with comments.
libcxx/include/type_traits | ||
---|---|---|
564–565 | I would remove that part of the comment -- I don't see what it adds. Also, I would document that this _IsSame can't be used anywhere that affects mangling in order to save some cycles if someone encounters the same issue in the future. | |
583–585 | I'm going to be really nitpicky and ask that you make this change in a separate NFC commit, no review needed. Just to keep reviews clean. |
libcxx/include/type_traits | ||
---|---|---|
564–565 | I added the latter part of the comment because it wasn't obvious to me at first glance. The alternative (and the first thing I happened to think of) is that on those platforms we define _IsSame<T,U> as an alias for is_same<T,U> and just have to beware of using _IsSame anywhere that the difference would be observable. | |
583–585 | Done! |
Do we support any compilers where this is false? I don't think so -- we could probably just drop the #if altogether.