PR libstdc++/60555 std::system_category() should recognise POSIX errno values
authorJonathan Wakely <jwakely@redhat.com>
Wed, 1 Aug 2018 13:57:05 +0000 (14:57 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Wed, 1 Aug 2018 13:57:05 +0000 (14:57 +0100)
PR libstdc++/60555
* src/c++11/system_error.cc
(system_error_category::default_error_condition): New override to
check for POSIX errno values.
* testsuite/19_diagnostics/error_category/generic_category.cc: New
* testsuite/19_diagnostics/error_category/system_category.cc: New
test.

From-SVN: r263210

libstdc++-v3/ChangeLog
libstdc++-v3/src/c++11/system_error.cc
libstdc++-v3/testsuite/19_diagnostics/error_category/generic_category.cc [new file with mode: 0644]
libstdc++-v3/testsuite/19_diagnostics/error_category/system_category.cc [new file with mode: 0644]

index b8532c280db02511d379ab7d3ebe8998bcd6c743..283babfe25c07e21c7aa6983bc479c0efc9b9621 100644 (file)
@@ -1,3 +1,13 @@
+2018-08-01  Jonathan Wakely  <jwakely@redhat.com>
+
+       PR libstdc++/60555
+       * src/c++11/system_error.cc
+       (system_error_category::default_error_condition): New override to
+       check for POSIX errno values.
+       * testsuite/19_diagnostics/error_category/generic_category.cc: New
+       * testsuite/19_diagnostics/error_category/system_category.cc: New
+       test.
+
 2018-07-31  Jonathan Wakely  <jwakely@redhat.com>
 
        PR libstdc++/86751
index c6549fcb4e08e8bf7b178dd14035d880f0c4c184..82b4cb5f98c6dcec4bde227db2748b54f7f54f64 100644 (file)
@@ -29,6 +29,7 @@
 #include <system_error>
 #include <bits/functexcept.h>
 #include <limits>
+#include <errno.h>
 #undef __sso_string
 
 namespace
@@ -65,6 +66,260 @@ namespace
       // _GLIBCXX_HAVE_STRERROR_L, strerror_l(i, cloc)
       return string(strerror(i));
     }
