NVIDIA/stdexec

__decay built-in rejected by gcc head

Opened this issue · 3 comments

My guess is that in

commit 9d0dba02c5452d5906f87e59455a4c38944eb217
Author: Ken Matsui <kmatsui@gcc.gnu.org>
Date:   Thu Feb 15 04:44:54 2024 -0800

    libstdc++: Optimize std::decay compilation performance
    
    This patch optimizes the compilation performance of std::decay
    by dispatching to the new __decay built-in trait.

gcc caught up with include/stdexec/__detail/__type_traits.hpp

  //////////////////////////////////////////////////////////////////////////////////////////////////
  // __decay_t: An efficient implementation for std::decay
#if STDEXEC_HAS_BUILTIN(__decay)

  template <class _Ty>
  using __decay_t = __decay(_Ty);

End result is my old code fails with

In file included from bounce.cc:32:
/usr/src/local/stdexec/include/exec/async_scope.hpp: In instantiation of 'exec::__scope::__when_empty_sender_t<_Constrained> exec::__scope::async_scope::when_empty(_Constrained&&) const [with _Constrained = stdexec::__sexpr<<lambda closure object>stdexec::{anonymous}::<lambda()>(), stdexec::{anonymous}::__anon>]':
bounce.cc:473:1:   required from here
  473 | }
      | ^
/usr/src/local/stdexec/include/exec/async_scope.hpp:758:12: error: use of built-in trait '__decay(_Ty)' in function signature; use library traits instead
  758 |       auto when_empty(_Constrained&& __c) const -> __when_empty_sender_t<_Constrained> {
      |            ^~~~~~~~~~
/usr/src/local/stdexec/include/exec/async_scope.hpp: In instantiation of 'exec::__scope::__when_empty_sender_t<_Constrained> exec::__scope::async_scope::when_empty(_Constrained&&) const [with _Constrained = stdexec::__sexpr<<lambda closure object>stdexec::{anonymous}::<lambda()>(), stdexec::{anonymous}::__anon>]':
bounce.cc:473:1:   required from here
  473 | }
      | ^
/usr/src/local/stdexec/include/exec/async_scope.hpp:758:12: error: use of built-in trait '__decay(_Ty)' in function signature; use library traits instead
  758 |       auto when_empty(_Constrained&& __c) const -> __when_empty_sender_t<_Constrained> {
      |            ^~~~~~~~~~

Egregious hack

diff --git a/include/stdexec/__detail/__type_traits.hpp b/include/stdexec/__detail/__type_traits.hpp
index 01b96467..cd78cf1e 100644
--- a/include/stdexec/__detail/__type_traits.hpp
+++ b/include/stdexec/__detail/__type_traits.hpp
@@ -31,7 +31,7 @@ namespace stdexec {
 #if STDEXEC_HAS_BUILTIN(__decay)
 
   template <class _Ty>
-  using __decay_t = __decay(_Ty);
+  using __decay_t = std::decay_t<_Ty>;
 
 #elif STDEXEC_NVHPC()
 

allows me to compile once again.

Presumably ignore until 15 is released, then test on version?

FWIW, there's a GCC bug report related to it (the bug here fixed was an ICE in the compiler), apparently using __decay is not the way to go.
Cf. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116052

apparently using __decay is not the way to go.

What is the issue with using __decay builtin?
It seems like the stdlib is fine using it in the definition of the std::decay struct definition.

template<typename T>
struct decay {
  using type = __decay(T);
};

Is there a restriction on the places that such a built-in can be used?
i.e. it's ok to use in member-alias-templates of a class definition, but not at namespace-scope-alias-templates.

Having said that, if the compilers/stdlib are now optimizing std::decay_t then we may as well just use that directly rather than trying to optimize in stdexec code.

Is there a restriction on the places that such a built-in can be used?

Yes, the restriction is that built-ins are not allowed to appear in function signatures. That's what the compilation error is all about. Using the trait that resolves to the built-in in function signatures is fine. Use the trait, don't use the built-in.