[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