This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.

### 3629. `make_error_code` and `make_error_condition` are customization points

Section: 19.5 [syserr] Status: WP Submitter: Jonathan Wakely Opened: 2021-10-31 Last modified: 2022-11-17

Priority: 2

View all other issues in [syserr].

View all issues with WP status.

Discussion:

The rule in 16.4.2.2 [contents] means that the calls to `make_error_code` in 19.5.4.2 [syserr.errcode.constructors] and 19.5.4.3 [syserr.errcode.modifiers] are required to call `std::make_error_code`, which means program-defined error codes do not work. The same applies to the `make_error_condition` calls in 19.5.5.2 [syserr.errcondition.constructors] and 19.5.5.3 [syserr.errcondition.modifiers].

They need to use ADL. This is what all known implementations (including Boost.System) do.

[2022-01-29; Reflector poll]

Set priority to 2 after reflector poll.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4901.

> 1. Modify 19.5.2 [system.error.syn] as indicated:

>    > -1- The value of each `enum errc` constant shall be the same as the value of the `<cerrno>` macro shown in the above synopsis. Whether or not the `<system_error>` implementation exposes the `<cerrno>` macros is unspecified.

>    > -?- Invocations of `make_error_code` and `make_error_condition` shown in subclause 19.5 [syserr] select a function to call via overload resolution (12.2 [over.match]) on a candidate set that includes the lookup set found by argument dependent lookup (6.5.4 [basic.lookup.argdep]).

>    > -2- The `is_error_code_enum` and `is_error_condition_enum` templates may be specialized for program-defined types to indicate that such types are eligible for `class error_code` and `class error_condition` implicit conversions, respectively.

>    > [Note 1: Conversions from such types are done by program-defined overloads of `make_error_code` and `make_error_condition`, found by ADL. —end note]

[2022-08-25; Jonathan Wakely provides improved wording]

Discussed in LWG telecon and decided on new direction:

- Add `make_error_code` and `make_error_condition` to 16.4.2.2 [contents] as done for `swap`. Describe form of lookup used for them.
- Respecify `error_code` and `error_condition` constructors in terms of "Effects: Equivalent to" so that the requirements on program-defined overloads found by ADL are implied by those effects.

[2022-09-07; Jonathan Wakely revises wording]

Discussed in LWG telecon. Decided to change "established as-if by performing unqualified name lookup and argument-dependent lookup" to simply "established as-if by performing argument-dependent lookup".

This resolves the question of whether `std::make_error_code(errc)`, `std::make_error_code(io_errc)`, etc. should be visible to the unqualified name lookup. This affects whether a program-defined type that specializes `is_error_code_enum` but doesn't provide an overload of `make_error_code` should find the overloads in namespace `std` and consider them for overload resolution, via implicit conversion to `std::errc`, `std::io_errc`, etc.

[2022-09-23; Reflector poll]

Set status to Tentatively Ready after seven votes in favour during reflector poll.

[2022-11-12 Approved at November 2022 meeting in Kona. Status changed: Voting → WP.]

Proposed resolution:

This wording is relative to N4910.

- Modify 16.4.2.2 [contents] as indicated:

  > -3- Whenever an unqualified name other than `swap`, `make_error_code`, or `make_error_condition` is used in the specification of a declaration `D` in 17 [support] through 33 [thread] or D [depr], its meaning is established as-if by performing unqualified name lookup (6.5.3 [basic.lookup.unqual]) in the context of `D`.

  > [Note 1: Argument-dependent lookup is not performed. — end note]

  > Similarly, the meaning of a qualified-id is established as-if by performing qualified name lookup (6.5.5 [basic.lookup.qual]) in the context of `D`.

  > [Example 1: The reference to `is_array_v` in the specification of `std::to_array` (24.3.7.6 [array.creation]) refers to `::std::is_array_v`. — end example]

  > [Note 2: Operators in expressions (12.2.2.3 [over.match.oper]) are not so constrained; see 16.4.6.4 [global.functions]. — end note]

  > The meaning of the unqualified name `swap` is established in an overload resolution context for swappable values (16.4.4.3 [swappable.requirements]). The meanings of the unqualified names `make_error_code` and `make_error_condition` are established as-if by performing argument-dependent lookup (6.5.4 [basic.lookup.argdep]).

- Modify 19.5.4.2 [syserr.errcode.constructors] as indicated:

  >     error_code() noexcept;

  > -1- Postconditions: `val_ == 0` and `cat_ == &system_category()`.
  > -1- Effects: Initializes `val_` with `0` and `cat_` with `&system_category()`.

  >     error_code(int val, const error_category& cat) noexcept;

  > -2- Postconditions: `val_ == val` and `cat_ == &cat`.
  > -2- Effects: Initializes `val_` with `val` and `cat_` with `&cat`.

  >     template<class ErrorCodeEnum>
  >       error_code(ErrorCodeEnum e) noexcept;

  > -3- Constraints: `is_error_code_enum_v<ErrorCodeEnum>` is `true`.

  > -4- Postconditions: `*this == make_error_code(e)`.
  > -4- Effects: Equivalent to:

  > >     error_code ec = make_error_code(e);
  > >     assign(ec.value(), ec.category());

- Modify 19.5.4.3 [syserr.errcode.modifiers] as indicated:

  >     template<class ErrorCodeEnum>
  >       error_code& operator=(ErrorCodeEnum e) noexcept;

  > -2- Constraints: `is_error_code_enum_v<ErrorCodeEnum>` is `true`.

  > -3- Postconditions: `*this == make_error_code(e)`.
  > -3- Effects: Equivalent to:

  > >     error_code ec = make_error_code(e);
  > >     assign(ec.value(), ec.category());

  > -4- Returns: `*this`.

- Modify 19.5.5.2 [syserr.errcondition.constructors] as indicated:

  >     error_condition() noexcept;

  > -1- Postconditions: `val_ == 0` and `cat_ == &generic_category()`.
  > -1- Effects: Initializes `val_` with `0` and `cat_` with `&generic_category()`.

  >     error_condition(int val, const error_category& cat) noexcept;

  > -2- Postconditions: `val_ == val` and `cat_ == &cat`.
  > -2- Effects: Initializes `val_` with `val` and `cat_` with `&cat`.

  >     template<class ErrorConditionEnum>
  >       error_condition(ErrorConditionEnum e) noexcept;

  > -3- Constraints: `is_error_condition_enum_v<ErrorConditionEnum>` is `true`.

  > -4- Postconditions: `*this == make_error_condition(e)`.
  > -4- Effects: Equivalent to:

  > >     error_condition ec = make_error_condition(e);
  > >     assign(ec.value(), ec.category());

- Modify 19.5.5.3 [syserr.errcondition.modifiers] as indicated:

  >     template<class ErrorConditionEnum>
  >       error_condition& operator=(ErrorConditionEnum e) noexcept;

  > -2- Constraints: `is_error_condition_enum_v<ErrorConditionEnum>` is `true`.

  > -3- Postconditions: `*this == make_error_condition(e)`.
  > -3- Effects: Equivalent to:

  > >     error_condition ec = make_error_condition(e);
  > >     assign(ec.value(), ec.category());

  > -4- Returns: `*this`.