+
+    virtual std::error_condition
+    default_error_condition(int ev) const noexcept
+    {
+      switch (ev)
+      {
+      // List of errno macros from [cerrno.syn].
+      // C11 only defines EDOM, EILSEQ and ERANGE, the rest are from POSIX.
+      // They expand to integer constant expressions with type int,
+      // and distinct positive values, suitable for use in #if directives.
+      // POSIX adds more macros (but they're not defined on all targets,
+      // see config/os/*/error_constants.h), and POSIX allows
+      // EAGAIN == EWOULDBLOCK and ENOTSUP == EOPNOTSUPP.
+
+#ifdef E2BIG
+      case E2BIG:
+#endif
+#ifdef EACCES
+      case EACCES:
+#endif
+#ifdef EADDRINUSE
+      case EADDRINUSE:
+#endif
+#ifdef EADDRNOTAVAIL
+      case EADDRNOTAVAIL:
+#endif
+#ifdef EAFNOSUPPORT
+      case EAFNOSUPPORT:
+#endif
+#ifdef EAGAIN
+      case EAGAIN:
+#endif
+#ifdef EALREADY
+      case EALREADY:
+#endif
+#ifdef EBADF
+      case EBADF:
+#endif
+#ifdef EBADMSG
+      case EBADMSG:
+#endif
+#ifdef EBUSY
+      case EBUSY:
+#endif
+#ifdef ECANCELED
+      case ECANCELED:
+#endif
+#ifdef ECHILD
+      case ECHILD:
+#endif
+#ifdef ECONNABORTED
+      case ECONNABORTED:
+#endif
+#ifdef ECONNREFUSED
+      case ECONNREFUSED:
+#endif
+#ifdef ECONNRESET
+      case ECONNRESET:
+#endif
+#ifdef EDEADLK
+      case EDEADLK:
+#endif
+#ifdef EDESTADDRREQ
+      case EDESTADDRREQ:
+#endif
+      case EDOM:
+#ifdef EEXIST
+      case EEXIST:
+#endif
+#ifdef EFAULT
+      case EFAULT:
+#endif
+#ifdef EFBIG
+      case EFBIG:
+#endif
+#ifdef EHOSTUNREACH
+      case EHOSTUNREACH:
+#endif
+#ifdef EIDRM
+      case EIDRM:
+#endif
+      case EILSEQ:
+#ifdef EINPROGRESS
+      case EINPROGRESS:
+#endif
+#ifdef EINTR
+      case EINTR:
+#endif
+#ifdef EINVAL
+      case EINVAL:
+#endif
+#ifdef EIO
+      case EIO:
+#endif
+#ifdef EISCONN
+      case EISCONN:
+#endif
+#ifdef EISDIR
+      case EISDIR:
+#endif
+#ifdef ELOOP
+      case ELOOP:
+#endif
+#ifdef EMFILE
+      case EMFILE:
+#endif
+#ifdef EMLINK
+      case EMLINK:
+#endif
+#ifdef EMSGSIZE
+      case EMSGSIZE:
+#endif
+#ifdef ENAMETOOLONG
+      case ENAMETOOLONG:
+#endif
+#ifdef ENETDOWN
+      case ENETDOWN:
+#endif
+#ifdef ENETRESET
+      case ENETRESET:
+#endif
+#ifdef ENETUNREACH
+      case ENETUNREACH:
+#endif
+#ifdef ENFILE
+      case ENFILE:
+#endif
+#ifdef ENOBUFS
+      case ENOBUFS:
+#endif
+#ifdef ENODATA
+      case ENODATA:
+#endif
+#ifdef ENODEV
+      case ENODEV:
+#endif
+#ifdef ENOENT
+      case ENOENT:
+#endif
+#ifdef ENOEXEC
+      case ENOEXEC:
+#endif
+#ifdef ENOLCK
+      case ENOLCK:
+#endif
+#ifdef ENOLINK
+      case ENOLINK:
+#endif
+#ifdef ENOMEM
+      case ENOMEM:
+#endif
+#ifdef ENOMSG
+      case ENOMSG:
+#endif
+#ifdef ENOPROTOOPT
+      case ENOPROTOOPT:
+#endif
+#ifdef ENOSPC
+      case ENOSPC:
+#endif
+#ifdef ENOSR
+      case ENOSR:
+#endif
+#ifdef ENOSTR
+      case ENOSTR:
+#endif
+#ifdef ENOSYS
+      case ENOSYS:
+#endif
+#ifdef ENOTCONN
+      case ENOTCONN:
+#endif
+#ifdef ENOTDIR
+      case ENOTDIR:
+#endif
+#ifdef ENOTEMPTY
+      case ENOTEMPTY:
+#endif
+#ifdef ENOTRECOVERABLE
+      case ENOTRECOVERABLE:
+#endif
+#ifdef ENOTSOCK
+      case ENOTSOCK:
+#endif
+#ifdef ENOTSUP
+      case ENOTSUP:
+#endif
+#ifdef ENOTTY
+      case ENOTTY:
+#endif
+#ifdef ENXIO
+      case ENXIO:
+#endif
+#if defined EOPNOTSUPP && (!defined ENOTSUP || EOPNOTSUPP != ENOTSUP)
+      case EOPNOTSUPP:
+#endif
+#ifdef EOVERFLOW
+      case EOVERFLOW:
+#endif
+#ifdef EOWNERDEAD
+      case EOWNERDEAD:
+#endif
+#ifdef EPERM
+      case EPERM:
+#endif
+#ifdef EPIPE
+      case EPIPE:
+#endif
+#ifdef EPROTO
+      case EPROTO:
+#endif
+#ifdef EPROTONOSUPPORT
+      case EPROTONOSUPPORT:
+#endif
+#ifdef EPROTOTYPE
+      case EPROTOTYPE:
+#endif
+      case ERANGE:
+#ifdef EROFS
+      case EROFS:
+#endif
+#ifdef ESPIPE
+      case ESPIPE:
+#endif
+#ifdef ESRCH
+      case ESRCH:
+#endif
+#ifdef ETIME
+      case ETIME:
+#endif
+#ifdef ETIMEDOUT
+      case ETIMEDOUT:
+#endif
+#ifdef ETXTBSY
+      case ETXTBSY:
+#endif
+#if defined EWOULDBLOCK && (!defined EAGAIN || EWOULDBLOCK != EAGAIN)
+      case EWOULDBLOCK:
+#endif
+#ifdef EXDEV
+      case EXDEV:
+#endif
+        return std::error_condition(ev, std::generic_category());
+
+      /* Additional system-dependent mappings from non-standard error codes
+       * to one of the POSIX values above would go here, e.g.
+      case EBLAH:
+       return std::error_condition(EINVAL, std::generic_category());
+       */
+
+      default:
+       return std::error_condition(ev, std::system_category());
+      }
+    }
   };
 
   const generic_error_category generic_category_instance{};
