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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits