EricWF created this revision.

The constructor `future_error(error_code)` isn't part of the C++ standard, but 
libc++ provides it in order to construct `future_error`'s before C++17.
However since it's non-standard we probably shouldn't be providing it all. We 
could make the constructor private but I suspect users already depend
on this extension. Instead this patch does the following:

1. Make it explicit so it doesn't cause weird implicit conversion bugs.
2. Generate a warning when the constructor is called from user code.
3. Cleanup tests that depend on the constructor.

@mclow.lists thoughts on handling this?


https://reviews.llvm.org/D29550

Files:
  docs/UsingLibcxx.rst
  include/__config
  include/future
  
test/libcxx/thread/futures/futures.future_error/diagnose_extended_constructor.fail.cpp
  test/libcxx/thread/futures/futures.future_error/extended_constructor.pass.cpp
  test/std/thread/futures/futures.future_error/code.pass.cpp
  test/std/thread/futures/futures.future_error/what.pass.cpp

Index: test/std/thread/futures/futures.future_error/what.pass.cpp
===================================================================
--- test/std/thread/futures/futures.future_error/what.pass.cpp
+++ test/std/thread/futures/futures.future_error/what.pass.cpp
@@ -28,24 +28,38 @@
 
 #include "test_macros.h"
 
+
+#if defined(__clang__)
+#pragma clang diagnostic ignored "-Wuser-defined-warnings"
+#endif
+
+template <class ErrC> // make dependent to prevent compile errors
+std::future_error make_error(ErrC ec) {
+#if TEST_STD_VER > 14
+  return std::future_error(ec);
+#else
+  return std::future_error(std::make_error_code(ec)); // libc++ extension
+#endif
+}
+
 int main()
 {
     {
-        std::future_error f(std::make_error_code(std::future_errc::broken_promise));
+        std::future_error f = make_error(std::future_errc::broken_promise);
         LIBCPP_ASSERT(std::strcmp(f.what(), "The associated promise has been destructed prior "
                       "to the associated state becoming ready.") == 0);
     }
     {
-        std::future_error f(std::make_error_code(std::future_errc::future_already_retrieved));
+        std::future_error f = make_error(std::future_errc::future_already_retrieved);
         LIBCPP_ASSERT(std::strcmp(f.what(), "The future has already been retrieved from "
                       "the promise or packaged_task.") == 0);
     }
     {
-        std::future_error f(std::make_error_code(std::future_errc::promise_already_satisfied));
+        std::future_error f = make_error(std::future_errc::promise_already_satisfied);
         LIBCPP_ASSERT(std::strcmp(f.what(), "The state of the promise has already been set.") == 0);
     }
     {
-        std::future_error f(std::make_error_code(std::future_errc::no_state));
+        std::future_error f = make_error(std::future_errc::no_state);
         LIBCPP_ASSERT(std::strcmp(f.what(), "Operation not permitted on an object without "
                       "an associated state.") == 0);
     }
Index: test/std/thread/futures/futures.future_error/code.pass.cpp
===================================================================
--- test/std/thread/futures/futures.future_error/code.pass.cpp
+++ test/std/thread/futures/futures.future_error/code.pass.cpp
@@ -22,8 +22,13 @@
 
 #include "test_macros.h"
 
+#if defined(__clang__)
+#pragma clang diagnostic ignored "-Wuser-defined-warnings"
+#endif
+
 int main()
 {
+#if defined(_LIBCPP_VERSION)
     {
         std::error_code ec = std::make_error_code(std::future_errc::broken_promise);
         std::future_error f(ec);
@@ -44,6 +49,7 @@
         std::future_error f(ec);
         assert(f.code() == ec);
     }
+#endif // _LIBCPP_VERSION
 #if TEST_STD_VER > 14
     {
         std::future_error f(std::future_errc::broken_promise);
Index: test/libcxx/thread/futures/futures.future_error/extended_constructor.pass.cpp
===================================================================
--- /dev/null
+++ test/libcxx/thread/futures/futures.future_error/extended_constructor.pass.cpp
@@ -0,0 +1,24 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// UNSUPPORTED: libcpp-has-no-threads
+
+// <future>
+
+// class future_error
+
+// future_error(error_code) // libc++ extension
+
+#include <future>
+#include <type_traits>
+
+int main() {
+  static_assert(std::is_constructible<std::future_error, std::error_code>::value, "");
+  static_assert(!std::is_convertible<std::error_code, std::future_error>::value, "");
+}
Index: test/libcxx/thread/futures/futures.future_error/diagnose_extended_constructor.fail.cpp
===================================================================
--- /dev/null
+++ test/libcxx/thread/futures/futures.future_error/diagnose_extended_constructor.fail.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// UNSUPPORTED: libcpp-has-no-threads
+// REQUIRES: diagnose-if-support
+
+// <future>
+
+// class future_error
+
+// future_error(error_code) // libc++ extension
+
+#include <future>
+
+int main() {
+  std::future_error f(std::make_error_code(std::future_errc::broken_promise));
+    // expected-warning@-1 {{this constructor is a libc++ extension}}
+  ((void)f);
+}
Index: include/future
===================================================================
--- include/future
+++ include/future
@@ -504,7 +504,9 @@
 {
     error_code __ec_;
 public:
-    future_error(error_code __ec);
+    explicit future_error(error_code __ec)
+        _LIBCPP_DIAGNOSE_WARNING(_LIBCPP_DIAGNOSE_EXTENSIONS,
+                                 "this constructor is a libc++ extension");
 #if _LIBCPP_STD_VERS > 14
     explicit future_error(future_errc _Ev) : logic_error(), __ec_(make_error_code(_Ev)) {}
 #endif
@@ -514,6 +516,11 @@
     virtual ~future_error() _NOEXCEPT;
 };
 
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wuser-defined-warnings"
+#endif
+
 _LIBCPP_NORETURN inline _LIBCPP_ALWAYS_INLINE
 void __throw_future_error(future_errc _Ev)
 {
@@ -525,6 +532,16 @@
 #endif
 }
 
+inline _LIBCPP_ALWAYS_INLINE
+future_error __make_future_error(future_errc _Ev)
+{
+  return future_error(make_error_code(_Ev));
+}
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
 class _LIBCPP_TYPE_VIS __assoc_sub_state
     : public __shared_count
 {
@@ -1444,7 +1461,7 @@
     {
         if (!__state_->__has_value() && __state_->use_count() > 1)
             __state_->set_exception(make_exception_ptr(
-                      future_error(make_error_code(future_errc::broken_promise))
+                      __make_future_error(future_errc::broken_promise)
                                                       ));
         __state_->__release_shared();
     }
@@ -1606,7 +1623,7 @@
     {
         if (!__state_->__has_value() && __state_->use_count() > 1)
             __state_->set_exception(make_exception_ptr(
-                      future_error(make_error_code(future_errc::broken_promise))
+                    __make_future_error(future_errc::broken_promise)
                                                       ));
         __state_->__release_shared();
     }
Index: include/__config
===================================================================
--- include/__config
+++ include/__config
@@ -1041,6 +1041,12 @@
 # define _LIBCPP_DIAGNOSE_ERROR(...)
 #endif
 
+#if defined(_LIBCPP_BUILDING_LIBRARY) || defined(_LIBCPP_DISABLE_EXTENSION_DIAGNOSTICS)
+# define _LIBCPP_DIAGNOSE_EXTENSIONS 0
+#else
+# define _LIBCPP_DIAGNOSE_EXTENSIONS 1
+#endif
+
 #if defined(_LIBCPP_ABI_MICROSOFT) && \
    (defined(_LIBCPP_COMPILER_MSVC) || __has_declspec_attribute(empty_bases))
 # define _LIBCPP_DECLSPEC_EMPTY_BASES __declspec(empty_bases)
Index: docs/UsingLibcxx.rst
===================================================================
--- docs/UsingLibcxx.rst
+++ docs/UsingLibcxx.rst
@@ -180,3 +180,6 @@
     * Giving `set`, `map`, `multiset`, `multimap` a comparator which is not
       const callable.
 
+**_LIBCPP_DISABLE_EXTENSION_DIAGNOSTICS**:
+  This macro disables diagnostics generated by libc++ when a libc++ extension
+  is used.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to