diff --git a/libstdc++-v3/testsuite/19_diagnostics/error_category/generic_category.cc b/libstdc++-v3/testsuite/19_diagnostics/error_category/generic_category.cc
new file mode 100644 (file)
index 0000000..64881f4
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++11 } }
+
+#include <system_error>
+#include <locale>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  const char* name = std::generic_category().name();
+  VERIFY( name == std::string("generic") );
+}
+
+void
+test02()
+{
+  const std::error_category& cat = std::generic_category();
+  std::error_condition cond;
+
+  cond = cat.default_error_condition(EBADF);
+  VERIFY( cond.value() == EBADF );
+  VERIFY( cond == std::errc::bad_file_descriptor );
+  VERIFY( cond.category() == std::generic_category() );
+  cond = cat.default_error_condition(EACCES);
+  VERIFY( cond.value() == EACCES );
+  VERIFY( cond == std::errc::permission_denied );
+  VERIFY( cond.category() == std::generic_category() );
+
+  // PR libstdc++/60555
+  VERIFY( std::error_code(EBADF, cat) == std::errc::bad_file_descriptor );
+  VERIFY( std::error_code(EACCES, cat) == std::errc::permission_denied );
+}
+
+void
+test03()
+{
+  // set "C" locale to get expected message
+  auto loc = std::locale::global(std::locale::classic());
+
+  std::string msg = std::generic_category().message(EBADF);
+  VERIFY( msg.find("file") != std::string::npos );
+
+  std::locale::global(loc);
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+}
diff --git a/libstdc++-v3/testsuite/19_diagnostics/error_category/system_category.cc b/libstdc++-v3/testsuite/19_diagnostics/error_category/system_category.cc
new file mode 100644 (file)
index 0000000..6076d73
--- /dev/null
@@ -0,0 +1,77 @@
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++11 } }
+
+#include <system_error>
+#include <locale>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  const char* name = std::system_category().name();
+  VERIFY( name == std::string("system") );
+}
+
+void
+test02()
+{
+  const std::error_category& cat = std::system_category();
+  std::error_condition cond;
+
+  cond = cat.default_error_condition(EBADF);
+  VERIFY( cond.value() == EBADF );
+  VERIFY( cond == std::errc::bad_file_descriptor );
+  VERIFY( cond.category() == std::generic_category() );
+  cond = cat.default_error_condition(EACCES);
+  VERIFY( cond.value() == EACCES );
+  VERIFY( cond == std::errc::permission_denied );
+  VERIFY( cond.category() == std::generic_category() );
+
+  // All POSIX errno values are positive:
+  cond = cat.default_error_condition(-1);
+  VERIFY( cond.value() == -1 );
+  VERIFY( cond.category() == cat );
+  cond = cat.default_error_condition(-99);
+  VERIFY( cond.value() == -99 );
+  VERIFY( cond.category() == cat );
+
+  // PR libstdc++/60555
+  VERIFY( std::error_code(EBADF, cat) == std::errc::bad_file_descriptor );
+  VERIFY( std::error_code(EACCES, cat) == std::errc::permission_denied );
+}
+
+void
+test03()
+{
+  // set "C" locale to get expected message
+  auto loc = std::locale::global(std::locale::classic());
+
+  std::string msg = std::system_category().message(EBADF);
+  VERIFY( msg.find("file") != std::string::npos );
+
+  std::locale::global(loc);
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+}