[libcxx-commits] [libcxx] [libc++] Deprecate non-standard std::launch::any extension (PR #173397)
via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Dec 23 10:42:02 PST 2025
https://github.com/sohail103 updated https://github.com/llvm/llvm-project/pull/173397
>From 4ded9fff4f558221184333f176c7f4df2d6931c2 Mon Sep 17 00:00:00 2001
From: sohail103 <sohailraj.satapathy at gmail.com>
Date: Tue, 23 Dec 2025 17:07:21 +0000
Subject: [PATCH] [libc++] Deprecate non-standard std::launch::any extension
std::launch::any was a draft C++11 feature that was removed before the final standard.
It has remained in libc++ as an extension. This patch marks it as deprecated to warn users
who might be relying on it unintentionally.
- Replaced internal usage of std::launch::any in std::async with standard flags.
- Added a verify test to check for the deprecation warning.
- Updated existing tests to expect the deprecation warning.
Fixes #173219
---
libcxx/include/future | 4 +-
.../diagnostics/future.nodiscard.verify.cpp | 1 +
.../futures/launch_any_deprecated.verify.cpp | 21 +++
.../futures/futures.async/async.pass.cpp | 155 +++++++++---------
.../futures/futures.overview/launch.pass.cpp | 38 +++--
5 files changed, 123 insertions(+), 96 deletions(-)
create mode 100644 libcxx/test/libcxx/thread/futures/launch_any_deprecated.verify.cpp
diff --git a/libcxx/include/future b/libcxx/include/future
index c249bc5e7938f..631572c6ebe8d 100644
--- a/libcxx/include/future
+++ b/libcxx/include/future
@@ -434,7 +434,7 @@ struct is_error_code_enum<future_errc::__lx> : public true_type {};
# endif
// enum class launch
-_LIBCPP_DECLARE_STRONG_ENUM(launch){async = 1, deferred = 2, any = async | deferred};
+_LIBCPP_DECLARE_STRONG_ENUM(launch){async = 1, deferred = 2, any _LIBCPP_DEPRECATED = async | deferred};
_LIBCPP_DECLARE_STRONG_ENUM_EPILOG(launch)
# ifndef _LIBCPP_CXX03_LANG
@@ -1872,7 +1872,7 @@ async(launch __policy, _Fp&& __f, _Args&&... __args) {
template <class _Fp, class... _Args>
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI future<__invoke_result_t<__decay_t<_Fp>, __decay_t<_Args>...> >
async(_Fp&& __f, _Args&&... __args) {
- return std::async(launch::any, std::forward<_Fp>(__f), std::forward<_Args>(__args)...);
+ return std::async(launch::async | launch::deferred, std::forward<_Fp>(__f), std::forward<_Args>(__args)...);
}
# endif // C++03
diff --git a/libcxx/test/libcxx/diagnostics/future.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/future.nodiscard.verify.cpp
index cc5c6135d109b..2eadd429b1629 100644
--- a/libcxx/test/libcxx/diagnostics/future.nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/diagnostics/future.nodiscard.verify.cpp
@@ -19,4 +19,5 @@
void test() {
std::async([]() {}); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
std::async(std::launch::any, []() {}); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ // expected-warning at -1 {{'any' is deprecated}}
}
diff --git a/libcxx/test/libcxx/thread/futures/launch_any_deprecated.verify.cpp b/libcxx/test/libcxx/thread/futures/launch_any_deprecated.verify.cpp
new file mode 100644
index 0000000000000..aa6ed5cccecb6
--- /dev/null
+++ b/libcxx/test/libcxx/thread/futures/launch_any_deprecated.verify.cpp
@@ -0,0 +1,21 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <future>
+
+// enum class launch;
+
+// Verify that std::launch::any is deprecated.
+// It was a draft C++11 feature that was removed, but libc++ kept it as an extension.
+
+#include <future>
+
+void test() {
+ auto l = std::launch::any; // expected-warning {{'any' is deprecated}}
+ (void)l;
+}
diff --git a/libcxx/test/std/thread/futures/futures.async/async.pass.cpp b/libcxx/test/std/thread/futures/futures.async/async.pass.cpp
index 109372b50a311..3694504105963 100644
--- a/libcxx/test/std/thread/futures/futures.async/async.pass.cpp
+++ b/libcxx/test/std/thread/futures/futures.async/async.pass.cpp
@@ -21,7 +21,6 @@
// future<typename result_of<F(Args...)>::type>
// async(launch policy, F&& f, Args&&... args);
-
#include <atomic>
#include <cassert>
#include <chrono>
@@ -36,47 +35,41 @@ typedef std::chrono::milliseconds ms;
std::atomic_bool invoked{false};
-int f0()
-{
- invoked = true;
- std::this_thread::sleep_for(ms(200));
- return 3;
+int f0() {
+ invoked = true;
+ std::this_thread::sleep_for(ms(200));
+ return 3;
}
int i = 0;
-int& f1()
-{
- invoked = true;
- std::this_thread::sleep_for(ms(200));
- return i;
+int& f1() {
+ invoked = true;
+ std::this_thread::sleep_for(ms(200));
+ return i;
}
-void f2()
-{
- invoked = true;
- std::this_thread::sleep_for(ms(200));
+void f2() {
+ invoked = true;
+ std::this_thread::sleep_for(ms(200));
}
-std::unique_ptr<int> f3(int j)
-{
- invoked = true;
- std::this_thread::sleep_for(ms(200));
- return std::unique_ptr<int>(new int(j));
+std::unique_ptr<int> f3(int j) {
+ invoked = true;
+ std::this_thread::sleep_for(ms(200));
+ return std::unique_ptr<int>(new int(j));
}
-std::unique_ptr<int> f4(std::unique_ptr<int>&& p)
-{
- invoked = true;
- std::this_thread::sleep_for(ms(200));
- return std::move(p);
+std::unique_ptr<int> f4(std::unique_ptr<int>&& p) {
+ invoked = true;
+ std::this_thread::sleep_for(ms(200));
+ return std::move(p);
}
-void f5(int j)
-{
- std::this_thread::sleep_for(ms(200));
- ((void)j);
- TEST_THROW(j);
+void f5(int j) {
+ std::this_thread::sleep_for(ms(200));
+ ((void)j);
+ TEST_THROW(j);
}
template <class Ret, class CheckLambda, class... Args>
@@ -106,54 +99,64 @@ void test(CheckLambda&& getAndCheckFn, bool IsDeferred, Args&&... args) {
}
}
-int main(int, char**)
-{
- // The default launch policy is implementation defined. libc++ defines
- // it to be std::launch::async.
- bool DefaultPolicyIsDeferred = false;
- bool DPID = DefaultPolicyIsDeferred;
-
- std::launch AnyPolicy = std::launch::async | std::launch::deferred;
- LIBCPP_ASSERT(AnyPolicy == std::launch::any);
-
- {
- auto checkInt = [](std::future<int>& f) { return f.get() == 3; };
- test<int>(checkInt, DPID, f0);
- test<int>(checkInt, false, std::launch::async, f0);
- test<int>(checkInt, true, std::launch::deferred, f0);
- test<int>(checkInt, DPID, AnyPolicy, f0);
- }
- {
- auto checkIntRef = [&](std::future<int&>& f) { return &f.get() == &i; };
- test<int&>(checkIntRef, DPID, f1);
- test<int&>(checkIntRef, false, std::launch::async, f1);
- test<int&>(checkIntRef, true, std::launch::deferred, f1);
- test<int&>(checkIntRef, DPID, AnyPolicy, f1);
- }
- {
- auto checkVoid = [](std::future<void>& f) { f.get(); return true; };
- test<void>(checkVoid, DPID, f2);
- test<void>(checkVoid, false, std::launch::async, f2);
- test<void>(checkVoid, true, std::launch::deferred, f2);
- test<void>(checkVoid, DPID, AnyPolicy, f2);
- }
- {
- using Ret = std::unique_ptr<int>;
- auto checkUPtr = [](std::future<Ret>& f) { return *f.get() == 3; };
- test<Ret>(checkUPtr, DPID, f3, 3);
- test<Ret>(checkUPtr, DPID, f4, std::unique_ptr<int>(new int(3)));
- }
+int main(int, char**) {
+ // The default launch policy is implementation defined. libc++ defines
+ // it to be std::launch::async.
+ bool DefaultPolicyIsDeferred = false;
+ bool DPID = DefaultPolicyIsDeferred;
+
+ std::launch AnyPolicy = std::launch::async | std::launch::deferred;
+ LIBCPP_ASSERT(AnyPolicy == std::launch::any); // expected-warning {{'any' is deprecated}}
+
+ {
+ auto checkInt = [](std::future<int>& f) { return f.get() == 3; };
+ test<int>(checkInt, DPID, f0);
+ test<int>(checkInt, false, std::launch::async, f0);
+ test<int>(checkInt, true, std::launch::deferred, f0);
+ test<int>(checkInt, DPID, AnyPolicy, f0);
+ }
+ {
+ auto checkIntRef = [&](std::future<int&>& f) { return &f.get() == &i; };
+ test<int&>(checkIntRef, DPID, f1);
+ test<int&>(checkIntRef, false, std::launch::async, f1);
+ test<int&>(checkIntRef, true, std::launch::deferred, f1);
+ test<int&>(checkIntRef, DPID, AnyPolicy, f1);
+ }
+ {
+ auto checkVoid = [](std::future<void>& f) {
+ f.get();
+ return true;
+ };
+ test<void>(checkVoid, DPID, f2);
+ test<void>(checkVoid, false, std::launch::async, f2);
+ test<void>(checkVoid, true, std::launch::deferred, f2);
+ test<void>(checkVoid, DPID, AnyPolicy, f2);
+ }
+ {
+ using Ret = std::unique_ptr<int>;
+ auto checkUPtr = [](std::future<Ret>& f) { return *f.get() == 3; };
+ test<Ret>(checkUPtr, DPID, f3, 3);
+ test<Ret>(checkUPtr, DPID, f4, std::unique_ptr<int>(new int(3)));
+ }
#ifndef TEST_HAS_NO_EXCEPTIONS
- {
- std::future<void> f = std::async(f5, 3);
- std::this_thread::sleep_for(ms(300));
- try { f.get(); assert (false); } catch ( int ) {}
+ {
+ std::future<void> f = std::async(f5, 3);
+ std::this_thread::sleep_for(ms(300));
+ try {
+ f.get();
+ assert(false);
+ } catch (int) {
}
- {
- std::future<void> f = std::async(std::launch::deferred, f5, 3);
- std::this_thread::sleep_for(ms(300));
- try { f.get(); assert (false); } catch ( int ) {}
+ }
+ {
+ std::future<void> f = std::async(std::launch::deferred, f5, 3);
+ std::this_thread::sleep_for(ms(300));
+ try {
+ f.get();
+ assert(false);
+ } catch (int) {
}
+ }
#endif
- return 0;
+ return 0;
}
diff --git a/libcxx/test/std/thread/futures/futures.overview/launch.pass.cpp b/libcxx/test/std/thread/futures/futures.overview/launch.pass.cpp
index 37ad2ff4a8645..05beb836e802a 100644
--- a/libcxx/test/std/thread/futures/futures.overview/launch.pass.cpp
+++ b/libcxx/test/std/thread/futures/futures.overview/launch.pass.cpp
@@ -22,27 +22,29 @@
#include "test_macros.h"
-int main(int, char**)
-{
+int main(int, char**) {
#if TEST_STD_VER < 11
- LIBCPP_STATIC_ASSERT(static_cast<int>(std::launch::any) ==
- (static_cast<int>(std::launch::async) | static_cast<int>(std::launch::deferred)), "");
+ LIBCPP_STATIC_ASSERT(static_cast<int>(std::launch::any) == // expected-warning {{'any' is deprecated}}
+ (static_cast<int>(std::launch::async) | static_cast<int>(std::launch::deferred)),
+ "");
#else
- LIBCPP_STATIC_ASSERT(std::launch::any == (std::launch::async | std::launch::deferred), "");
- static_assert(std::launch(0) == (std::launch::async & std::launch::deferred), "");
- LIBCPP_STATIC_ASSERT(std::launch::any == (std::launch::async ^ std::launch::deferred), "");
- LIBCPP_STATIC_ASSERT(std::launch::deferred == ~std::launch::async, "");
- std::launch x = std::launch::async;
- x &= std::launch::deferred;
- assert(x == std::launch(0));
- x = std::launch::async;
- x |= std::launch::deferred;
- LIBCPP_ASSERT(x == std::launch::any);
- x ^= std::launch::deferred;
- assert(x == std::launch::async);
+ LIBCPP_STATIC_ASSERT(
+ std::launch::any == (std::launch::async | std::launch::deferred), ""); // expected-warning {{'any' is deprecated}}
+ static_assert(std::launch(0) == (std::launch::async & std::launch::deferred), "");
+ LIBCPP_STATIC_ASSERT(
+ std::launch::any == (std::launch::async ^ std::launch::deferred), ""); // expected-warning {{'any' is deprecated}}
+ LIBCPP_STATIC_ASSERT(std::launch::deferred == ~std::launch::async, "");
+ std::launch x = std::launch::async;
+ x &= std::launch::deferred;
+ assert(x == std::launch(0));
+ x = std::launch::async;
+ x |= std::launch::deferred;
+ LIBCPP_ASSERT(x == std::launch::any); // expected-warning {{'any' is deprecated}}
+ x ^= std::launch::deferred;
+ assert(x == std::launch::async);
#endif
- static_assert(static_cast<int>(std::launch::async) == 1, "");
- static_assert(static_cast<int>(std::launch::deferred) == 2, "");
+ static_assert(static_cast<int>(std::launch::async) == 1, "");
+ static_assert(static_cast<int>(std::launch::deferred) == 2, "");
return 0;
}
More information about the libcxx-commits
mailing list