Skip to content

Conversation

@RobertLeahy
Copy link
Contributor

@RobertLeahy RobertLeahy commented Dec 29, 2025

Asio operations frequently declare completion signatures which are correct only if you ignore cv- and ref-qualification. That is to say an operation might declare void(int) as its completion signature but in actual fact complete with int& or const int& (rather than the expected int&&).

asioexec::completion_token has tried to deal with the above since it was initially added (35a3e31), however this has not been without issue (8bb5b46).

The correct way to deal with the above issue (as reified by 8bb5b46) is to use a combination of:

  • std::is_convertible_v, and
  • std::reference_converts_from_temporary_v

To determine whether values should be forwarded through to the receiver or first converted. Unfortunately compilers/standard libraries that don't feature std::reference_converts_from_temporary_v are supported hence this fallback from 8bb5b46:

  (
    //  Just using is_base_of_v is insufficient because it always reports false for built-in types
    (std::is_base_of_v<std::remove_cvref_t<T>, std::remove_cvref_t<U>>
     || std::is_same_v<std::remove_cvref_t<T>, std::remove_cvref_t<U>>)
    &&
    //  The returned type must be at least as cv-qualified as the input type (it can be more cv-qualified)
    at_least_as_qualified_v<std::remove_reference_t<T>, std::remove_reference_t<U>>
    && (
      //  Reference type must agree except...
      (std::is_lvalue_reference_v<T> == std::is_lvalue_reference_v<T>) ||
      //  ...special rules for const& which allows rvalues to bind thereto
      (std::is_lvalue_reference_v<T> && std::is_const_v<std::remove_reference_t<T>>) ))

Unfortunately there's a typo under the comment which reads "[r]eference type must agree except:" Both sides of the equality comparison are std:: is_lvalue_reference_v thereby rendering it tautological. This had the effect of activating the overload constrained thereby in the case where:

  • The destination type (T) is an rvalue reference, and
  • The source type (U) is a mutable lvalue reference

Leading to a compiler error of the following form:

  error: rvalue reference to type 'boost::system::error_code' cannot bind to lvalue of type 'boost::system::error_code'
  100 |       return static_cast<U&&>(u);
      |              ^~~~~~~~~~~~~~~~~~~

Which is #1724 (which this commit addresses).

Added a reproducing test and fixed.

Asio operations frequently declare completion signatures which are
correct only if you ignore cv- and ref-qualification. That is to say an
operation might declare void(int) as its completion signature but in
actual fact complete with int& or const int& (rather than the expected
int&&).

asioexec::completion_token has tried to deal with the above since it was
initially added (35a3e31), however this
has not been without issue (8bb5b46).

The correct way to deal with the above issue (as reified by
8bb5b46) is to use a combination of:

- std::is_convertible_v, and
- std::reference_converts_from_temporary_v

To determine whether values should be forwarded through to the receiver
or first converted. Unfortunately compilers/standard libraries that
don't feature std::reference_converts_from_temporary_v are supported
hence this fallback from 8bb5b46:

  (
    //  Just using is_base_of_v is insufficient because it always reports false for built-in types
    (std::is_base_of_v<std::remove_cvref_t<T>, std::remove_cvref_t<U>>
     || std::is_same_v<std::remove_cvref_t<T>, std::remove_cvref_t<U>>)
    &&
    //  The returned type must be at least as cv-qualified as the input type (it can be more cv-qualified)
    at_least_as_qualified_v<std::remove_reference_t<T>, std::remove_reference_t<U>>
    && (
      //  Reference type must agree except...
      (std::is_lvalue_reference_v<T> == std::is_lvalue_reference_v<T>) ||
      //  ...special rules for const& which allows rvalues to bind thereto
      (std::is_lvalue_reference_v<T> && std::is_const_v<std::remove_reference_t<T>>) ))

Unfortunately there's a typo under the comment which reads "[r]eference
type must agree except:" Both sides of the equality comparison are std::
is_lvalue_reference_v<T> thereby rendering it tautological. This had the
effect of activating the overload constrained thereby in the case where:

- The destination type (T) is an rvalue reference, and
- The source type (U) is a mutable lvalue reference

Leading to a compiler error of the following form:

  error: rvalue reference to type 'boost::system::error_code' cannot
  bind to lvalue of type 'boost::system::error_code'
  100 |       return static_cast<U&&>(u);
      |              ^~~~~~~~~~~~~~~~~~~

Which is NVIDIA#1724 (which this commit addresses).

Added a reproducing test and fixed.
@copy-pr-bot
Copy link

copy-pr-bot bot commented Dec 29, 2025

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@ericniebler
Copy link
Collaborator

/ok to test b8a2589

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants