In libstdc++-v3/include/bits/cpp_type_traits.h, `__is_pointer` is both used as a unary type trait and the name of a template struct. After it is a struct template's name, Clang no longer parses it as a builtin and `inline constexpr bool is_pointer_v = __is_pointer(_Tp);` in libstdc++-v3/include/std/type_traits fails to compile. This only happens if cpp_type_traits.h is included before type_traits, which unfortunately happens with this program: https://godbolt.org/z/afbvddddK #include <vector> (Please advise if you think this is a Clang bug, how libstdc++ expects these type trait names to be parsed)
https://gcc.gnu.org/pipermail/gcc-patches/2024-June/654499.html
Ok, clang behavior is an odd one here: ``` template<typename _Tp, bool _IsPtr = __is_pointer(_Tp)> struct __is_pointer {}; template<typename _Tp> inline bool t = __is_pointer(_Tp); template<bool> struct ts{}; template<typename _Tp> struct is_pointer : ts<__is_pointer(_Tp)> {}; int tt = t<int>; ``` clang does not complain about the use of __is_pointer for variable template t but does for the base class of is_pointer.
(In reply to Andrew Pinski from comment #2) > clang does not complain about the use of __is_pointer for variable template > t but does for the base class of is_pointer. Filed that as https://github.com/llvm/llvm-project/issues/95598
It appears that Clang is parsing it as a broken function type, but it should then retry parsing as an expression. Forcing it to be an expression in the first place does let it compile: template<typename _Tp> struct is_pointer : ts<static_cast<bool>(__is_pointer(_Tp))> {};
I suppose we can just include <type_traits> at the top of <bits/cpp_type_traits.h>, we could even make that conditional on __clang__
(In reply to Mital Ashok from comment #4) > Forcing it to be an expression in the first place does let it compile: > > template<typename _Tp> > struct is_pointer : ts<static_cast<bool>(__is_pointer(_Tp))> {}; Ah nice, we can do that
Note I think we should workaround this. I only posted the clang issue because clang was acting inconsistent in its handling and should be more consistent in there; not that libstdc++ should not workaround the issue.
FWIW, I also ran into this, this morning. Reduced: https://godbolt.org/z/rxYKTqKd4 Organically in Abseil: https://godbolt.org/z/9eoqKzYjc (This happens because Abseil #includes <algorithm> before <type_traits> (alphabetically). If you switch the order of those two includes, it Just Works.) IMVHO libstdc++ should do jwakely's idea of #include <type_traits> from the offending header file; that's the most foolproof O(1) solution, rather than the O(N) solution of being really careful to always write `bool(__is_foo(T))` instead of `__is_foo(T)`. Also, there are definitely third-party libraries (like Abseil) out there who legitimately want to use `__is_pointer(T)` in their own code, and right now they have no idea that they ought to write all their uses with an extra `bool` cast just to work around a problematic interaction between Clang and libstdc++ (a mode they probably don't even build in their CI). So fixing the problem once and for all on libstdc++'s side of the fence would be really helpful.
Changing libstdc++ order of includes won't help abseil. If their use of __is_pointer still comes after any standard header has included cpp_type_traits.h, the identifier will be "poisoned" by the class template. So they need their own workaround.
The only foolproof fix would be to rename the __is_pointer class template.
Although that class template has been there for years, so if any library like abseil was using the built-in, they're already have the problem that libstdc++ now has.
(In reply to Jonathan Wakely from comment #11) > Although that class template has been there for years, so if any library > like abseil was using the built-in, they're already have the problem that > libstdc++ now has. It looks like the abseil code is not using __is_pointer directly at all, but rather the standard headers here. I suspect we should just rename the __is_pointer template to workaround this clang oddness (and add a comment on why the name is not __is_pointer).
(In reply to Jonathan Wakely from comment #10) > The only foolproof fix would be to rename the __is_pointer class template. Yes, given that Clang treats this identifier as a keyword, the best solution would be for libstdc++ to stop using it as a type name. We have an awful hack in Clang to support libstdc++ doing this, and it'd be great to remove that eventually. (I apologize, we should have made this request years ago when we added the hack.) As is evidenced in this bug, this hack was only made to be good enough to support libstdc++ as it existed at the time. I'm not really sure what behavior one would expect from `__is_pointer(_Tp)`, given that it can parse as a type (treating `__is_pointer` as a placeholder for CTAD, which is semantically invalid in this context only because we can't perform CTAD here). We could extend our hack to support this too, but doing so is really a losing proposition. In general, we seem to have organically adopted the convention that `std::blah<...>` type traits correspond to `__blah` keywords, so it'd be great if libstdc++ didn't use any of those identifiers as type names.
I assume clang doesn't have __is_arithmetic, __is_scalar and __is_void built-ins yet, because <bits/cpp_type_traits.h> also defines class templates with those names. At least __are_same, __is_integer and __is_floating don't clash.
(In reply to Jonathan Wakely from comment #14) > I assume clang doesn't have __is_arithmetic, __is_scalar and __is_void > built-ins yet, because <bits/cpp_type_traits.h> also defines class templates > with those names. Clang has all of those (https://github.com/llvm/llvm-project/blob/12cf0dc685a9c3adfefc3a58f0b8ed4360be8b14/clang/include/clang/Basic/TokenKinds.def#L552), but it looks like <type_traits> happens to not use them in a way that breaks. The specific problem with __is_pointer in <type_traits> is that it's being used in a template argument: : public __bool_constant<__is_pointer(_Tp)> ... where it would be valid to parse a type. Clang's hack to treat `__is_pointer(T)` as the builtin (after we've seen a declaration using the same name) only applies in contexts where we know we're parsing an expression. (We can fix this, but I think the healthier thing long-term is to treat these as keywords everywhere.)
Patches series to eradicate __is_pointer, __is_scalar and __is_void posted: https://gcc.gnu.org/pipermail/gcc-patches/2024-June/655268.html
And this one is needed before that patch series: https://gcc.gnu.org/pipermail/gcc-patches/2024-June/655267.html
The master branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>: https://gcc.gnu.org/g:b3743181899c5490a94c4dbde56a69ab77a40f11 commit r15-1549-gb3743181899c5490a94c4dbde56a69ab77a40f11 Author: Jonathan Wakely <jwakely@redhat.com> Date: Wed Jun 19 16:14:56 2024 +0100 libstdc++: Fix std::fill and std::fill_n optimizations [PR109150] As noted in the PR, the optimization used for scalar types in std::fill and std::fill_n is non-conforming, because it doesn't consider that assigning a scalar type might have non-trivial side effects which are affected by the optimization. By changing the condition under which the optimization is done we ensure it's only performed when safe to do so, and we also enable it for additional types, which was the original subject of the PR. Instead of two overloads using __enable_if<__is_scalar<T>::__value, R> we can combine them into one and create a local variable which is either a local copy of __value or another reference to it, depending on whether the optimization is allowed. This removes a use of std::__is_scalar, which is a step towards fixing PR 115497 by removing std::__is_pointer from <bits/cpp_type_traits.h> libstdc++-v3/ChangeLog: PR libstdc++/109150 * include/bits/stl_algobase.h (__fill_a1): Combine the !__is_scalar and __is_scalar overloads into one and rewrite the condition used to decide whether to perform the load outside the loop. * testsuite/25_algorithms/fill/109150.cc: New test. * testsuite/25_algorithms/fill_n/109150.cc: New test.
The master branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>: https://gcc.gnu.org/g:139d65d1f5a60ac90479653a4f9b63618509f3f9 commit r15-1550-g139d65d1f5a60ac90479653a4f9b63618509f3f9 Author: Jonathan Wakely <jwakely@redhat.com> Date: Wed Jun 19 11:19:58 2024 +0100 libstdc++: Don't use std::__is_scalar in std::valarray initialization [PR115497] This removes the use of the std::__is_scalar trait from <valarray>, where it can be replaced by __is_trivial. It's used to decide whether we can use memset to value-initialize valarray elements, but memset is suitable for any trivial types, because value-initializing them is equivalent to filling them with zeros. This is another step towards removing the class templates in <bits/cpp_type_traits.h> that conflict with Clang built-in names. libstdc++-v3/ChangeLog: PR libstdc++/115497 * include/bits/valarray_array.h (__valarray_default_construct): Use __is_trivial(_Tp). instead of __is_scalar<_Tp>.
The master branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>: https://gcc.gnu.org/g:5f10547e021db3a4a34382cd067668f9ef97fdeb commit r15-1551-g5f10547e021db3a4a34382cd067668f9ef97fdeb Author: Jonathan Wakely <jwakely@redhat.com> Date: Wed Jun 19 17:21:16 2024 +0100 libstdc++: Stop using std::__is_pointer in <deque> and <algorithm> [PR115497] This replaces all uses of the std::__is_pointer type trait with uses of the new __is_pointer built-in. Since the class template was only used to enable some performance optimizations for algorithms, we can use the built-in when __has_builtin(__is_pointer) is true (which is the case for GCC trunk and for current versions of Clang) and just forego the optimization otherwise. Removing the uses of std::__is_pointer means it can be removed from <bits/cpp_type_traits.h>, which is another step towards fixing PR 115497. libstdc++-v3/ChangeLog: PR libstdc++/115497 * include/bits/deque.tcc (__lex_cmp_dit): Replace __is_pointer class template with __is_pointer(T) built-in. (__lexicographical_compare_aux1): Likewise. * include/bits/stl_algobase.h (__equal_aux1): Likewise. (__lexicographical_compare_aux1): Likewise.
The master branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>: https://gcc.gnu.org/g:51cc77672add517123ef9ea45335b08442e8d57c commit r15-1552-g51cc77672add517123ef9ea45335b08442e8d57c Author: Jonathan Wakely <jwakely@redhat.com> Date: Wed Jun 19 11:19:58 2024 +0100 libstdc++: Remove std::__is_void class template [PR115497] This removes the std::__is_void trait, as it conflicts with a Clang built-in. There is only one use of the trait, which can easily be replaced by simpler code. Although Clang has a hack to make the class template work despite using a reserved name, removing std::__is_void will allow that hack to be dropped at some future date. libstdc++-v3/ChangeLog: PR libstdc++/115497 * include/bits/cpp_type_traits.h (__is_void): Remove. * include/debug/helper_functions.h (_Distance_traits): Adjust partial specialization to match void directly, instead of using __is_void<T>::__type and matching __true_type.
The master branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>: https://gcc.gnu.org/g:52a82359073653e312aaa5703f7e0ce339588961 commit r15-1553-g52a82359073653e312aaa5703f7e0ce339588961 Author: Jonathan Wakely <jwakely@redhat.com> Date: Wed Jun 19 17:26:37 2024 +0100 libstdc++: Remove std::__is_pointer and std::__is_scalar [PR115497] This removes the std::__is_pointer and std::__is_scalar traits, as they conflicts with a Clang built-in. Although Clang has a hack to make the class templates work despite using reserved names, removing these class templates will allow that hack to be dropped at some future date. libstdc++-v3/ChangeLog: PR libstdc++/115497 * include/bits/cpp_type_traits.h (__is_pointer, __is_scalar): Remove. (__is_arithmetic): Do not use __is_pointer in the primary template. Add partial specialization for pointers.
(In reply to Jonathan Wakely from comment #16) > Patches series to eradicate __is_pointer, __is_scalar and __is_void posted: > https://gcc.gnu.org/pipermail/gcc-patches/2024-June/655268.html And pushed. That should fix the immediate problem, please reopen if you still see problems with clang (I don't have a clang trunk build handy to check). I'll kill __is_arithmetic soonish.