2992. system_category() and error_code::error_code() should be constexpr

Section: 22.5.2.5 [syserr.errcat.objects], 22.5.3.2 [syserr.errcode.constructors] Status: NAD Submitter: Peter Dimov Opened: 2017-06-27 Last modified: 2017-07-12

Priority: Not Prioritized

View all other issues in [syserr.errcat.objects].

View all issues with NAD status.

Discussion:

The default constructor of error_code should be constexpr to enable constant initialization; as a practical matter, there are reports that it regularly shows up in profiles because clearing error codes is so frequent.

Suggested resolution:

There was an objection that system_category() can't be made constexpr because it needs to "immortalize" the object so that it's not destroyed at process shutdown or module unload, in order for the error_code facility to remain usable. However, the following proof of concept shows how to achieve this and still make the function constexpr:

#include <new>

template<class _Ty>
  union _Immortalizer
  { // constructs _Ty, never destroys
  constexpr _Immortalizer(): __ty()
  {
  }

  ~_Immortalizer() noexcept {}
  _Immortalizer(const _Immortalizer&) = delete;
  _Immortalizer& operator=(const _Immortalizer&) = delete;

  _Ty __ty;
};

struct error_category
{
  virtual ~error_category() = default;
};

struct system_category_impl : public error_category
{
};

[[clang::require_constant_initialization]] static const _Immortalizer<system_category_impl> _System_category;

constexpr error_category const& system_category() noexcept
{
  return _System_category.__ty;
}

struct error_code
{
  int val_;
  const error_category* cat_;

  constexpr error_code() noexcept : val_(0), cat_(&system_category()) {}

  constexpr int value() const noexcept { return val_; }
  constexpr error_category const& category() const noexcept { return *cat_; }
};

constexpr error_code s_code;

static_assert(s_code.value() == 0);
static_assert(&s_code.category() == &system_category());

[2017-07 Toronto Tuesday PM issue prioritization]

NAD; This is a feature request; needs a paper.

Proposed resolution:

This wording is relative to N4659.

  1. Edit 22.5.2.1 [syserr.errcat.overview], class error_category synopsis, as indicated:

    class error_category {
    public:
      constexpr error_category() noexcept;
      virtual ~error_category();
      error_category(const error_category&) = delete;
      error_category& operator=(const error_category&) = delete;
      virtual const char* name() const noexcept = 0;
      virtual error_condition default_error_condition(int ev) const noexcept;
      virtual bool equivalent(int code, const error_condition& condition) const noexcept;
      virtual bool equivalent(const error_code& code, int condition) const noexcept;
      virtual string message(int ev) const = 0;
    
      bool operator==(const error_category& rhs) const noexcept;
      bool operator!=(const error_category& rhs) const noexcept;
      bool operator<(const error_category& rhs) const noexcept;
    };
    
    constexpr const error_category& generic_category() noexcept;
    constexpr const error_category& system_category() noexcept;
    
  2. Edit 22.5.2.5 [syserr.errcat.objects] as indicated:

    constexpr const error_category& generic_category() noexcept;
    

    […]

    constexpr const error_category& system_category() noexcept;
    

    […]

  3. Edit 22.5.3.1 [syserr.errcode.overview], class error_code synopsis, as indicated:

    class error_code {
    public:
      // 22.5.3.2 [syserr.errcode.constructors], constructors
      constexpr error_code() noexcept;
      constexpr error_code(int val, const error_category& cat) noexcept;
      template <class ErrorCodeEnum>
      error_code(ErrorCodeEnum e) noexcept;
      
      // 22.5.3.3 [syserr.errcode.modifiers], modifiers
      constexpr void assign(int val, const error_category& cat) noexcept;
      template <class ErrorCodeEnum>
      error_code& operator=(ErrorCodeEnum e) noexcept;
      constexpr void clear() noexcept;
      
      // 22.5.3.4 [syserr.errcode.observers], observers
      constexpr int value() const noexcept;
      constexpr const error_category& category() const noexcept;
      error_condition default_error_condition() const noexcept;
      string message() const;
      explicit operator bool() const noexcept;
      
    private:
      int val_; // exposition only
      const error_category* cat_; // exposition only
    };
  4. Edit 22.5.3.2 [syserr.errcode.constructors] as indicated:

    constexpr error_code() noexcept;
    

    […]

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

    […]

  5. Edit 22.5.3.3 [syserr.errcode.modifiers] as indicated:

    constexpr void assign(int val, const error_category& cat) noexcept;
    

    […]

    constexpr void clear() noexcept;
    

    […]

  6. Edit 22.5.3.4 [syserr.errcode.observers] as indicated:

    constexpr int value() const noexcept;
    

    […]

    constexpr const error_category& category() const noexcept;
    

    […]