[libcxx-commits] [libcxx] [llvm] [libc++][CI] Upgrade compiler HEAD version to Clang-20 (PR #108761)

Robin Caloudis via libcxx-commits libcxx-commits at lists.llvm.org
Wed Sep 18 14:20:00 PDT 2024


https://github.com/robincaloudis updated https://github.com/llvm/llvm-project/pull/108761

>From 66c9942b9a70d2ad8a2498d051bb51c3fcf5a0cc Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Sun, 15 Sep 2024 17:09:35 +0200
Subject: [PATCH 1/2] [libc++][CI] Update to Clang-20

---
 .github/workflows/libcxx-build-and-test.yaml  |  26 ++--
 libcxx/docs/ReleaseNotes/20.rst               |   4 +-
 libcxx/docs/index.rst                         |   2 +-
 libcxx/include/__chrono/weekday.h             |  19 ---
 libcxx/include/__configuration/compiler.h     |   4 +-
 libcxx/include/__type_traits/promote.h        |  81 -----------
 .../diagnose_invalid_memory_order.verify.cpp  |   2 +-
 libcxx/test/libcxx/clang_tidy.gen.py          |   9 +-
 .../libcxx/gdb/gdb_pretty_printer_test.sh.cpp |   2 +-
 .../no_unique_address.compile.pass.cpp        |   2 +-
 .../no_unique_address.compile.pass.cpp        |   2 +-
 .../no_unique_address.compile.pass.cpp        |   2 +-
 .../transform_error.mandates.verify.cpp       |  20 ++-
 .../transform_error.mandates.verify.cpp       |  24 ++--
 .../atomics.types.float/fetch_add.pass.cpp    |   2 +-
 .../atomics.types.float/fetch_sub.pass.cpp    |   2 +-
 .../operator.minus_equals.pass.cpp            |   2 +-
 .../operator.plus_equals.pass.cpp             |   2 +-
 .../simd/simd.class/simd_copy.pass.cpp        |   2 +-
 .../sized_delete_array14.pass.cpp             |   2 +-
 .../new.delete.single/sized_delete14.pass.cpp |   2 +-
 .../test/std/numerics/c.math/signbit.pass.cpp |   2 +-
 .../numeric.ops.sat/add_sat.pass.cpp          |   6 +-
 .../numeric.ops.sat/div_sat.pass.cpp          |   6 +-
 .../numeric.ops.sat/mul_sat.pass.cpp          |   6 +-
 .../numeric.ops.sat/saturate_cast.pass.cpp    | 132 +++++++++---------
 .../numeric.ops.sat/sub_sat.pass.cpp          |   6 +-
 .../expected.expected/ctor/ctor.copy.pass.cpp |   3 -
 .../format.arg/visit.pass.cpp                 |   1 -
 .../format.arg/visit.return_type.pass.cpp     |   1 -
 .../visit_format_arg.deprecated.verify.cpp    |   1 -
 .../meta/meta.rel/is_virtual_base_of.pass.cpp |   2 +-
 .../nttp.equivalence.compile.pass.cpp         |   1 -
 .../utility/pairs/pairs.pair/nttp.verify.cpp  |   1 -
 .../robust_against_adl.pass.cpp               |   1 -
 .../variant.visit.member/visit.pass.cpp       |   1 -
 .../visit_return_type.pass.cpp                |   1 -
 37 files changed, 127 insertions(+), 257 deletions(-)

diff --git a/.github/workflows/libcxx-build-and-test.yaml b/.github/workflows/libcxx-build-and-test.yaml
index b5e60781e00064..426c40cc2f248c 100644
--- a/.github/workflows/libcxx-build-and-test.yaml
+++ b/.github/workflows/libcxx-build-and-test.yaml
@@ -38,11 +38,11 @@ env:
   # LLVM POST-BRANCH bump version
   # LLVM POST-BRANCH add compiler test for ToT - 1, e.g. "Clang 17"
   # LLVM RELEASE bump remove compiler ToT - 3, e.g. "Clang 15"
-  LLVM_HEAD_VERSION: "19"   # Used compiler, update POST-BRANCH.
-  LLVM_PREVIOUS_VERSION: "18"
-  LLVM_OLDEST_VERSION: "17"
+  LLVM_HEAD_VERSION: "20"   # Used compiler, update POST-BRANCH.
+  LLVM_PREVIOUS_VERSION: "19"
+  LLVM_OLDEST_VERSION: "18"
   GCC_STABLE_VERSION: "13"
-  LLVM_SYMBOLIZER_PATH: "/usr/bin/llvm-symbolizer-19"
+  LLVM_SYMBOLIZER_PATH: "/usr/bin/llvm-symbolizer-20"
   CLANG_CRASH_DIAGNOSTICS_DIR: "crash_diagnostics"
 
 
@@ -59,8 +59,8 @@ jobs:
           'generic-cxx26',
           'generic-modules'
         ]
-        cc: [  'clang-19' ]
-        cxx: [ 'clang++-19' ]
+        cc: [  'clang-20' ]
+        cxx: [ 'clang++-20' ]
         include:
           - config: 'generic-gcc'
             cc: 'gcc-14'
@@ -97,18 +97,18 @@ jobs:
           'generic-cxx20',
           'generic-cxx23'
         ]
-        cc: [ 'clang-19' ]
-        cxx: [ 'clang++-19' ]
+        cc: [ 'clang-20' ]
+        cxx: [ 'clang++-20' ]
         include:
           - config: 'generic-gcc-cxx11'
             cc: 'gcc-14'
             cxx: 'g++-14'
-          - config: 'generic-cxx23'
-            cc: 'clang-17'
-            cxx: 'clang++-17'
           - config: 'generic-cxx26'
             cc: 'clang-18'
             cxx: 'clang++-18'
+          - config: 'generic-cxx26'
+            cc: 'clang-19'
+            cxx: 'clang++-19'
     steps:
       - uses: actions/checkout at v4
       - name: ${{ matrix.config }}
@@ -179,8 +179,8 @@ jobs:
       - name: ${{ matrix.config }}
         run: libcxx/utils/ci/run-buildbot ${{ matrix.config }}
         env:
-          CC: clang-19
-          CXX: clang++-19
+          CC: clang-20
+          CXX: clang++-20
       - uses: actions/upload-artifact at 26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
         if: always()
         with:
diff --git a/libcxx/docs/ReleaseNotes/20.rst b/libcxx/docs/ReleaseNotes/20.rst
index aecac6692932b8..93bed91992084b 100644
--- a/libcxx/docs/ReleaseNotes/20.rst
+++ b/libcxx/docs/ReleaseNotes/20.rst
@@ -64,8 +64,8 @@ Deprecations and Removals
   removed in language modes prior to C++20. If you are using these features prior to C++20, you will need to
   update to ``-std=c++20``.
 
-- TODO: The relational operators for ``std::chrono::weekday`` will be removed entirely, and the
-  ``_LIBCPP_ENABLE_REMOVED_WEEKDAY_RELATIONAL_OPERATORS`` macro that was used to re-enable this extension will be
+- The relational operators for ``std::chrono::weekday`` are removed entirely, and the
+  ``_LIBCPP_ENABLE_REMOVED_WEEKDAY_RELATIONAL_OPERATORS`` macro that was used to re-enable this extension is
   ignored in LLVM 20.
 
 - The ``_LIBCPP_ENABLE_REMOVED_ALLOCATOR_CONST`` macro no longer has any effect. ``std::allocator<const T>`` is not
diff --git a/libcxx/docs/index.rst b/libcxx/docs/index.rst
index a9610cbb4db3a4..8d076928fe9c7f 100644
--- a/libcxx/docs/index.rst
+++ b/libcxx/docs/index.rst
@@ -130,7 +130,7 @@ velocity, libc++ drops support for older compilers as newer ones are released.
 ============ =============== ========================== =====================
 Compiler     Versions        Restrictions               Support policy
 ============ =============== ========================== =====================
-Clang        17, 18, 19-git                             latest two stable releases per `LLVM's release page <https://releases.llvm.org>`_ and the development version
+Clang        18, 19, 20-git                             latest two stable releases per `LLVM's release page <https://releases.llvm.org>`_ and the development version
 AppleClang   15                                         latest stable release per `Xcode's release page <https://developer.apple.com/documentation/xcode-release-notes>`_
 Open XL      17.1 (AIX)                                 latest stable release per `Open XL's documentation page <https://www.ibm.com/docs/en/openxl-c-and-cpp-aix>`_
 GCC          14              In C++11 or later only     latest stable release per `GCC's release page <https://gcc.gnu.org/releases.html>`_
diff --git a/libcxx/include/__chrono/weekday.h b/libcxx/include/__chrono/weekday.h
index 86c780cc718256..728cbb844633fe 100644
--- a/libcxx/include/__chrono/weekday.h
+++ b/libcxx/include/__chrono/weekday.h
@@ -79,25 +79,6 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr bool operator==(const weekday& __lhs, con
   return __lhs.c_encoding() == __rhs.c_encoding();
 }
 
-// TODO(LLVM 20): Remove the escape hatch
-#  ifdef _LIBCPP_ENABLE_REMOVED_WEEKDAY_RELATIONAL_OPERATORS
-_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator<(const weekday& __lhs, const weekday& __rhs) noexcept {
-  return __lhs.c_encoding() < __rhs.c_encoding();
-}
-
-_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator>(const weekday& __lhs, const weekday& __rhs) noexcept {
-  return __rhs < __lhs;
-}
-
-_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator<=(const weekday& __lhs, const weekday& __rhs) noexcept {
-  return !(__rhs < __lhs);
-}
-
-_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator>=(const weekday& __lhs, const weekday& __rhs) noexcept {
-  return !(__lhs < __rhs);
-}
-#  endif // _LIBCPP_ENABLE_REMOVED_WEEKDAY_RELATIONAL_OPERATORS
-
 _LIBCPP_HIDE_FROM_ABI inline constexpr weekday operator+(const weekday& __lhs, const days& __rhs) noexcept {
   auto const __mu = static_cast<long long>(__lhs.c_encoding()) + __rhs.count();
   auto const __yr = (__mu >= 0 ? __mu : __mu - 6) / 7;
diff --git a/libcxx/include/__configuration/compiler.h b/libcxx/include/__configuration/compiler.h
index 80ece22bb50bd6..cf459a0619b23c 100644
--- a/libcxx/include/__configuration/compiler.h
+++ b/libcxx/include/__configuration/compiler.h
@@ -33,8 +33,8 @@
 // Warn if a compiler version is used that is not supported anymore
 // LLVM RELEASE Update the minimum compiler versions
 #  if defined(_LIBCPP_CLANG_VER)
-#    if _LIBCPP_CLANG_VER < 1700
-#      warning "Libc++ only supports Clang 17 and later"
+#    if _LIBCPP_CLANG_VER < 1800
+#      warning "Libc++ only supports Clang 18 and later"
 #    endif
 #  elif defined(_LIBCPP_APPLE_CLANG_VER)
 #    if _LIBCPP_APPLE_CLANG_VER < 1500
diff --git a/libcxx/include/__type_traits/promote.h b/libcxx/include/__type_traits/promote.h
index 2b2a6843b91502..cccb6e0e04a00f 100644
--- a/libcxx/include/__type_traits/promote.h
+++ b/libcxx/include/__type_traits/promote.h
@@ -13,20 +13,12 @@
 #include <__type_traits/integral_constant.h>
 #include <__type_traits/is_arithmetic.h>
 
-#if defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER == 1700
-#  include <__type_traits/is_same.h>
-#  include <__utility/declval.h>
-#endif
-
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
 #endif
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-// TODO(LLVM-20): Remove this workaround
-#if !defined(_LIBCPP_CLANG_VER) || _LIBCPP_CLANG_VER != 1700
-
 template <class... _Args>
 class __promote {
   static_assert((is_arithmetic<_Args>::value && ...));
@@ -50,79 +42,6 @@ class __promote {
   using type = decltype((__test(_Args()) + ...));
 };
 
-#else
-
-template <class _Tp>
-struct __numeric_type {
-  static void __test(...);
-  static float __test(float);
-  static double __test(char);
-  static double __test(int);
-  static double __test(unsigned);
-  static double __test(long);
-  static double __test(unsigned long);
-  static double __test(long long);
-  static double __test(unsigned long long);
-#  ifndef _LIBCPP_HAS_NO_INT128
-  static double __test(__int128_t);
-  static double __test(__uint128_t);
-#  endif
-  static double __test(double);
-  static long double __test(long double);
-
-  typedef decltype(__test(std::declval<_Tp>())) type;
-  static const bool value = _IsNotSame<type, void>::value;
-};
-
-template <>
-struct __numeric_type<void> {
-  static const bool value = true;
-};
-
-template <class _A1,
-          class _A2 = void,
-          class _A3 = void,
-          bool      = __numeric_type<_A1>::value && __numeric_type<_A2>::value && __numeric_type<_A3>::value>
-class __promote_imp {
-public:
-  static const bool value = false;
-};
-
-template <class _A1, class _A2, class _A3>
-class __promote_imp<_A1, _A2, _A3, true> {
-private:
-  typedef typename __promote_imp<_A1>::type __type1;
-  typedef typename __promote_imp<_A2>::type __type2;
-  typedef typename __promote_imp<_A3>::type __type3;
-
-public:
-  typedef decltype(__type1() + __type2() + __type3()) type;
-  static const bool value = true;
-};
-
-template <class _A1, class _A2>
-class __promote_imp<_A1, _A2, void, true> {
-private:
-  typedef typename __promote_imp<_A1>::type __type1;
-  typedef typename __promote_imp<_A2>::type __type2;
-
-public:
-  typedef decltype(__type1() + __type2()) type;
-  static const bool value = true;
-};
-
-template <class _A1>
-class __promote_imp<_A1, void, void, true> {
-public:
-  typedef typename __numeric_type<_A1>::type type;
-  static const bool value = true;
-};
-
-template <class _A1, class _A2 = void, class _A3 = void>
-class __promote : public __promote_imp<_A1, _A2, _A3> {};
-
-#endif // !defined(_LIBCPP_CLANG_VER) || _LIBCPP_CLANG_VER >= 1700
-
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP___TYPE_TRAITS_PROMOTE_H
diff --git a/libcxx/test/libcxx/atomics/diagnose_invalid_memory_order.verify.cpp b/libcxx/test/libcxx/atomics/diagnose_invalid_memory_order.verify.cpp
index 2790916edaf698..fc83017c7d8227 100644
--- a/libcxx/test/libcxx/atomics/diagnose_invalid_memory_order.verify.cpp
+++ b/libcxx/test/libcxx/atomics/diagnose_invalid_memory_order.verify.cpp
@@ -9,7 +9,7 @@
 // This test fails with Clang <18 because diagnose_if doesn't emit all of the
 // diagnostics when -fdelayed-template-parsing is enabled, like it is in MSVC
 // mode.
-// XFAIL: msvc && clang-17
+// XFAIL: msvc
 
 // REQUIRES: diagnose-if-support
 
diff --git a/libcxx/test/libcxx/clang_tidy.gen.py b/libcxx/test/libcxx/clang_tidy.gen.py
index 5e84fbbb9913f3..4311bb49ac802b 100644
--- a/libcxx/test/libcxx/clang_tidy.gen.py
+++ b/libcxx/test/libcxx/clang_tidy.gen.py
@@ -18,7 +18,8 @@
 from libcxx.header_information import lit_header_restrictions, public_headers
 
 for header in public_headers:
-  print(f"""\
+    print(
+        f"""\
 //--- {header}.sh.cpp
 
 // REQUIRES: has-clang-tidy
@@ -26,9 +27,6 @@
 // The GCC compiler flags are not always compatible with clang-tidy.
 // UNSUPPORTED: gcc
 
-// Clang 17 has false positives.
-// UNSUPPORTED: clang-17
-
 {lit_header_restrictions.get(header, '')}
 
 // TODO: run clang-tidy with modules enabled once they are supported
@@ -36,4 +34,5 @@
 // RUN: %{{clang-tidy}} %s --warnings-as-errors=* -header-filter=.* --config-file=%{{libcxx-dir}}/.clang-tidy -- -Wweak-vtables %{{compile_flags}} -fno-modules
 
 #include <{header}>
-""")
+"""
+    )
diff --git a/libcxx/test/libcxx/gdb/gdb_pretty_printer_test.sh.cpp b/libcxx/test/libcxx/gdb/gdb_pretty_printer_test.sh.cpp
index 2c8534977febc7..4d0e925ea0fab4 100644
--- a/libcxx/test/libcxx/gdb/gdb_pretty_printer_test.sh.cpp
+++ b/libcxx/test/libcxx/gdb/gdb_pretty_printer_test.sh.cpp
@@ -12,7 +12,7 @@
 // UNSUPPORTED: c++03
 
 // TODO: Investigate these failures which break the CI.
-// UNSUPPORTED: clang-17, clang-18, clang-19
+// UNSUPPORTED: clang-18, clang-19
 
 // The Android libc++ tests are run on a non-Android host, connected to an
 // Android device over adb. gdb needs special support to make this work (e.g.
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.lazy.split/no_unique_address.compile.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.lazy.split/no_unique_address.compile.pass.cpp
index a0bfb7c4a246b5..33531e2389de0b 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.lazy.split/no_unique_address.compile.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.lazy.split/no_unique_address.compile.pass.cpp
@@ -7,7 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17
-// XFAIL: msvc && clang-17
+// XFAIL: msvc
 
 // class lazy_split_view {
 //   _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.split/no_unique_address.compile.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.split/no_unique_address.compile.pass.cpp
index 694cf1fd0d0e4c..192b52307e9683 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.split/no_unique_address.compile.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.split/no_unique_address.compile.pass.cpp
@@ -7,7 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17
-// XFAIL: msvc && clang-17
+// XFAIL: msvc
 
 // class split_view {
 //   _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
diff --git a/libcxx/test/libcxx/ranges/range.factories/range.istream.view/no_unique_address.compile.pass.cpp b/libcxx/test/libcxx/ranges/range.factories/range.istream.view/no_unique_address.compile.pass.cpp
index a77c4e4d1bcdb0..64454d81a03803 100644
--- a/libcxx/test/libcxx/ranges/range.factories/range.istream.view/no_unique_address.compile.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.factories/range.istream.view/no_unique_address.compile.pass.cpp
@@ -8,7 +8,7 @@
 
 // UNSUPPORTED: no-localization
 // UNSUPPORTED: c++03, c++11, c++14, c++17
-// XFAIL: msvc && clang-17
+// XFAIL: msvc
 
 // Test the libc++ extension that the value stored in `std::ranges::istream_view` has been marked
 // as _LIBCPP_NO_UNIQUE_ADDRESS
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp
index 61374094b7adfb..5fbc115d670bfc 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp
@@ -6,10 +6,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-// Clang-18 fixed some spurious clang diagnostics. Once clang-18 is the
-// minimum required version these obsolete tests can be removed.
-// TODO(LLVM-20) remove spurious clang diagnostic tests.
-
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
 
 // With clang-cl, some warnings have a 'which is a Microsoft extension' suffix
@@ -59,12 +55,12 @@ void test() {
   {
     std::expected<int, int> e;
     e.transform_error(return_unexpected<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
     // expected-error-re@*:* {{static assertion failed {{.*}}[expected.object.general] A program that instantiates the definition of template expected<T, E> for {{.*}} is ill-formed.}}
     // expected-error-re@*:* 0-1 {{union member {{.*}} has reference type {{.*}}}}
 
     e.transform_error(return_no_object<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
     // expected-error-re@*:* {{static assertion failed {{.*}}[expected.object.general] A program that instantiates the definition of template expected<T, E> for {{.*}} is ill-formed.}}
     // expected-warning-re@*:* 0-1 {{union member {{.*}} has reference type {{.*}}, which is a Microsoft extension}}
   }
@@ -73,27 +69,27 @@ void test() {
   {
     const std::expected<int, int> e;
     e.transform_error(return_unexpected<const int &>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* 0-2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* 2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
     e.transform_error(return_no_object<const int &>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* 0-2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* 2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
   }
 
   // Test && overload
   {
     std::expected<int, int> e;
     std::move(e).transform_error(return_unexpected<int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* 0-2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* 2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
     std::move(e).transform_error(return_no_object<int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* 0-2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* 2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
   }
 
   // Test const&& overload
   {
     const std::expected<int, int> e;
     std::move(e).transform_error(return_unexpected<const int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* 0-2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* 2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
     std::move(e).transform_error(return_no_object<const int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* 0-2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* 2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
   }
 }
 // clang-format on
diff --git a/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp
index 16233cd90d2199..dc553a1fda463f 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp
@@ -6,10 +6,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-// Clang-18 fixed some spurious clang diagnostics. Once clang-18 is the
-// minumum required version these obsolete tests can be removed.
-// TODO(LLVM-20) remove spurious clang diagnostic tests.
-
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
 
 // With clang-cl, some warnings have a 'which is a Microsoft extension' suffix
@@ -60,13 +56,13 @@ void test() {
   {
     std::expected<void, int> e;
     e.transform_error(return_unexpected<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
     // expected-error-re@*:* {{static assertion failed {{.*}}A program that instantiates expected<T, E> with a E that is not a valid argument for unexpected<E> is ill-formed}}
-    // expected-error-re@*:* 0-1 {{call to deleted constructor of {{.*}}}}
+    // expected-error-re@*:* {{call to deleted constructor of {{.*}}}}
     // expected-error-re@*:* 0-1 {{union member {{.*}} has reference type {{.*}}}}
 
     e.transform_error(return_no_object<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
     // expected-error-re@*:* {{static assertion failed {{.*}}A program that instantiates expected<T, E> with a E that is not a valid argument for unexpected<E> is ill-formed}}
     // expected-warning-re@*:* 0-1 {{union member {{.*}} has reference type {{.*}}, which is a Microsoft extension}}
   }
@@ -75,28 +71,28 @@ void test() {
   {
     const std::expected<void, int> e;
     e.transform_error(return_unexpected<const int &>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
     e.transform_error(return_no_object<const int &>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
-    // expected-error-re@*:* 0-1 {{call to deleted constructor of {{.*}}}}
+    // expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* {{call to deleted constructor of {{.*}}}}
   }
 
   // Test && overload
   {
     std::expected<void, int> e;
     std::move(e).transform_error(return_unexpected<int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
     std::move(e).transform_error(return_no_object<int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
   }
 
   // Test const&& overload
   {
     const std::expected<void, int> e;
     std::move(e).transform_error(return_unexpected<const int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
     std::move(e).transform_error(return_no_object<const int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
   }
 }
 // clang-format on
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
index 40a475ec38b723..6c3294bd549b67 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
@@ -10,7 +10,7 @@
 
 // Older versions of clang have a bug with atomic builtins affecting double and long double.
 // Fixed by 5fdd0948.
-// XFAIL: target=powerpc-ibm-{{.*}} && (clang-17 || clang-18)
+// XFAIL: target=powerpc-ibm-{{.*}} && clang-18
 
 // https://github.com/llvm/llvm-project/issues/72893
 // XFAIL: target={{x86_64-.*}} && tsan
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
index 9e798a2a519ff0..3c9545e32df049 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
@@ -10,7 +10,7 @@
 
 // Older versions of clang have a bug with atomic builtins affecting double and long double.
 // Fixed by 5fdd0948.
-// XFAIL: target=powerpc-ibm-{{.*}} && (clang-17 || clang-18)
+// XFAIL: target=powerpc-ibm-{{.*}} && clang-18
 
 // https://github.com/llvm/llvm-project/issues/72893
 // XFAIL: target={{x86_64-.*}} && tsan
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
index 732bd4d7e5dc2b..f16bf1261656c5 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
@@ -10,7 +10,7 @@
 
 // Older versions of clang have a bug with atomic builtins affecting double and long double.
 // Fixed by 5fdd0948.
-// XFAIL: target=powerpc-ibm-{{.*}} && (clang-17 || clang-18)
+// XFAIL: target=powerpc-ibm-{{.*}} && clang-18
 
 // floating-point-type operator-=(floating-point-type) volatile noexcept;
 // floating-point-type operator-=(floating-point-type) noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
index 1821aca42c7988..3605648be36da0 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
@@ -10,7 +10,7 @@
 
 // Older versions of clang have a bug with atomic builtins affecting double and long double.
 // Fixed by 5fdd0948.
-// XFAIL: target=powerpc-ibm-{{.*}} && (clang-17 || clang-18)
+// XFAIL: target=powerpc-ibm-{{.*}} && clang-18
 
 // floating-point-type operator+=(floating-point-type) volatile noexcept;
 // floating-point-type operator+=(floating-point-type) noexcept;
diff --git a/libcxx/test/std/experimental/simd/simd.class/simd_copy.pass.cpp b/libcxx/test/std/experimental/simd/simd.class/simd_copy.pass.cpp
index 7d91ca0eada1d3..722e6f770b05bd 100644
--- a/libcxx/test/std/experimental/simd/simd.class/simd_copy.pass.cpp
+++ b/libcxx/test/std/experimental/simd/simd.class/simd_copy.pass.cpp
@@ -10,7 +10,7 @@
 
 // Older versions of clang may encounter a backend error (see 0295c2ad):
 //   Pass-by-value arguments with alignment greater than register width are not supported.
-// XFAIL: target=powerpc{{.*}}-ibm-{{.*}} && (clang-17 || clang-18)
+// XFAIL: target=powerpc{{.*}}-ibm-{{.*}} clang-18
 
 // <experimental/simd>
 //
diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array14.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array14.pass.cpp
index 85b641322d99e3..e02e522c05c531 100644
--- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array14.pass.cpp
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array14.pass.cpp
@@ -9,7 +9,7 @@
 // test sized operator delete[] replacement.
 
 // These compiler versions don't enable sized deallocation by default.
-// UNSUPPORTED: clang-17, clang-18
+// UNSUPPORTED: clang-18
 
 // UNSUPPORTED: sanitizer-new-delete, c++03, c++11
 // XFAIL: apple-clang
diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete14.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete14.pass.cpp
index ae614a1432f7db..da1fecadee8488 100644
--- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete14.pass.cpp
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete14.pass.cpp
@@ -9,7 +9,7 @@
 // Test sized operator delete replacement.
 
 // These compiler versions do not enable sized deallocation by default.
-// UNSUPPORTED: clang-17, clang-18
+// UNSUPPORTED: clang-18
 
 // UNSUPPORTED: sanitizer-new-delete, c++03, c++11
 // XFAIL: apple-clang
diff --git a/libcxx/test/std/numerics/c.math/signbit.pass.cpp b/libcxx/test/std/numerics/c.math/signbit.pass.cpp
index a8a566f7de6434..6dbc0b1413f9da 100644
--- a/libcxx/test/std/numerics/c.math/signbit.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/signbit.pass.cpp
@@ -12,7 +12,7 @@
 // UNSUPPORTED: windows
 
 // These compilers don't support constexpr `__builtin_signbit` yet.
-// UNSUPPORTED: clang-17, clang-18, clang-19, apple-clang-15, apple-clang-16
+// UNSUPPORTED: clang-18, clang-19, apple-clang-15, apple-clang-16
 
 #include <cassert>
 #include <cmath>
diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/add_sat.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/add_sat.pass.cpp
index 036bf53e36dcd4..8288378ab769e1 100644
--- a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/add_sat.pass.cpp
+++ b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/add_sat.pass.cpp
@@ -25,8 +25,7 @@ constexpr bool test_signed() {
   constexpr auto minVal = std::numeric_limits<IntegerT>::min();
   constexpr auto maxVal = std::numeric_limits<IntegerT>::max();
 
-  // TODO(LLVM-20) remove [[maybe_unused]]  since all supported compilers support "Placeholder variables with no name"
-  [[maybe_unused]] std::same_as<IntegerT> decltype(auto) _ = std::add_sat(minVal, maxVal);
+  std::same_as<IntegerT> decltype(auto) _ = std::add_sat(minVal, maxVal);
 
   static_assert(noexcept(std::add_sat(minVal, maxVal)));
 
@@ -97,8 +96,7 @@ constexpr bool test_unsigned() {
   constexpr auto minVal = std::numeric_limits<IntegerT>::min();
   constexpr auto maxVal = std::numeric_limits<IntegerT>::max();
 
-  // TODO(LLVM-20) remove [[maybe_unused]]  since all supported compilers support "Placeholder variables with no name"
-  [[maybe_unused]] std::same_as<IntegerT> decltype(auto) _ = std::add_sat(minVal, maxVal);
+  std::same_as<IntegerT> decltype(auto) _ = std::add_sat(minVal, maxVal);
 
   static_assert(noexcept(std::add_sat(minVal, maxVal)));
 
diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/div_sat.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/div_sat.pass.cpp
index b1cace74d88288..fa9841b24d27ac 100644
--- a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/div_sat.pass.cpp
+++ b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/div_sat.pass.cpp
@@ -26,8 +26,7 @@ constexpr bool test_signed() {
   constexpr auto minVal = std::numeric_limits<IntegerT>::min();
   constexpr auto maxVal = std::numeric_limits<IntegerT>::max();
 
-  // TODO(LLVM-20) remove [[maybe_unused]] and `{}` scope since all supported compilers support "Placeholder variables with no name"
-  [[maybe_unused]] std::same_as<IntegerT> decltype(auto) _ = std::div_sat(minVal, maxVal);
+  std::same_as<IntegerT> decltype(auto) _ = std::div_sat(minVal, maxVal);
 
   static_assert(noexcept(std::div_sat(minVal, maxVal)));
 
@@ -89,8 +88,7 @@ constexpr bool test_unsigned() {
   constexpr auto minVal = std::numeric_limits<IntegerT>::min();
   constexpr auto maxVal = std::numeric_limits<IntegerT>::max();
 
-  // TODO(LLVM-20) remove [[maybe_unused]] since all supported compilers support "Placeholder variables with no name"
-  [[maybe_unused]] std::same_as<IntegerT> decltype(auto) _ = std::div_sat(minVal, maxVal);
+  std::same_as<IntegerT> decltype(auto) _ = std::div_sat(minVal, maxVal);
   static_assert(noexcept(std::div_sat(minVal, maxVal)));
 
   // clang-format off
diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/mul_sat.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/mul_sat.pass.cpp
index 2c8eec57e12042..060eb52103a024 100644
--- a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/mul_sat.pass.cpp
+++ b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/mul_sat.pass.cpp
@@ -26,8 +26,7 @@ constexpr bool test_signed() {
   constexpr auto minVal = std::numeric_limits<IntegerT>::min();
   constexpr auto maxVal = std::numeric_limits<IntegerT>::max();
 
-  // TODO(LLVM-20) remove [[maybe_unused]] since all supported compilers support "Placeholder variables with no name"
-  [[maybe_unused]] std::same_as<IntegerT> decltype(auto) _ = std::mul_sat(minVal, maxVal);
+  std::same_as<IntegerT> decltype(auto) _ = std::mul_sat(minVal, maxVal);
 
   static_assert(noexcept(std::mul_sat(minVal, maxVal)));
 
@@ -103,8 +102,7 @@ constexpr bool test_unsigned() {
   constexpr auto minVal = std::numeric_limits<IntegerT>::min();
   constexpr auto maxVal = std::numeric_limits<IntegerT>::max();
 
-  // TODO(LLVM-20) remove [[maybe_unused]] since all supported compilers support "Placeholder variables with no name"
-  [[maybe_unused]] std::same_as<IntegerT> decltype(auto) _ = std::mul_sat(minVal, maxVal);
+  std::same_as<IntegerT> decltype(auto) _ = std::mul_sat(minVal, maxVal);
 
   static_assert(noexcept(std::mul_sat(minVal, maxVal)));
 
diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturate_cast.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturate_cast.pass.cpp
index cbca37e3a66139..7c3e570c407575 100644
--- a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturate_cast.pass.cpp
+++ b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturate_cast.pass.cpp
@@ -72,314 +72,312 @@ constexpr bool test() {
 
   // signed char
 
-  // TODO(LLVM-20) remove [[maybe_unused]] and `{}` scope since all supported compilers support "Placeholder variables with no name",
-  // here and below...
-  { [[maybe_unused]] std::same_as<signed char> decltype(auto) _ = std::saturate_cast<signed char>(SCHAR_MAX); }
+  std::same_as<signed char> decltype(auto) _ = std::saturate_cast<signed char>(SCHAR_MAX);
   assert(std::saturate_cast<signed char>(SCHAR_MIN)  == SCHAR_MIN);
   assert(std::saturate_cast<signed char>(      O_C)  ==       O_C);
   assert(std::saturate_cast<signed char>(SCHAR_MAX)  == SCHAR_MAX);
 
-  { [[maybe_unused]] std::same_as<signed char> decltype(auto) _ = std::saturate_cast<signed char>(UCHAR_MAX); }
+  std::same_as<signed char> decltype(auto) _ = std::saturate_cast<signed char>(UCHAR_MAX);
   assert(std::saturate_cast<signed char>(     O_UC)  ==       O_C);
   assert(std::saturate_cast<signed char>(UCHAR_MAX)  == SCHAR_MAX);
 
-  { [[maybe_unused]] std::same_as<signed char> decltype(auto) _ = std::saturate_cast<signed char>(sBigMax); }
+  std::same_as<signed char> decltype(auto) _ = std::saturate_cast<signed char>(sBigMax);
   assert(std::saturate_cast<signed char>(sBigMin)    == SCHAR_MIN); // saturated
   assert(std::saturate_cast<signed char>(  sZero)    ==       O_C);
   assert(std::saturate_cast<signed char>(sBigMax)    == SCHAR_MAX); // saturated
 
-  { [[maybe_unused]] std::same_as<signed char> decltype(auto) _ = std::saturate_cast<signed char>(uBigMax); }
+  std::same_as<signed char> decltype(auto) _ = std::saturate_cast<signed char>(uBigMax);
   assert(std::saturate_cast<signed char>(  uZero)    ==       O_C);
   assert(std::saturate_cast<signed char>(uBigMax)    == SCHAR_MAX); // saturated
 
   // short
 
-  { [[maybe_unused]] std::same_as<signed short int> decltype(auto) _ = std::saturate_cast<signed short int>(SCHAR_MAX); }
+  std::same_as<signed short int> decltype(auto) _ = std::saturate_cast<signed short int>(SCHAR_MAX);
   assert(std::saturate_cast<signed short int>(SCHAR_MIN) == static_cast<signed short int>(SCHAR_MIN));
   assert(std::saturate_cast<signed short int>(      O_C) == O_S);
   assert(std::saturate_cast<signed short int>(SCHAR_MAX) == static_cast<signed short int>(SCHAR_MAX));
 
-  { [[maybe_unused]] std::same_as<signed short int> decltype(auto) _ = std::saturate_cast<signed short int>(UCHAR_MAX); }
+  std::same_as<signed short int> decltype(auto) _ = std::saturate_cast<signed short int>(UCHAR_MAX);
   assert(std::saturate_cast<signed short int>(     O_UC) == O_S);
   assert(std::saturate_cast<signed short int>(UCHAR_MAX) == static_cast<signed short int>(UCHAR_MAX));
 
-  { [[maybe_unused]] std::same_as<signed short int> decltype(auto) _ = std::saturate_cast<signed short int>(SHRT_MAX); }
+  std::same_as<signed short int> decltype(auto) _ = std::saturate_cast<signed short int>(SHRT_MAX);
   assert(std::saturate_cast<signed short int>( SHRT_MIN) == SHRT_MIN);
   assert(std::saturate_cast<signed short int>(      O_S) == O_S);
   assert(std::saturate_cast<signed short int>( SHRT_MAX) == SHRT_MAX);
 
-  { [[maybe_unused]] std::same_as<signed short int> decltype(auto) _ = std::saturate_cast<signed short int>(USHRT_MAX); }
+  std::same_as<signed short int> decltype(auto) _ = std::saturate_cast<signed short int>(USHRT_MAX);
   assert(std::saturate_cast<signed short int>(     O_US) == O_S);
   assert(std::saturate_cast<signed short int>(USHRT_MAX) == SHRT_MAX); // saturated
 
-  { [[maybe_unused]] std::same_as<signed short int> decltype(auto) _ = std::saturate_cast<signed short int>(sBigMax); }
+  std::same_as<signed short int> decltype(auto) _ = std::saturate_cast<signed short int>(sBigMax);
   assert(std::saturate_cast<signed short int>( sBigMin)   == SHRT_MIN); // saturated
   assert(std::saturate_cast<signed short int>(   sZero)   == O_S);
   assert(std::saturate_cast<signed short int>( sBigMax)   == SHRT_MAX); // saturated
 
-  { [[maybe_unused]] std::same_as<signed short int> decltype(auto) _ = std::saturate_cast<signed short int>(uBigMax); }
+  std::same_as<signed short int> decltype(auto) _ = std::saturate_cast<signed short int>(uBigMax);
   assert(std::saturate_cast<signed short int>(   uZero)   == O_S);
   assert(std::saturate_cast<signed short int>( uBigMax)   == SHRT_MAX); // saturated
 
   // int
 
-  { [[maybe_unused]] std::same_as<signed int> decltype(auto) _ = std::saturate_cast<signed int>(SCHAR_MAX); }
+  std::same_as<signed int> decltype(auto) _ = std::saturate_cast<signed int>(SCHAR_MAX);
   assert(std::saturate_cast<signed int>(SCHAR_MIN) == static_cast<signed int>(SCHAR_MIN));
   assert(std::saturate_cast<signed int>(      O_C) == 0);
   assert(std::saturate_cast<signed int>(SCHAR_MAX) == static_cast<signed int>(SCHAR_MAX));
 
-  { [[maybe_unused]] std::same_as<signed int> decltype(auto) _ = std::saturate_cast<signed int>(UCHAR_MAX); }
+  std::same_as<signed int> decltype(auto) _ = std::saturate_cast<signed int>(UCHAR_MAX);
   assert(std::saturate_cast<signed int>(     O_UC) == 0);
   assert(std::saturate_cast<signed int>(UCHAR_MAX) == static_cast<signed int>(UCHAR_MAX));
 
-  { [[maybe_unused]] std::same_as<signed int> decltype(auto) _ = std::saturate_cast<signed int>(INT_MAX); }
+  std::same_as<signed int> decltype(auto) _ = std::saturate_cast<signed int>(INT_MAX);
   assert(std::saturate_cast<signed int>(  INT_MIN) == INT_MIN);
   assert(std::saturate_cast<signed int>(        0) == 0);
   assert(std::saturate_cast<signed int>(  INT_MAX) == INT_MAX);
 
-  { [[maybe_unused]] std::same_as<signed int> decltype(auto) _ = std::saturate_cast<signed int>(UINT_MAX); }
+  std::same_as<signed int> decltype(auto) _ = std::saturate_cast<signed int>(UINT_MAX);
   assert(std::saturate_cast<signed int>(       0)  == 0);
   assert(std::saturate_cast<signed int>(UINT_MAX)  == INT_MAX); // saturated
 
-  { [[maybe_unused]] std::same_as<signed int> decltype(auto) _ = std::saturate_cast<signed int>(sBigMax); }
+  std::same_as<signed int> decltype(auto) _ = std::saturate_cast<signed int>(sBigMax);
   assert(std::saturate_cast<signed int>( sBigMin)  == INT_MIN); // saturated
   assert(std::saturate_cast<signed int>(   sZero)  == 0);
   assert(std::saturate_cast<signed int>( sBigMax)  == INT_MAX); // saturated
 
-  { [[maybe_unused]] std::same_as<signed int> decltype(auto) _ = std::saturate_cast<signed int>(uBigMax); }
+  std::same_as<signed int> decltype(auto) _ = std::saturate_cast<signed int>(uBigMax);
   assert(std::saturate_cast<signed int>( uZero)    == 0);
   assert(std::saturate_cast<signed int>( uBigMax)  == INT_MAX); // saturated
 
   // long
 
-  { [[maybe_unused]] std::same_as<signed long int> decltype(auto) _ = std::saturate_cast<signed long int>(SCHAR_MAX); }
+  std::same_as<signed long int> decltype(auto) _ = std::saturate_cast<signed long int>(SCHAR_MAX);
   assert(std::saturate_cast<signed long int>(SCHAR_MIN) == static_cast<signed long int>(SCHAR_MIN));
   assert(std::saturate_cast<signed long int>(      O_C) == 0L);
   assert(std::saturate_cast<signed long int>(SCHAR_MAX) == static_cast<signed long int>(SCHAR_MAX));
 
-  { [[maybe_unused]] std::same_as<signed long int> decltype(auto) _ = std::saturate_cast<signed long int>(UCHAR_MAX); }
+  std::same_as<signed long int> decltype(auto) _ = std::saturate_cast<signed long int>(UCHAR_MAX);
   assert(std::saturate_cast<signed long int>(     O_UC) == 0L);
   assert(std::saturate_cast<signed long int>(UCHAR_MAX) == static_cast<signed long int>(UCHAR_MAX));
 
-  { [[maybe_unused]] std::same_as<signed long int> decltype(auto) _ = std::saturate_cast<signed long int>(LONG_MAX); }
+  std::same_as<signed long int> decltype(auto) _ = std::saturate_cast<signed long int>(LONG_MAX);
   assert(std::saturate_cast<signed long int>( LONG_MIN) == LONG_MIN);
   assert(std::saturate_cast<signed long int>(       0L) == 0L);
   assert(std::saturate_cast<signed long int>( LONG_MAX) == LONG_MAX);
 
-  { [[maybe_unused]] std::same_as<signed long int> decltype(auto) _ = std::saturate_cast<signed long int>(ULONG_MAX); }
+  std::same_as<signed long int> decltype(auto) _ = std::saturate_cast<signed long int>(ULONG_MAX);
   assert(std::saturate_cast<signed long int>(      0UL) == 0L);
   assert(std::saturate_cast<signed long int>(ULONG_MAX) == LONG_MAX); // saturated
 
-  { [[maybe_unused]] std::same_as<signed long int> decltype(auto) _ = std::saturate_cast<signed long int>(sBigMax); }
+  std::same_as<signed long int> decltype(auto) _ = std::saturate_cast<signed long int>(sBigMax);
   assert(std::saturate_cast<signed long int>(  sBigMin) == LONG_MIN); // saturated
   assert(std::saturate_cast<signed long int>(    sZero) == 0L);
   assert(std::saturate_cast<signed long int>(  sBigMax) == LONG_MAX); // saturated
 
-  { [[maybe_unused]] std::same_as<signed long int> decltype(auto) _ = std::saturate_cast<signed long int>(uBigMax); }
+  std::same_as<signed long int> decltype(auto) _ = std::saturate_cast<signed long int>(uBigMax);
   assert(std::saturate_cast<signed long int>(    uZero) == 0L);
   assert(std::saturate_cast<signed long int>(  uBigMax) == LONG_MAX); // saturated
 
   // long long
 
-  { [[maybe_unused]] std::same_as<signed long long int> decltype(auto) _ = std::saturate_cast<signed long long int>(SCHAR_MAX); }
+  std::same_as<signed long long int> decltype(auto) _ = std::saturate_cast<signed long long int>(SCHAR_MAX);
   assert(std::saturate_cast<signed long long int>(SCHAR_MIN) == static_cast<signed long long int>(SCHAR_MIN));
   assert(std::saturate_cast<signed long long int>(      0LL) == 0LL);
   assert(std::saturate_cast<signed long long int>(SCHAR_MAX) == static_cast<signed long long int>(SCHAR_MAX));
 
-  { [[maybe_unused]]   std::same_as<signed long long int> decltype(auto) _ = std::saturate_cast<signed long long int>(UCHAR_MAX); }
+    std::same_as<signed long long int> decltype(auto) _ = std::saturate_cast<signed long long int>(UCHAR_MAX);
   assert(std::saturate_cast<signed long long int>(     O_UC) == 0LL);
   assert(std::saturate_cast<signed long long int>(UCHAR_MAX) == static_cast<signed long long int>(UCHAR_MAX));
 
-  { [[maybe_unused]] std::same_as<signed long long int> decltype(auto) _ = std::saturate_cast<signed long long int>(LLONG_MIN); }
+  std::same_as<signed long long int> decltype(auto) _ = std::saturate_cast<signed long long int>(LLONG_MIN);
   assert(std::saturate_cast<signed long long int>(LLONG_MIN) == LLONG_MIN);
   assert(std::saturate_cast<signed long long int>(      0LL) == 0LL);
   assert(std::saturate_cast<signed long long int>(LLONG_MAX) == LLONG_MAX);
 
-  { [[maybe_unused]] std::same_as<signed long long int> decltype(auto) _ = std::saturate_cast<signed long long int>(ULLONG_MAX); }
+  std::same_as<signed long long int> decltype(auto) _ = std::saturate_cast<signed long long int>(ULLONG_MAX);
   assert(std::saturate_cast<signed long long int>(      0ULL) == 0LL);
   assert(std::saturate_cast<signed long long int>(ULLONG_MAX) == LLONG_MAX); // saturated
 
 #ifndef TEST_HAS_NO_INT128
-  { [[maybe_unused]] std::same_as<signed long long int> decltype(auto) _ = std::saturate_cast<signed long long int>(sBigMax); }
+  std::same_as<signed long long int> decltype(auto) _ = std::saturate_cast<signed long long int>(sBigMax);
   assert(std::saturate_cast<signed long long int>(   sBigMin) == LLONG_MIN); // (128-bit) saturated
   assert(std::saturate_cast<signed long long int>(     sZero) == 0LL);
   assert(std::saturate_cast<signed long long int>(   sBigMax) == LLONG_MAX); // (128-bit) saturated
 
-  { [[maybe_unused]] std::same_as<signed long long int> decltype(auto) _ = std::saturate_cast<signed long long int>(uBigMax); }
+  std::same_as<signed long long int> decltype(auto) _ = std::saturate_cast<signed long long int>(uBigMax);
   assert(std::saturate_cast<signed long long int>(     uZero) == 0LL);
   assert(std::saturate_cast<signed long long int>(   uBigMax) == LLONG_MAX); // (128-bit) saturated
 
-  { [[maybe_unused]] std::same_as<__int128_t> decltype(auto) _ = std::saturate_cast<__int128_t>(SCHAR_MAX); }
+  std::same_as<__int128_t> decltype(auto) _ = std::saturate_cast<__int128_t>(SCHAR_MAX);
   assert(std::saturate_cast<__int128_t>(SCHAR_MIN) == static_cast<__int128_t>(SCHAR_MIN));
   assert(std::saturate_cast<__int128_t>(      O_C) == sZero);
   assert(std::saturate_cast<__int128_t>(SCHAR_MAX) == static_cast<__int128_t>(SCHAR_MAX));
 
-  { [[maybe_unused]] std::same_as<__int128_t> decltype(auto) _ = std::saturate_cast<__int128_t>(UCHAR_MAX); }
+  std::same_as<__int128_t> decltype(auto) _ = std::saturate_cast<__int128_t>(UCHAR_MAX);
   assert(std::saturate_cast<__int128_t>(     O_UC) == sZero);
   assert(std::saturate_cast<__int128_t>(UCHAR_MAX) == static_cast<__int128_t>(UCHAR_MAX));
 
-  { [[maybe_unused]] std::same_as<__int128_t> decltype(auto) _ = std::saturate_cast<__int128_t>(sBigMax); }
+  std::same_as<__int128_t> decltype(auto) _ = std::saturate_cast<__int128_t>(sBigMax);
   assert(std::saturate_cast<__int128_t>(  sBigMin) == sBigMin);
   assert(std::saturate_cast<__int128_t>(    sZero) == sZero);
   assert(std::saturate_cast<__int128_t>(  sBigMax) == sBigMax);
 
-  { [[maybe_unused]] std::same_as<__int128_t> decltype(auto) _ = std::saturate_cast<__int128_t>(uBigMax); }
+  std::same_as<__int128_t> decltype(auto) _ = std::saturate_cast<__int128_t>(uBigMax);
   assert(std::saturate_cast<__int128_t>(    uZero) == sZero);
   assert(std::saturate_cast<__int128_t>(  uBigMax) == sBigMax); // saturated
 #endif
 
   // unsigned char
 
-  { [[maybe_unused]] std::same_as<unsigned char> decltype(auto) _ = std::saturate_cast<unsigned char>(SCHAR_MAX); }
+  std::same_as<unsigned char> decltype(auto) _ = std::saturate_cast<unsigned char>(SCHAR_MAX);
   assert(std::saturate_cast<unsigned char>(SCHAR_MIN) == O_UC);
   assert(std::saturate_cast<unsigned char>(      O_C) == O_UC);
   assert(std::saturate_cast<unsigned char>(SCHAR_MAX) == static_cast<unsigned char>(SCHAR_MAX));
 
-  { [[maybe_unused]] std::same_as<unsigned char> decltype(auto) _ = std::saturate_cast<unsigned char>(UCHAR_MAX); }
+  std::same_as<unsigned char> decltype(auto) _ = std::saturate_cast<unsigned char>(UCHAR_MAX);
   assert(std::saturate_cast<unsigned char>(     O_UC) == O_UC);
   assert(std::saturate_cast<unsigned char>(UCHAR_MAX) == UCHAR_MAX);
 
-  { [[maybe_unused]] std::same_as<unsigned char> decltype(auto) _ = std::saturate_cast<unsigned char>(sBigMax); }
+  std::same_as<unsigned char> decltype(auto) _ = std::saturate_cast<unsigned char>(sBigMax);
   assert(std::saturate_cast<unsigned char>(  sBigMin) == O_UC);      // saturated
   assert(std::saturate_cast<unsigned char>(    sZero) == O_UC);
   assert(std::saturate_cast<unsigned char>(  sBigMax) == UCHAR_MAX); // saturated
 
-  { [[maybe_unused]] std::same_as<unsigned char> decltype(auto) _ = std::saturate_cast<unsigned char>(uBigMax); }
+  std::same_as<unsigned char> decltype(auto) _ = std::saturate_cast<unsigned char>(uBigMax);
   assert(std::saturate_cast<unsigned char>(    uZero) == O_UC);
   assert(std::saturate_cast<unsigned char>(  uBigMax) == UCHAR_MAX); // saturated
 
   // unsigned short
 
-  { [[maybe_unused]] std::same_as<unsigned short int> decltype(auto) _ = std::saturate_cast<unsigned short int>(SCHAR_MAX); }
+  std::same_as<unsigned short int> decltype(auto) _ = std::saturate_cast<unsigned short int>(SCHAR_MAX);
   assert(std::saturate_cast<unsigned short int>(SCHAR_MIN) == O_US);
   assert(std::saturate_cast<unsigned short int>(      O_C) == O_US);
   assert(std::saturate_cast<unsigned short int>(SCHAR_MAX) == static_cast<unsigned short int>(SCHAR_MAX));
 
-  { [[maybe_unused]] std::same_as<unsigned short int> decltype(auto) _ = std::saturate_cast<unsigned short int>(UCHAR_MAX); }
+  std::same_as<unsigned short int> decltype(auto) _ = std::saturate_cast<unsigned short int>(UCHAR_MAX);
   assert(std::saturate_cast<unsigned short int>(     O_UC) == O_US);
   assert(std::saturate_cast<unsigned short int>(UCHAR_MAX) == static_cast<unsigned short int>(UCHAR_MAX));
 
-  { [[maybe_unused]] std::same_as<unsigned short int> decltype(auto) _ = std::saturate_cast<unsigned short int>(SCHAR_MIN); }
+  std::same_as<unsigned short int> decltype(auto) _ = std::saturate_cast<unsigned short int>(SCHAR_MIN);
   assert(std::saturate_cast<unsigned short int>( SHRT_MIN) == O_US);
   assert(std::saturate_cast<unsigned short int>(      O_S) == O_US);
   assert(std::saturate_cast<unsigned short int>( SHRT_MAX) == static_cast<unsigned short int>(SHRT_MAX));
 
-  { [[maybe_unused]] std::same_as<unsigned short int> decltype(auto) _ = std::saturate_cast<unsigned short int>(UCHAR_MAX); }
+  std::same_as<unsigned short int> decltype(auto) _ = std::saturate_cast<unsigned short int>(UCHAR_MAX);
   assert(std::saturate_cast<unsigned short int>(     O_US) == O_US);
   assert(std::saturate_cast<unsigned short int>(USHRT_MAX) == USHRT_MAX);
 
-  { [[maybe_unused]] std::same_as<unsigned short int> decltype(auto) _ = std::saturate_cast<unsigned short int>(sBigMax); }
+  std::same_as<unsigned short int> decltype(auto) _ = std::saturate_cast<unsigned short int>(sBigMax);
   assert(std::saturate_cast<unsigned short int>(  sBigMin) == O_US);      // saturated
   assert(std::saturate_cast<unsigned short int>(    sZero) == O_US);
   assert(std::saturate_cast<unsigned short int>(  sBigMax) == USHRT_MAX); // saturated
 
-  { [[maybe_unused]] std::same_as<unsigned short int> decltype(auto) _ = std::saturate_cast<unsigned short int>(uBigMax); }
+  std::same_as<unsigned short int> decltype(auto) _ = std::saturate_cast<unsigned short int>(uBigMax);
   assert(std::saturate_cast<unsigned short int>(    uZero) == O_US);
   assert(std::saturate_cast<unsigned short int>(  uBigMax) == USHRT_MAX); // saturated
 
   // unsigned int
 
-  { [[maybe_unused]] std::same_as<unsigned int> decltype(auto) _ = std::saturate_cast<unsigned int>(SCHAR_MAX); }
+  std::same_as<unsigned int> decltype(auto) _ = std::saturate_cast<unsigned int>(SCHAR_MAX);
   assert(std::saturate_cast<unsigned int>(SCHAR_MIN) == O_US);
   assert(std::saturate_cast<unsigned int>(     O_UC) == 0U);
   assert(std::saturate_cast<unsigned int>(SCHAR_MAX) == static_cast<unsigned int>(SCHAR_MAX));
 
-  { [[maybe_unused]] std::same_as<unsigned int> decltype(auto) _ = std::saturate_cast<unsigned int>(UCHAR_MAX); }
+  std::same_as<unsigned int> decltype(auto) _ = std::saturate_cast<unsigned int>(UCHAR_MAX);
   assert(std::saturate_cast<unsigned int>(     O_UC) == 0U);
   assert(std::saturate_cast<unsigned int>(UCHAR_MAX) == static_cast<unsigned int>(UCHAR_MAX));
 
-  { [[maybe_unused]] std::same_as<unsigned int> decltype(auto) _ = std::saturate_cast<unsigned int>(INT_MAX); }
+  std::same_as<unsigned int> decltype(auto) _ = std::saturate_cast<unsigned int>(INT_MAX);
   assert(std::saturate_cast<unsigned int>(  INT_MIN) == 0U);
   assert(std::saturate_cast<unsigned int>(        0) == 0U);
   assert(std::saturate_cast<unsigned int>(  INT_MAX) == static_cast<unsigned int>(INT_MAX));
 
-  { [[maybe_unused]] std::same_as<unsigned int> decltype(auto) _ = std::saturate_cast<unsigned int>(UINT_MAX); }
+  std::same_as<unsigned int> decltype(auto) _ = std::saturate_cast<unsigned int>(UINT_MAX);
   assert(std::saturate_cast<unsigned int>(       0U) == 0U);
   assert(std::saturate_cast<unsigned int>( UINT_MAX) == UINT_MAX);
 
-  { [[maybe_unused]] std::same_as<unsigned int> decltype(auto) _ = std::saturate_cast<unsigned int>(sBigMax); }
+  std::same_as<unsigned int> decltype(auto) _ = std::saturate_cast<unsigned int>(sBigMax);
   assert(std::saturate_cast<unsigned int>(  sBigMin) == 0U);       // saturated
   assert(std::saturate_cast<unsigned int>(    sZero) == 0U);
   assert(std::saturate_cast<unsigned int>(  sBigMax) == UINT_MAX); // saturated
-  
-  { [[maybe_unused]] std::same_as<unsigned int> decltype(auto) _ = std::saturate_cast<unsigned int>(uBigMax); }
+
+  std::same_as<unsigned int> decltype(auto) _ = std::saturate_cast<unsigned int>(uBigMax);
   assert(std::saturate_cast<unsigned int>(    uZero) == 0U);
   assert(std::saturate_cast<unsigned int>(  uBigMax) == UINT_MAX);  // saturated
 
   // unsigned long
 
-  { [[maybe_unused]] std::same_as<unsigned long int> decltype(auto) _ = std::saturate_cast<unsigned long int>(SCHAR_MAX); }
+  std::same_as<unsigned long int> decltype(auto) _ = std::saturate_cast<unsigned long int>(SCHAR_MAX);
   assert(std::saturate_cast<unsigned long int>(SCHAR_MIN) == 0UL);
   assert(std::saturate_cast<unsigned long int>(      O_C) == 0UL);
   assert(std::saturate_cast<unsigned long int>(SCHAR_MAX) == static_cast<unsigned long int>(SCHAR_MAX));
 
-  { [[maybe_unused]] std::same_as<unsigned long int> decltype(auto) _ = std::saturate_cast<unsigned long int>(UCHAR_MAX); }
+  std::same_as<unsigned long int> decltype(auto) _ = std::saturate_cast<unsigned long int>(UCHAR_MAX);
   assert(std::saturate_cast<unsigned long int>(     O_UC) == 0UL);
   assert(std::saturate_cast<unsigned long int>(UCHAR_MAX) == static_cast<unsigned long int>(UCHAR_MAX));
 
-  { [[maybe_unused]] std::same_as<unsigned long int> decltype(auto) _ = std::saturate_cast<unsigned long int>(LONG_MAX); }
+  std::same_as<unsigned long int> decltype(auto) _ = std::saturate_cast<unsigned long int>(LONG_MAX);
   assert(std::saturate_cast<unsigned long int>( LONG_MIN) == 0UL);
   assert(std::saturate_cast<unsigned long int>(       0L) == 0UL);
   assert(std::saturate_cast<unsigned long int>( LONG_MAX) == static_cast<unsigned long int>(LONG_MAX));
 
-  { [[maybe_unused]] std::same_as<unsigned long int> decltype(auto) _ = std::saturate_cast<unsigned long int>(ULONG_MAX); }
+  std::same_as<unsigned long int> decltype(auto) _ = std::saturate_cast<unsigned long int>(ULONG_MAX);
   assert(std::saturate_cast<unsigned long int>(      0UL) == 0UL);
   assert(std::saturate_cast<unsigned long int>(ULONG_MAX) == ULONG_MAX);
 
-  { [[maybe_unused]] std::same_as<unsigned long int> decltype(auto) _ = std::saturate_cast<unsigned long int>(sBigMax); }
+  std::same_as<unsigned long int> decltype(auto) _ = std::saturate_cast<unsigned long int>(sBigMax);
   assert(std::saturate_cast<unsigned long int>(  sBigMin) == 0UL);       // saturated
   assert(std::saturate_cast<unsigned long int>(    sZero) == 0UL);
   assert(std::saturate_cast<unsigned long int>(  sBigMax) == (sizeof(UIntT) > sizeof(unsigned long int) ? ULONG_MAX : LONG_MAX)); // saturated depending on underlying types
 
-  { [[maybe_unused]] std::same_as<unsigned long int> decltype(auto) _ = std::saturate_cast<unsigned long int>(uBigMax); }
+  std::same_as<unsigned long int> decltype(auto) _ = std::saturate_cast<unsigned long int>(uBigMax);
   assert(std::saturate_cast<unsigned long int>(    uZero) == 0UL);
   assert(std::saturate_cast<unsigned long int>(  uBigMax) == ULONG_MAX); // saturated
 
   // unsigned long long
 
-  { [[maybe_unused]] std::same_as<unsigned long long int> decltype(auto) _ = std::saturate_cast<unsigned long long int>(SCHAR_MAX); }
+  std::same_as<unsigned long long int> decltype(auto) _ = std::saturate_cast<unsigned long long int>(SCHAR_MAX);
   assert(std::saturate_cast<unsigned long long int>( SCHAR_MIN) == 0ULL);
   assert(std::saturate_cast<unsigned long long int>(       O_C) == 0ULL);
   assert(std::saturate_cast<unsigned long long int>( SCHAR_MAX) == static_cast<unsigned long long int>(SCHAR_MAX));
 
-  { [[maybe_unused]] std::same_as<unsigned long long  int> decltype(auto) _ = std::saturate_cast<unsigned long long int>(UCHAR_MAX); }
+  std::same_as<unsigned long long  int> decltype(auto) _ = std::saturate_cast<unsigned long long int>(UCHAR_MAX);
   assert(std::saturate_cast<unsigned long long int>(      O_UC) == 0ULL);
   assert(std::saturate_cast<unsigned long long int>( UCHAR_MAX) == static_cast<unsigned long long int>(UCHAR_MAX));
 
-  { [[maybe_unused]] std::same_as<unsigned long long int> decltype(auto) _ = std::saturate_cast<unsigned long long int>(LLONG_MAX); }
+  std::same_as<unsigned long long int> decltype(auto) _ = std::saturate_cast<unsigned long long int>(LLONG_MAX);
   assert(std::saturate_cast<unsigned long long int>( LLONG_MIN) == 0ULL);
   assert(std::saturate_cast<unsigned long long int>(       0LL) == 0ULL);
   assert(std::saturate_cast<unsigned long long int>( LLONG_MAX) == static_cast<unsigned long long int>(LLONG_MAX));
 
-  { [[maybe_unused]] std::same_as<unsigned long long int> decltype(auto) _ = std::saturate_cast<unsigned long long int>(ULLONG_MAX); }
+  std::same_as<unsigned long long int> decltype(auto) _ = std::saturate_cast<unsigned long long int>(ULLONG_MAX);
   assert(std::saturate_cast<unsigned long long int>(      0ULL) == 0ULL);
   assert(std::saturate_cast<unsigned long long int>(ULLONG_MAX) == ULLONG_MAX);
 
 #ifndef TEST_HAS_NO_INT128
-  { [[maybe_unused]] std::same_as<unsigned long long int> decltype(auto) _ = std::saturate_cast<unsigned long long int>(sBigMax); }
+  std::same_as<unsigned long long int> decltype(auto) _ = std::saturate_cast<unsigned long long int>(sBigMax);
   assert(std::saturate_cast<unsigned long long int>(   sBigMin) == 0ULL);       // (128-bit) saturated
   assert(std::saturate_cast<unsigned long long int>(     sZero) == 0ULL);
   assert(std::saturate_cast<unsigned long long int>(   sBigMax) == ULLONG_MAX); // (128-bit) saturated
 
-  { [[maybe_unused]] std::same_as<unsigned long long int> decltype(auto) _ = std::saturate_cast<unsigned long long int>(uBigMax); }
+  std::same_as<unsigned long long int> decltype(auto) _ = std::saturate_cast<unsigned long long int>(uBigMax);
   assert(std::saturate_cast<unsigned long long int>(     uZero) == 0ULL);
   assert(std::saturate_cast<unsigned long long int>(   uBigMax) == ULLONG_MAX); // (128-bit) saturated
 
-  { [[maybe_unused]] std::same_as<__uint128_t> decltype(auto) _ = std::saturate_cast<__uint128_t>(SCHAR_MIN); }
+  std::same_as<__uint128_t> decltype(auto) _ = std::saturate_cast<__uint128_t>(SCHAR_MIN);
   assert(std::saturate_cast<__uint128_t>(SCHAR_MIN) == uZero);
   assert(std::saturate_cast<__uint128_t>(      O_C) == uZero);
   assert(std::saturate_cast<__uint128_t>(SCHAR_MAX) == static_cast<__uint128_t>(SCHAR_MAX));
 
-  { [[maybe_unused]] std::same_as<__uint128_t> decltype(auto) _ = std::saturate_cast<__uint128_t>(UCHAR_MAX); }
+  std::same_as<__uint128_t> decltype(auto) _ = std::saturate_cast<__uint128_t>(UCHAR_MAX);
   assert(std::saturate_cast<__uint128_t>(     O_UC) == uZero);
   assert(std::saturate_cast<__uint128_t>(UCHAR_MAX) == static_cast<__uint128_t>(UCHAR_MAX));
 
-  { [[maybe_unused]] std::same_as<__uint128_t> decltype(auto) _ = std::saturate_cast<__uint128_t>(sBigMax); }
+  std::same_as<__uint128_t> decltype(auto) _ = std::saturate_cast<__uint128_t>(sBigMax);
   assert(std::saturate_cast<__uint128_t>(  sBigMin) == uZero); // saturated
   assert(std::saturate_cast<__uint128_t>(    sZero) == uZero);
   assert(std::saturate_cast<__uint128_t>(  sBigMax) == static_cast<__uint128_t>(sBigMax));
 
-  { [[maybe_unused]] std::same_as<__uint128_t> decltype(auto) _ = std::saturate_cast<__uint128_t>(uBigMax); }
+  std::same_as<__uint128_t> decltype(auto) _ = std::saturate_cast<__uint128_t>(uBigMax);
   assert(std::saturate_cast<__uint128_t>(    uZero) == uZero);
   assert(std::saturate_cast<__uint128_t>(  uBigMax) == uBigMax);
 #endif
diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/sub_sat.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/sub_sat.pass.cpp
index d7bdf2c0271acf..fe4255c1f7a6b8 100644
--- a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/sub_sat.pass.cpp
+++ b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/sub_sat.pass.cpp
@@ -26,8 +26,7 @@ constexpr bool test_signed() {
   constexpr auto minVal = std::numeric_limits<IntegerT>::min();
   constexpr auto maxVal = std::numeric_limits<IntegerT>::max();
 
-  // TODO(LLVM-20) remove [[maybe_unused]] since all supported compilers support "Placeholder variables with no name"
-  [[maybe_unused]] std::same_as<IntegerT> decltype(auto) _ = std::sub_sat(minVal, maxVal);
+  std::same_as<IntegerT> decltype(auto) _ = std::sub_sat(minVal, maxVal);
 
   static_assert(noexcept(std::sub_sat(minVal, maxVal)));
 
@@ -89,8 +88,7 @@ constexpr bool test_unsigned() {
   constexpr auto minVal = std::numeric_limits<IntegerT>::min();
   constexpr auto maxVal = std::numeric_limits<IntegerT>::max();
 
-  // TODO(LLVM-20) remove [[maybe_unused]] since all supported compilers support "Placeholder variables with no name"
-  [[maybe_unused]] std::same_as<IntegerT> decltype(auto) _ = std::sub_sat(minVal, maxVal);
+  std::same_as<IntegerT> decltype(auto) _ = std::sub_sat(minVal, maxVal);
 
   static_assert(noexcept(std::sub_sat(minVal, maxVal)));
 
diff --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.copy.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.copy.pass.cpp
index 9e78596929fb62..32560bf8fac35b 100644
--- a/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.copy.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.copy.pass.cpp
@@ -121,13 +121,10 @@ constexpr bool test() {
   }
 
   {
-    // TODO(LLVM 20): Remove once we drop support for Clang 17
-#if defined(TEST_CLANG_VER) && TEST_CLANG_VER >= 1800
     // https://github.com/llvm/llvm-project/issues/92676
     std::expected<Any, int> e1;
     auto e2 = e1;
     assert(e2.has_value());
-#endif
   }
 
   return true;
diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg/visit.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg/visit.pass.cpp
index 829b74121b9c6b..20e0a5ed66bd05 100644
--- a/libcxx/test/std/utilities/format/format.arguments/format.arg/visit.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.arguments/format.arg/visit.pass.cpp
@@ -9,7 +9,6 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
 // UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
 // The tested functionality needs deducing this.
-// UNSUPPORTED: clang-17
 // XFAIL: apple-clang
 
 // <format>
diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg/visit.return_type.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg/visit.return_type.pass.cpp
index 874d609432f221..8a79dd4d50f20d 100644
--- a/libcxx/test/std/utilities/format/format.arguments/format.arg/visit.return_type.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.arguments/format.arg/visit.return_type.pass.cpp
@@ -9,7 +9,6 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
 // UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
 // The tested functionality needs deducing this.
-// UNSUPPORTED: clang-17
 // XFAIL: apple-clang
 
 // <format>
diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg/visit_format_arg.deprecated.verify.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg/visit_format_arg.deprecated.verify.cpp
index e3e3e9a19e122f..146ceba58872e2 100644
--- a/libcxx/test/std/utilities/format/format.arguments/format.arg/visit_format_arg.deprecated.verify.cpp
+++ b/libcxx/test/std/utilities/format/format.arguments/format.arg/visit_format_arg.deprecated.verify.cpp
@@ -8,7 +8,6 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
 // UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
-// UNSUPPORTED: clang-17
 // XFAIL: apple-clang
 
 // <format>
diff --git a/libcxx/test/std/utilities/meta/meta.rel/is_virtual_base_of.pass.cpp b/libcxx/test/std/utilities/meta/meta.rel/is_virtual_base_of.pass.cpp
index 6b34d56e2c6f45..f443d2030961d1 100644
--- a/libcxx/test/std/utilities/meta/meta.rel/is_virtual_base_of.pass.cpp
+++ b/libcxx/test/std/utilities/meta/meta.rel/is_virtual_base_of.pass.cpp
@@ -9,7 +9,7 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
 
 // These compilers don't support __builtin_is_virtual_base_of yet.
-// UNSUPPORTED: clang-17, clang-18, clang-19, gcc-14, apple-clang-16, apple-clang-17
+// UNSUPPORTED: clang-18, clang-19, gcc-14, apple-clang-16, apple-clang-17
 
 // <type_traits>
 
diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/nttp.equivalence.compile.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/nttp.equivalence.compile.pass.cpp
index db45a56feb88aa..f5fd5a674882bd 100644
--- a/libcxx/test/std/utilities/utility/pairs/pairs.pair/nttp.equivalence.compile.pass.cpp
+++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/nttp.equivalence.compile.pass.cpp
@@ -7,7 +7,6 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17
-// UNSUPPORTED: clang-17
 
 // <utility>
 
diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/nttp.verify.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/nttp.verify.cpp
index ac081495a62052..499ba6b243bed4 100644
--- a/libcxx/test/std/utilities/utility/pairs/pairs.pair/nttp.verify.cpp
+++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/nttp.verify.cpp
@@ -7,7 +7,6 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17
-// UNSUPPORTED: clang-17
 
 // <utility>
 
diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp
index bea6d949924bd8..8a8d41547fbec1 100644
--- a/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp
@@ -8,7 +8,6 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
 // The tested functionality needs deducing this.
-// UNSUPPORTED: clang-17
 // XFAIL: apple-clang
 
 // <variant>
diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp
index 0da23fd58ccaa7..f68112d30fc35d 100644
--- a/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp
@@ -8,7 +8,6 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
 // The tested functionality needs deducing this.
-// UNSUPPORTED: clang-17
 // XFAIL: apple-clang
 
 // <variant>
diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp
index 7429cdf80facaa..8093af0aba587c 100644
--- a/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp
@@ -8,7 +8,6 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
 // The tested functionality needs deducing this.
-// UNSUPPORTED: clang-17
 // XFAIL: apple-clang
 
 // <variant>

>From 594ee7dfa60b8b6423f84d18e14af4b0d194a727 Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Sun, 15 Sep 2024 18:22:03 +0200
Subject: [PATCH 2/2] Remove unrelated changes

Let's adjust tests and implementation
in a seperate PR.
---
 libcxx/docs/ReleaseNotes/20.rst               |   4 +-
 libcxx/include/__chrono/weekday.h             |  19 +++
 libcxx/include/__type_traits/promote.h        |  81 +++++++++++
 .../diagnose_invalid_memory_order.verify.cpp  |   2 +-
 libcxx/test/libcxx/clang_tidy.gen.py          |   3 +
 .../libcxx/gdb/gdb_pretty_printer_test.sh.cpp |   2 +-
 .../no_unique_address.compile.pass.cpp        |   2 +-
 .../no_unique_address.compile.pass.cpp        |   2 +-
 .../no_unique_address.compile.pass.cpp        |   2 +-
 .../transform_error.mandates.verify.cpp       |  20 +--
 .../transform_error.mandates.verify.cpp       |  24 ++--
 .../atomics.types.float/fetch_add.pass.cpp    |   2 +-
 .../atomics.types.float/fetch_sub.pass.cpp    |   2 +-
 .../operator.minus_equals.pass.cpp            |   2 +-
 .../operator.plus_equals.pass.cpp             |   2 +-
 .../simd/simd.class/simd_copy.pass.cpp        |   2 +-
 .../sized_delete_array14.pass.cpp             |   2 +-
 .../new.delete.single/sized_delete14.pass.cpp |   2 +-
 .../test/std/numerics/c.math/signbit.pass.cpp |   2 +-
 .../numeric.ops.sat/add_sat.pass.cpp          |   6 +-
 .../numeric.ops.sat/div_sat.pass.cpp          |   6 +-
 .../numeric.ops.sat/mul_sat.pass.cpp          |   6 +-
 .../numeric.ops.sat/saturate_cast.pass.cpp    | 132 +++++++++---------
 .../numeric.ops.sat/sub_sat.pass.cpp          |   6 +-
 .../expected.expected/ctor/ctor.copy.pass.cpp |   3 +
 .../format.arg/visit.pass.cpp                 |   1 +
 .../format.arg/visit.return_type.pass.cpp     |   1 +
 .../visit_format_arg.deprecated.verify.cpp    |   1 +
 .../meta/meta.rel/is_virtual_base_of.pass.cpp |   2 +-
 .../nttp.equivalence.compile.pass.cpp         |   1 +
 .../utility/pairs/pairs.pair/nttp.verify.cpp  |   1 +
 .../robust_against_adl.pass.cpp               |   1 +
 .../variant.visit.member/visit.pass.cpp       |   1 +
 .../visit_return_type.pass.cpp                |   1 +
 34 files changed, 239 insertions(+), 107 deletions(-)

diff --git a/libcxx/docs/ReleaseNotes/20.rst b/libcxx/docs/ReleaseNotes/20.rst
index 93bed91992084b..aecac6692932b8 100644
--- a/libcxx/docs/ReleaseNotes/20.rst
+++ b/libcxx/docs/ReleaseNotes/20.rst
@@ -64,8 +64,8 @@ Deprecations and Removals
   removed in language modes prior to C++20. If you are using these features prior to C++20, you will need to
   update to ``-std=c++20``.
 
-- The relational operators for ``std::chrono::weekday`` are removed entirely, and the
-  ``_LIBCPP_ENABLE_REMOVED_WEEKDAY_RELATIONAL_OPERATORS`` macro that was used to re-enable this extension is
+- TODO: The relational operators for ``std::chrono::weekday`` will be removed entirely, and the
+  ``_LIBCPP_ENABLE_REMOVED_WEEKDAY_RELATIONAL_OPERATORS`` macro that was used to re-enable this extension will be
   ignored in LLVM 20.
 
 - The ``_LIBCPP_ENABLE_REMOVED_ALLOCATOR_CONST`` macro no longer has any effect. ``std::allocator<const T>`` is not
diff --git a/libcxx/include/__chrono/weekday.h b/libcxx/include/__chrono/weekday.h
index 728cbb844633fe..86c780cc718256 100644
--- a/libcxx/include/__chrono/weekday.h
+++ b/libcxx/include/__chrono/weekday.h
@@ -79,6 +79,25 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr bool operator==(const weekday& __lhs, con
   return __lhs.c_encoding() == __rhs.c_encoding();
 }
 
+// TODO(LLVM 20): Remove the escape hatch
+#  ifdef _LIBCPP_ENABLE_REMOVED_WEEKDAY_RELATIONAL_OPERATORS
+_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator<(const weekday& __lhs, const weekday& __rhs) noexcept {
+  return __lhs.c_encoding() < __rhs.c_encoding();
+}
+
+_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator>(const weekday& __lhs, const weekday& __rhs) noexcept {
+  return __rhs < __lhs;
+}
+
+_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator<=(const weekday& __lhs, const weekday& __rhs) noexcept {
+  return !(__rhs < __lhs);
+}
+
+_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator>=(const weekday& __lhs, const weekday& __rhs) noexcept {
+  return !(__lhs < __rhs);
+}
+#  endif // _LIBCPP_ENABLE_REMOVED_WEEKDAY_RELATIONAL_OPERATORS
+
 _LIBCPP_HIDE_FROM_ABI inline constexpr weekday operator+(const weekday& __lhs, const days& __rhs) noexcept {
   auto const __mu = static_cast<long long>(__lhs.c_encoding()) + __rhs.count();
   auto const __yr = (__mu >= 0 ? __mu : __mu - 6) / 7;
diff --git a/libcxx/include/__type_traits/promote.h b/libcxx/include/__type_traits/promote.h
index cccb6e0e04a00f..2b2a6843b91502 100644
--- a/libcxx/include/__type_traits/promote.h
+++ b/libcxx/include/__type_traits/promote.h
@@ -13,12 +13,20 @@
 #include <__type_traits/integral_constant.h>
 #include <__type_traits/is_arithmetic.h>
 
+#if defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER == 1700
+#  include <__type_traits/is_same.h>
+#  include <__utility/declval.h>
+#endif
+
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
 #endif
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
+// TODO(LLVM-20): Remove this workaround
+#if !defined(_LIBCPP_CLANG_VER) || _LIBCPP_CLANG_VER != 1700
+
 template <class... _Args>
 class __promote {
   static_assert((is_arithmetic<_Args>::value && ...));
@@ -42,6 +50,79 @@ class __promote {
   using type = decltype((__test(_Args()) + ...));
 };
 
+#else
+
+template <class _Tp>
+struct __numeric_type {
+  static void __test(...);
+  static float __test(float);
+  static double __test(char);
+  static double __test(int);
+  static double __test(unsigned);
+  static double __test(long);
+  static double __test(unsigned long);
+  static double __test(long long);
+  static double __test(unsigned long long);
+#  ifndef _LIBCPP_HAS_NO_INT128
+  static double __test(__int128_t);
+  static double __test(__uint128_t);
+#  endif
+  static double __test(double);
+  static long double __test(long double);
+
+  typedef decltype(__test(std::declval<_Tp>())) type;
+  static const bool value = _IsNotSame<type, void>::value;
+};
+
+template <>
+struct __numeric_type<void> {
+  static const bool value = true;
+};
+
+template <class _A1,
+          class _A2 = void,
+          class _A3 = void,
+          bool      = __numeric_type<_A1>::value && __numeric_type<_A2>::value && __numeric_type<_A3>::value>
+class __promote_imp {
+public:
+  static const bool value = false;
+};
+
+template <class _A1, class _A2, class _A3>
+class __promote_imp<_A1, _A2, _A3, true> {
+private:
+  typedef typename __promote_imp<_A1>::type __type1;
+  typedef typename __promote_imp<_A2>::type __type2;
+  typedef typename __promote_imp<_A3>::type __type3;
+
+public:
+  typedef decltype(__type1() + __type2() + __type3()) type;
+  static const bool value = true;
+};
+
+template <class _A1, class _A2>
+class __promote_imp<_A1, _A2, void, true> {
+private:
+  typedef typename __promote_imp<_A1>::type __type1;
+  typedef typename __promote_imp<_A2>::type __type2;
+
+public:
+  typedef decltype(__type1() + __type2()) type;
+  static const bool value = true;
+};
+
+template <class _A1>
+class __promote_imp<_A1, void, void, true> {
+public:
+  typedef typename __numeric_type<_A1>::type type;
+  static const bool value = true;
+};
+
+template <class _A1, class _A2 = void, class _A3 = void>
+class __promote : public __promote_imp<_A1, _A2, _A3> {};
+
+#endif // !defined(_LIBCPP_CLANG_VER) || _LIBCPP_CLANG_VER >= 1700
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP___TYPE_TRAITS_PROMOTE_H
diff --git a/libcxx/test/libcxx/atomics/diagnose_invalid_memory_order.verify.cpp b/libcxx/test/libcxx/atomics/diagnose_invalid_memory_order.verify.cpp
index fc83017c7d8227..2790916edaf698 100644
--- a/libcxx/test/libcxx/atomics/diagnose_invalid_memory_order.verify.cpp
+++ b/libcxx/test/libcxx/atomics/diagnose_invalid_memory_order.verify.cpp
@@ -9,7 +9,7 @@
 // This test fails with Clang <18 because diagnose_if doesn't emit all of the
 // diagnostics when -fdelayed-template-parsing is enabled, like it is in MSVC
 // mode.
-// XFAIL: msvc
+// XFAIL: msvc && clang-17
 
 // REQUIRES: diagnose-if-support
 
diff --git a/libcxx/test/libcxx/clang_tidy.gen.py b/libcxx/test/libcxx/clang_tidy.gen.py
index 4311bb49ac802b..f4f905f579784f 100644
--- a/libcxx/test/libcxx/clang_tidy.gen.py
+++ b/libcxx/test/libcxx/clang_tidy.gen.py
@@ -27,6 +27,9 @@
 // The GCC compiler flags are not always compatible with clang-tidy.
 // UNSUPPORTED: gcc
 
+// Clang 17 has false positives.
+// UNSUPPORTED: clang-17
+
 {lit_header_restrictions.get(header, '')}
 
 // TODO: run clang-tidy with modules enabled once they are supported
diff --git a/libcxx/test/libcxx/gdb/gdb_pretty_printer_test.sh.cpp b/libcxx/test/libcxx/gdb/gdb_pretty_printer_test.sh.cpp
index 4d0e925ea0fab4..2c8534977febc7 100644
--- a/libcxx/test/libcxx/gdb/gdb_pretty_printer_test.sh.cpp
+++ b/libcxx/test/libcxx/gdb/gdb_pretty_printer_test.sh.cpp
@@ -12,7 +12,7 @@
 // UNSUPPORTED: c++03
 
 // TODO: Investigate these failures which break the CI.
-// UNSUPPORTED: clang-18, clang-19
+// UNSUPPORTED: clang-17, clang-18, clang-19
 
 // The Android libc++ tests are run on a non-Android host, connected to an
 // Android device over adb. gdb needs special support to make this work (e.g.
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.lazy.split/no_unique_address.compile.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.lazy.split/no_unique_address.compile.pass.cpp
index 33531e2389de0b..a0bfb7c4a246b5 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.lazy.split/no_unique_address.compile.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.lazy.split/no_unique_address.compile.pass.cpp
@@ -7,7 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17
-// XFAIL: msvc
+// XFAIL: msvc && clang-17
 
 // class lazy_split_view {
 //   _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.split/no_unique_address.compile.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.split/no_unique_address.compile.pass.cpp
index 192b52307e9683..694cf1fd0d0e4c 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.split/no_unique_address.compile.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.split/no_unique_address.compile.pass.cpp
@@ -7,7 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17
-// XFAIL: msvc
+// XFAIL: msvc && clang-17
 
 // class split_view {
 //   _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
diff --git a/libcxx/test/libcxx/ranges/range.factories/range.istream.view/no_unique_address.compile.pass.cpp b/libcxx/test/libcxx/ranges/range.factories/range.istream.view/no_unique_address.compile.pass.cpp
index 64454d81a03803..a77c4e4d1bcdb0 100644
--- a/libcxx/test/libcxx/ranges/range.factories/range.istream.view/no_unique_address.compile.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.factories/range.istream.view/no_unique_address.compile.pass.cpp
@@ -8,7 +8,7 @@
 
 // UNSUPPORTED: no-localization
 // UNSUPPORTED: c++03, c++11, c++14, c++17
-// XFAIL: msvc
+// XFAIL: msvc && clang-17
 
 // Test the libc++ extension that the value stored in `std::ranges::istream_view` has been marked
 // as _LIBCPP_NO_UNIQUE_ADDRESS
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp
index 5fbc115d670bfc..61374094b7adfb 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp
@@ -6,6 +6,10 @@
 //
 //===----------------------------------------------------------------------===//
 
+// Clang-18 fixed some spurious clang diagnostics. Once clang-18 is the
+// minimum required version these obsolete tests can be removed.
+// TODO(LLVM-20) remove spurious clang diagnostic tests.
+
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
 
 // With clang-cl, some warnings have a 'which is a Microsoft extension' suffix
@@ -55,12 +59,12 @@ void test() {
   {
     std::expected<int, int> e;
     e.transform_error(return_unexpected<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
     // expected-error-re@*:* {{static assertion failed {{.*}}[expected.object.general] A program that instantiates the definition of template expected<T, E> for {{.*}} is ill-formed.}}
     // expected-error-re@*:* 0-1 {{union member {{.*}} has reference type {{.*}}}}
 
     e.transform_error(return_no_object<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
     // expected-error-re@*:* {{static assertion failed {{.*}}[expected.object.general] A program that instantiates the definition of template expected<T, E> for {{.*}} is ill-formed.}}
     // expected-warning-re@*:* 0-1 {{union member {{.*}} has reference type {{.*}}, which is a Microsoft extension}}
   }
@@ -69,27 +73,27 @@ void test() {
   {
     const std::expected<int, int> e;
     e.transform_error(return_unexpected<const int &>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* 2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* 0-2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
     e.transform_error(return_no_object<const int &>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* 2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* 0-2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
   }
 
   // Test && overload
   {
     std::expected<int, int> e;
     std::move(e).transform_error(return_unexpected<int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* 2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* 0-2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
     std::move(e).transform_error(return_no_object<int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* 2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* 0-2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
   }
 
   // Test const&& overload
   {
     const std::expected<int, int> e;
     std::move(e).transform_error(return_unexpected<const int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* 2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* 0-2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
     std::move(e).transform_error(return_no_object<const int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* 2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* 0-2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
   }
 }
 // clang-format on
diff --git a/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp
index dc553a1fda463f..16233cd90d2199 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp
@@ -6,6 +6,10 @@
 //
 //===----------------------------------------------------------------------===//
 
+// Clang-18 fixed some spurious clang diagnostics. Once clang-18 is the
+// minumum required version these obsolete tests can be removed.
+// TODO(LLVM-20) remove spurious clang diagnostic tests.
+
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
 
 // With clang-cl, some warnings have a 'which is a Microsoft extension' suffix
@@ -56,13 +60,13 @@ void test() {
   {
     std::expected<void, int> e;
     e.transform_error(return_unexpected<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
     // expected-error-re@*:* {{static assertion failed {{.*}}A program that instantiates expected<T, E> with a E that is not a valid argument for unexpected<E> is ill-formed}}
-    // expected-error-re@*:* {{call to deleted constructor of {{.*}}}}
+    // expected-error-re@*:* 0-1 {{call to deleted constructor of {{.*}}}}
     // expected-error-re@*:* 0-1 {{union member {{.*}} has reference type {{.*}}}}
 
     e.transform_error(return_no_object<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
     // expected-error-re@*:* {{static assertion failed {{.*}}A program that instantiates expected<T, E> with a E that is not a valid argument for unexpected<E> is ill-formed}}
     // expected-warning-re@*:* 0-1 {{union member {{.*}} has reference type {{.*}}, which is a Microsoft extension}}
   }
@@ -71,28 +75,28 @@ void test() {
   {
     const std::expected<void, int> e;
     e.transform_error(return_unexpected<const int &>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
     e.transform_error(return_no_object<const int &>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
-    // expected-error-re@*:* {{call to deleted constructor of {{.*}}}}
+    // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* 0-1 {{call to deleted constructor of {{.*}}}}
   }
 
   // Test && overload
   {
     std::expected<void, int> e;
     std::move(e).transform_error(return_unexpected<int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
     std::move(e).transform_error(return_no_object<int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
   }
 
   // Test const&& overload
   {
     const std::expected<void, int> e;
     std::move(e).transform_error(return_unexpected<const int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
     std::move(e).transform_error(return_no_object<const int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
-    // expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
+    // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
   }
 }
 // clang-format on
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
index 6c3294bd549b67..40a475ec38b723 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
@@ -10,7 +10,7 @@
 
 // Older versions of clang have a bug with atomic builtins affecting double and long double.
 // Fixed by 5fdd0948.
-// XFAIL: target=powerpc-ibm-{{.*}} && clang-18
+// XFAIL: target=powerpc-ibm-{{.*}} && (clang-17 || clang-18)
 
 // https://github.com/llvm/llvm-project/issues/72893
 // XFAIL: target={{x86_64-.*}} && tsan
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
index 3c9545e32df049..9e798a2a519ff0 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
@@ -10,7 +10,7 @@
 
 // Older versions of clang have a bug with atomic builtins affecting double and long double.
 // Fixed by 5fdd0948.
-// XFAIL: target=powerpc-ibm-{{.*}} && clang-18
+// XFAIL: target=powerpc-ibm-{{.*}} && (clang-17 || clang-18)
 
 // https://github.com/llvm/llvm-project/issues/72893
 // XFAIL: target={{x86_64-.*}} && tsan
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
index f16bf1261656c5..732bd4d7e5dc2b 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
@@ -10,7 +10,7 @@
 
 // Older versions of clang have a bug with atomic builtins affecting double and long double.
 // Fixed by 5fdd0948.
-// XFAIL: target=powerpc-ibm-{{.*}} && clang-18
+// XFAIL: target=powerpc-ibm-{{.*}} && (clang-17 || clang-18)
 
 // floating-point-type operator-=(floating-point-type) volatile noexcept;
 // floating-point-type operator-=(floating-point-type) noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
index 3605648be36da0..1821aca42c7988 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
@@ -10,7 +10,7 @@
 
 // Older versions of clang have a bug with atomic builtins affecting double and long double.
 // Fixed by 5fdd0948.
-// XFAIL: target=powerpc-ibm-{{.*}} && clang-18
+// XFAIL: target=powerpc-ibm-{{.*}} && (clang-17 || clang-18)
 
 // floating-point-type operator+=(floating-point-type) volatile noexcept;
 // floating-point-type operator+=(floating-point-type) noexcept;
diff --git a/libcxx/test/std/experimental/simd/simd.class/simd_copy.pass.cpp b/libcxx/test/std/experimental/simd/simd.class/simd_copy.pass.cpp
index 722e6f770b05bd..7d91ca0eada1d3 100644
--- a/libcxx/test/std/experimental/simd/simd.class/simd_copy.pass.cpp
+++ b/libcxx/test/std/experimental/simd/simd.class/simd_copy.pass.cpp
@@ -10,7 +10,7 @@
 
 // Older versions of clang may encounter a backend error (see 0295c2ad):
 //   Pass-by-value arguments with alignment greater than register width are not supported.
-// XFAIL: target=powerpc{{.*}}-ibm-{{.*}} clang-18
+// XFAIL: target=powerpc{{.*}}-ibm-{{.*}} && (clang-17 || clang-18)
 
 // <experimental/simd>
 //
diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array14.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array14.pass.cpp
index e02e522c05c531..85b641322d99e3 100644
--- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array14.pass.cpp
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/sized_delete_array14.pass.cpp
@@ -9,7 +9,7 @@
 // test sized operator delete[] replacement.
 
 // These compiler versions don't enable sized deallocation by default.
-// UNSUPPORTED: clang-18
+// UNSUPPORTED: clang-17, clang-18
 
 // UNSUPPORTED: sanitizer-new-delete, c++03, c++11
 // XFAIL: apple-clang
diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete14.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete14.pass.cpp
index da1fecadee8488..ae614a1432f7db 100644
--- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete14.pass.cpp
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/sized_delete14.pass.cpp
@@ -9,7 +9,7 @@
 // Test sized operator delete replacement.
 
 // These compiler versions do not enable sized deallocation by default.
-// UNSUPPORTED: clang-18
+// UNSUPPORTED: clang-17, clang-18
 
 // UNSUPPORTED: sanitizer-new-delete, c++03, c++11
 // XFAIL: apple-clang
diff --git a/libcxx/test/std/numerics/c.math/signbit.pass.cpp b/libcxx/test/std/numerics/c.math/signbit.pass.cpp
index 6dbc0b1413f9da..a8a566f7de6434 100644
--- a/libcxx/test/std/numerics/c.math/signbit.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/signbit.pass.cpp
@@ -12,7 +12,7 @@
 // UNSUPPORTED: windows
 
 // These compilers don't support constexpr `__builtin_signbit` yet.
-// UNSUPPORTED: clang-18, clang-19, apple-clang-15, apple-clang-16
+// UNSUPPORTED: clang-17, clang-18, clang-19, apple-clang-15, apple-clang-16
 
 #include <cassert>
 #include <cmath>
diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/add_sat.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/add_sat.pass.cpp
index 8288378ab769e1..036bf53e36dcd4 100644
--- a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/add_sat.pass.cpp
+++ b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/add_sat.pass.cpp
@@ -25,7 +25,8 @@ constexpr bool test_signed() {
   constexpr auto minVal = std::numeric_limits<IntegerT>::min();
   constexpr auto maxVal = std::numeric_limits<IntegerT>::max();
 
-  std::same_as<IntegerT> decltype(auto) _ = std::add_sat(minVal, maxVal);
+  // TODO(LLVM-20) remove [[maybe_unused]]  since all supported compilers support "Placeholder variables with no name"
+  [[maybe_unused]] std::same_as<IntegerT> decltype(auto) _ = std::add_sat(minVal, maxVal);
 
   static_assert(noexcept(std::add_sat(minVal, maxVal)));
 
@@ -96,7 +97,8 @@ constexpr bool test_unsigned() {
   constexpr auto minVal = std::numeric_limits<IntegerT>::min();
   constexpr auto maxVal = std::numeric_limits<IntegerT>::max();
 
-  std::same_as<IntegerT> decltype(auto) _ = std::add_sat(minVal, maxVal);
+  // TODO(LLVM-20) remove [[maybe_unused]]  since all supported compilers support "Placeholder variables with no name"
+  [[maybe_unused]] std::same_as<IntegerT> decltype(auto) _ = std::add_sat(minVal, maxVal);
 
   static_assert(noexcept(std::add_sat(minVal, maxVal)));
 
diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/div_sat.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/div_sat.pass.cpp
index fa9841b24d27ac..b1cace74d88288 100644
--- a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/div_sat.pass.cpp
+++ b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/div_sat.pass.cpp
@@ -26,7 +26,8 @@ constexpr bool test_signed() {
   constexpr auto minVal = std::numeric_limits<IntegerT>::min();
   constexpr auto maxVal = std::numeric_limits<IntegerT>::max();
 
-  std::same_as<IntegerT> decltype(auto) _ = std::div_sat(minVal, maxVal);
+  // TODO(LLVM-20) remove [[maybe_unused]] and `{}` scope since all supported compilers support "Placeholder variables with no name"
+  [[maybe_unused]] std::same_as<IntegerT> decltype(auto) _ = std::div_sat(minVal, maxVal);
 
   static_assert(noexcept(std::div_sat(minVal, maxVal)));
 
@@ -88,7 +89,8 @@ constexpr bool test_unsigned() {
   constexpr auto minVal = std::numeric_limits<IntegerT>::min();
   constexpr auto maxVal = std::numeric_limits<IntegerT>::max();
 
-  std::same_as<IntegerT> decltype(auto) _ = std::div_sat(minVal, maxVal);
+  // TODO(LLVM-20) remove [[maybe_unused]] since all supported compilers support "Placeholder variables with no name"
+  [[maybe_unused]] std::same_as<IntegerT> decltype(auto) _ = std::div_sat(minVal, maxVal);
   static_assert(noexcept(std::div_sat(minVal, maxVal)));
 
   // clang-format off
diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/mul_sat.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/mul_sat.pass.cpp
index 060eb52103a024..2c8eec57e12042 100644
--- a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/mul_sat.pass.cpp
+++ b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/mul_sat.pass.cpp
@@ -26,7 +26,8 @@ constexpr bool test_signed() {
   constexpr auto minVal = std::numeric_limits<IntegerT>::min();
   constexpr auto maxVal = std::numeric_limits<IntegerT>::max();
 
-  std::same_as<IntegerT> decltype(auto) _ = std::mul_sat(minVal, maxVal);
+  // TODO(LLVM-20) remove [[maybe_unused]] since all supported compilers support "Placeholder variables with no name"
+  [[maybe_unused]] std::same_as<IntegerT> decltype(auto) _ = std::mul_sat(minVal, maxVal);
 
   static_assert(noexcept(std::mul_sat(minVal, maxVal)));
 
@@ -102,7 +103,8 @@ constexpr bool test_unsigned() {
   constexpr auto minVal = std::numeric_limits<IntegerT>::min();
   constexpr auto maxVal = std::numeric_limits<IntegerT>::max();
 
-  std::same_as<IntegerT> decltype(auto) _ = std::mul_sat(minVal, maxVal);
+  // TODO(LLVM-20) remove [[maybe_unused]] since all supported compilers support "Placeholder variables with no name"
+  [[maybe_unused]] std::same_as<IntegerT> decltype(auto) _ = std::mul_sat(minVal, maxVal);
 
   static_assert(noexcept(std::mul_sat(minVal, maxVal)));
 
diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturate_cast.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturate_cast.pass.cpp
index 7c3e570c407575..cbca37e3a66139 100644
--- a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturate_cast.pass.cpp
+++ b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturate_cast.pass.cpp
@@ -72,312 +72,314 @@ constexpr bool test() {
 
   // signed char
 
-  std::same_as<signed char> decltype(auto) _ = std::saturate_cast<signed char>(SCHAR_MAX);
+  // TODO(LLVM-20) remove [[maybe_unused]] and `{}` scope since all supported compilers support "Placeholder variables with no name",
+  // here and below...
+  { [[maybe_unused]] std::same_as<signed char> decltype(auto) _ = std::saturate_cast<signed char>(SCHAR_MAX); }
   assert(std::saturate_cast<signed char>(SCHAR_MIN)  == SCHAR_MIN);
   assert(std::saturate_cast<signed char>(      O_C)  ==       O_C);
   assert(std::saturate_cast<signed char>(SCHAR_MAX)  == SCHAR_MAX);
 
-  std::same_as<signed char> decltype(auto) _ = std::saturate_cast<signed char>(UCHAR_MAX);
+  { [[maybe_unused]] std::same_as<signed char> decltype(auto) _ = std::saturate_cast<signed char>(UCHAR_MAX); }
   assert(std::saturate_cast<signed char>(     O_UC)  ==       O_C);
   assert(std::saturate_cast<signed char>(UCHAR_MAX)  == SCHAR_MAX);
 
-  std::same_as<signed char> decltype(auto) _ = std::saturate_cast<signed char>(sBigMax);
+  { [[maybe_unused]] std::same_as<signed char> decltype(auto) _ = std::saturate_cast<signed char>(sBigMax); }
   assert(std::saturate_cast<signed char>(sBigMin)    == SCHAR_MIN); // saturated
   assert(std::saturate_cast<signed char>(  sZero)    ==       O_C);
   assert(std::saturate_cast<signed char>(sBigMax)    == SCHAR_MAX); // saturated
 
-  std::same_as<signed char> decltype(auto) _ = std::saturate_cast<signed char>(uBigMax);
+  { [[maybe_unused]] std::same_as<signed char> decltype(auto) _ = std::saturate_cast<signed char>(uBigMax); }
   assert(std::saturate_cast<signed char>(  uZero)    ==       O_C);
   assert(std::saturate_cast<signed char>(uBigMax)    == SCHAR_MAX); // saturated
 
   // short
 
-  std::same_as<signed short int> decltype(auto) _ = std::saturate_cast<signed short int>(SCHAR_MAX);
+  { [[maybe_unused]] std::same_as<signed short int> decltype(auto) _ = std::saturate_cast<signed short int>(SCHAR_MAX); }
   assert(std::saturate_cast<signed short int>(SCHAR_MIN) == static_cast<signed short int>(SCHAR_MIN));
   assert(std::saturate_cast<signed short int>(      O_C) == O_S);
   assert(std::saturate_cast<signed short int>(SCHAR_MAX) == static_cast<signed short int>(SCHAR_MAX));
 
-  std::same_as<signed short int> decltype(auto) _ = std::saturate_cast<signed short int>(UCHAR_MAX);
+  { [[maybe_unused]] std::same_as<signed short int> decltype(auto) _ = std::saturate_cast<signed short int>(UCHAR_MAX); }
   assert(std::saturate_cast<signed short int>(     O_UC) == O_S);
   assert(std::saturate_cast<signed short int>(UCHAR_MAX) == static_cast<signed short int>(UCHAR_MAX));
 
-  std::same_as<signed short int> decltype(auto) _ = std::saturate_cast<signed short int>(SHRT_MAX);
+  { [[maybe_unused]] std::same_as<signed short int> decltype(auto) _ = std::saturate_cast<signed short int>(SHRT_MAX); }
   assert(std::saturate_cast<signed short int>( SHRT_MIN) == SHRT_MIN);
   assert(std::saturate_cast<signed short int>(      O_S) == O_S);
   assert(std::saturate_cast<signed short int>( SHRT_MAX) == SHRT_MAX);
 
-  std::same_as<signed short int> decltype(auto) _ = std::saturate_cast<signed short int>(USHRT_MAX);
+  { [[maybe_unused]] std::same_as<signed short int> decltype(auto) _ = std::saturate_cast<signed short int>(USHRT_MAX); }
   assert(std::saturate_cast<signed short int>(     O_US) == O_S);
   assert(std::saturate_cast<signed short int>(USHRT_MAX) == SHRT_MAX); // saturated
 
-  std::same_as<signed short int> decltype(auto) _ = std::saturate_cast<signed short int>(sBigMax);
+  { [[maybe_unused]] std::same_as<signed short int> decltype(auto) _ = std::saturate_cast<signed short int>(sBigMax); }
   assert(std::saturate_cast<signed short int>( sBigMin)   == SHRT_MIN); // saturated
   assert(std::saturate_cast<signed short int>(   sZero)   == O_S);
   assert(std::saturate_cast<signed short int>( sBigMax)   == SHRT_MAX); // saturated
 
-  std::same_as<signed short int> decltype(auto) _ = std::saturate_cast<signed short int>(uBigMax);
+  { [[maybe_unused]] std::same_as<signed short int> decltype(auto) _ = std::saturate_cast<signed short int>(uBigMax); }
   assert(std::saturate_cast<signed short int>(   uZero)   == O_S);
   assert(std::saturate_cast<signed short int>( uBigMax)   == SHRT_MAX); // saturated
 
   // int
 
-  std::same_as<signed int> decltype(auto) _ = std::saturate_cast<signed int>(SCHAR_MAX);
+  { [[maybe_unused]] std::same_as<signed int> decltype(auto) _ = std::saturate_cast<signed int>(SCHAR_MAX); }
   assert(std::saturate_cast<signed int>(SCHAR_MIN) == static_cast<signed int>(SCHAR_MIN));
   assert(std::saturate_cast<signed int>(      O_C) == 0);
   assert(std::saturate_cast<signed int>(SCHAR_MAX) == static_cast<signed int>(SCHAR_MAX));
 
-  std::same_as<signed int> decltype(auto) _ = std::saturate_cast<signed int>(UCHAR_MAX);
+  { [[maybe_unused]] std::same_as<signed int> decltype(auto) _ = std::saturate_cast<signed int>(UCHAR_MAX); }
   assert(std::saturate_cast<signed int>(     O_UC) == 0);
   assert(std::saturate_cast<signed int>(UCHAR_MAX) == static_cast<signed int>(UCHAR_MAX));
 
-  std::same_as<signed int> decltype(auto) _ = std::saturate_cast<signed int>(INT_MAX);
+  { [[maybe_unused]] std::same_as<signed int> decltype(auto) _ = std::saturate_cast<signed int>(INT_MAX); }
   assert(std::saturate_cast<signed int>(  INT_MIN) == INT_MIN);
   assert(std::saturate_cast<signed int>(        0) == 0);
   assert(std::saturate_cast<signed int>(  INT_MAX) == INT_MAX);
 
-  std::same_as<signed int> decltype(auto) _ = std::saturate_cast<signed int>(UINT_MAX);
+  { [[maybe_unused]] std::same_as<signed int> decltype(auto) _ = std::saturate_cast<signed int>(UINT_MAX); }
   assert(std::saturate_cast<signed int>(       0)  == 0);
   assert(std::saturate_cast<signed int>(UINT_MAX)  == INT_MAX); // saturated
 
-  std::same_as<signed int> decltype(auto) _ = std::saturate_cast<signed int>(sBigMax);
+  { [[maybe_unused]] std::same_as<signed int> decltype(auto) _ = std::saturate_cast<signed int>(sBigMax); }
   assert(std::saturate_cast<signed int>( sBigMin)  == INT_MIN); // saturated
   assert(std::saturate_cast<signed int>(   sZero)  == 0);
   assert(std::saturate_cast<signed int>( sBigMax)  == INT_MAX); // saturated
 
-  std::same_as<signed int> decltype(auto) _ = std::saturate_cast<signed int>(uBigMax);
+  { [[maybe_unused]] std::same_as<signed int> decltype(auto) _ = std::saturate_cast<signed int>(uBigMax); }
   assert(std::saturate_cast<signed int>( uZero)    == 0);
   assert(std::saturate_cast<signed int>( uBigMax)  == INT_MAX); // saturated
 
   // long
 
-  std::same_as<signed long int> decltype(auto) _ = std::saturate_cast<signed long int>(SCHAR_MAX);
+  { [[maybe_unused]] std::same_as<signed long int> decltype(auto) _ = std::saturate_cast<signed long int>(SCHAR_MAX); }
   assert(std::saturate_cast<signed long int>(SCHAR_MIN) == static_cast<signed long int>(SCHAR_MIN));
   assert(std::saturate_cast<signed long int>(      O_C) == 0L);
   assert(std::saturate_cast<signed long int>(SCHAR_MAX) == static_cast<signed long int>(SCHAR_MAX));
 
-  std::same_as<signed long int> decltype(auto) _ = std::saturate_cast<signed long int>(UCHAR_MAX);
+  { [[maybe_unused]] std::same_as<signed long int> decltype(auto) _ = std::saturate_cast<signed long int>(UCHAR_MAX); }
   assert(std::saturate_cast<signed long int>(     O_UC) == 0L);
   assert(std::saturate_cast<signed long int>(UCHAR_MAX) == static_cast<signed long int>(UCHAR_MAX));
 
-  std::same_as<signed long int> decltype(auto) _ = std::saturate_cast<signed long int>(LONG_MAX);
+  { [[maybe_unused]] std::same_as<signed long int> decltype(auto) _ = std::saturate_cast<signed long int>(LONG_MAX); }
   assert(std::saturate_cast<signed long int>( LONG_MIN) == LONG_MIN);
   assert(std::saturate_cast<signed long int>(       0L) == 0L);
   assert(std::saturate_cast<signed long int>( LONG_MAX) == LONG_MAX);
 
-  std::same_as<signed long int> decltype(auto) _ = std::saturate_cast<signed long int>(ULONG_MAX);
+  { [[maybe_unused]] std::same_as<signed long int> decltype(auto) _ = std::saturate_cast<signed long int>(ULONG_MAX); }
   assert(std::saturate_cast<signed long int>(      0UL) == 0L);
   assert(std::saturate_cast<signed long int>(ULONG_MAX) == LONG_MAX); // saturated
 
-  std::same_as<signed long int> decltype(auto) _ = std::saturate_cast<signed long int>(sBigMax);
+  { [[maybe_unused]] std::same_as<signed long int> decltype(auto) _ = std::saturate_cast<signed long int>(sBigMax); }
   assert(std::saturate_cast<signed long int>(  sBigMin) == LONG_MIN); // saturated
   assert(std::saturate_cast<signed long int>(    sZero) == 0L);
   assert(std::saturate_cast<signed long int>(  sBigMax) == LONG_MAX); // saturated
 
-  std::same_as<signed long int> decltype(auto) _ = std::saturate_cast<signed long int>(uBigMax);
+  { [[maybe_unused]] std::same_as<signed long int> decltype(auto) _ = std::saturate_cast<signed long int>(uBigMax); }
   assert(std::saturate_cast<signed long int>(    uZero) == 0L);
   assert(std::saturate_cast<signed long int>(  uBigMax) == LONG_MAX); // saturated
 
   // long long
 
-  std::same_as<signed long long int> decltype(auto) _ = std::saturate_cast<signed long long int>(SCHAR_MAX);
+  { [[maybe_unused]] std::same_as<signed long long int> decltype(auto) _ = std::saturate_cast<signed long long int>(SCHAR_MAX); }
   assert(std::saturate_cast<signed long long int>(SCHAR_MIN) == static_cast<signed long long int>(SCHAR_MIN));
   assert(std::saturate_cast<signed long long int>(      0LL) == 0LL);
   assert(std::saturate_cast<signed long long int>(SCHAR_MAX) == static_cast<signed long long int>(SCHAR_MAX));
 
-    std::same_as<signed long long int> decltype(auto) _ = std::saturate_cast<signed long long int>(UCHAR_MAX);
+  { [[maybe_unused]]   std::same_as<signed long long int> decltype(auto) _ = std::saturate_cast<signed long long int>(UCHAR_MAX); }
   assert(std::saturate_cast<signed long long int>(     O_UC) == 0LL);
   assert(std::saturate_cast<signed long long int>(UCHAR_MAX) == static_cast<signed long long int>(UCHAR_MAX));
 
-  std::same_as<signed long long int> decltype(auto) _ = std::saturate_cast<signed long long int>(LLONG_MIN);
+  { [[maybe_unused]] std::same_as<signed long long int> decltype(auto) _ = std::saturate_cast<signed long long int>(LLONG_MIN); }
   assert(std::saturate_cast<signed long long int>(LLONG_MIN) == LLONG_MIN);
   assert(std::saturate_cast<signed long long int>(      0LL) == 0LL);
   assert(std::saturate_cast<signed long long int>(LLONG_MAX) == LLONG_MAX);
 
-  std::same_as<signed long long int> decltype(auto) _ = std::saturate_cast<signed long long int>(ULLONG_MAX);
+  { [[maybe_unused]] std::same_as<signed long long int> decltype(auto) _ = std::saturate_cast<signed long long int>(ULLONG_MAX); }
   assert(std::saturate_cast<signed long long int>(      0ULL) == 0LL);
   assert(std::saturate_cast<signed long long int>(ULLONG_MAX) == LLONG_MAX); // saturated
 
 #ifndef TEST_HAS_NO_INT128
-  std::same_as<signed long long int> decltype(auto) _ = std::saturate_cast<signed long long int>(sBigMax);
+  { [[maybe_unused]] std::same_as<signed long long int> decltype(auto) _ = std::saturate_cast<signed long long int>(sBigMax); }
   assert(std::saturate_cast<signed long long int>(   sBigMin) == LLONG_MIN); // (128-bit) saturated
   assert(std::saturate_cast<signed long long int>(     sZero) == 0LL);
   assert(std::saturate_cast<signed long long int>(   sBigMax) == LLONG_MAX); // (128-bit) saturated
 
-  std::same_as<signed long long int> decltype(auto) _ = std::saturate_cast<signed long long int>(uBigMax);
+  { [[maybe_unused]] std::same_as<signed long long int> decltype(auto) _ = std::saturate_cast<signed long long int>(uBigMax); }
   assert(std::saturate_cast<signed long long int>(     uZero) == 0LL);
   assert(std::saturate_cast<signed long long int>(   uBigMax) == LLONG_MAX); // (128-bit) saturated
 
-  std::same_as<__int128_t> decltype(auto) _ = std::saturate_cast<__int128_t>(SCHAR_MAX);
+  { [[maybe_unused]] std::same_as<__int128_t> decltype(auto) _ = std::saturate_cast<__int128_t>(SCHAR_MAX); }
   assert(std::saturate_cast<__int128_t>(SCHAR_MIN) == static_cast<__int128_t>(SCHAR_MIN));
   assert(std::saturate_cast<__int128_t>(      O_C) == sZero);
   assert(std::saturate_cast<__int128_t>(SCHAR_MAX) == static_cast<__int128_t>(SCHAR_MAX));
 
-  std::same_as<__int128_t> decltype(auto) _ = std::saturate_cast<__int128_t>(UCHAR_MAX);
+  { [[maybe_unused]] std::same_as<__int128_t> decltype(auto) _ = std::saturate_cast<__int128_t>(UCHAR_MAX); }
   assert(std::saturate_cast<__int128_t>(     O_UC) == sZero);
   assert(std::saturate_cast<__int128_t>(UCHAR_MAX) == static_cast<__int128_t>(UCHAR_MAX));
 
-  std::same_as<__int128_t> decltype(auto) _ = std::saturate_cast<__int128_t>(sBigMax);
+  { [[maybe_unused]] std::same_as<__int128_t> decltype(auto) _ = std::saturate_cast<__int128_t>(sBigMax); }
   assert(std::saturate_cast<__int128_t>(  sBigMin) == sBigMin);
   assert(std::saturate_cast<__int128_t>(    sZero) == sZero);
   assert(std::saturate_cast<__int128_t>(  sBigMax) == sBigMax);
 
-  std::same_as<__int128_t> decltype(auto) _ = std::saturate_cast<__int128_t>(uBigMax);
+  { [[maybe_unused]] std::same_as<__int128_t> decltype(auto) _ = std::saturate_cast<__int128_t>(uBigMax); }
   assert(std::saturate_cast<__int128_t>(    uZero) == sZero);
   assert(std::saturate_cast<__int128_t>(  uBigMax) == sBigMax); // saturated
 #endif
 
   // unsigned char
 
-  std::same_as<unsigned char> decltype(auto) _ = std::saturate_cast<unsigned char>(SCHAR_MAX);
+  { [[maybe_unused]] std::same_as<unsigned char> decltype(auto) _ = std::saturate_cast<unsigned char>(SCHAR_MAX); }
   assert(std::saturate_cast<unsigned char>(SCHAR_MIN) == O_UC);
   assert(std::saturate_cast<unsigned char>(      O_C) == O_UC);
   assert(std::saturate_cast<unsigned char>(SCHAR_MAX) == static_cast<unsigned char>(SCHAR_MAX));
 
-  std::same_as<unsigned char> decltype(auto) _ = std::saturate_cast<unsigned char>(UCHAR_MAX);
+  { [[maybe_unused]] std::same_as<unsigned char> decltype(auto) _ = std::saturate_cast<unsigned char>(UCHAR_MAX); }
   assert(std::saturate_cast<unsigned char>(     O_UC) == O_UC);
   assert(std::saturate_cast<unsigned char>(UCHAR_MAX) == UCHAR_MAX);
 
-  std::same_as<unsigned char> decltype(auto) _ = std::saturate_cast<unsigned char>(sBigMax);
+  { [[maybe_unused]] std::same_as<unsigned char> decltype(auto) _ = std::saturate_cast<unsigned char>(sBigMax); }
   assert(std::saturate_cast<unsigned char>(  sBigMin) == O_UC);      // saturated
   assert(std::saturate_cast<unsigned char>(    sZero) == O_UC);
   assert(std::saturate_cast<unsigned char>(  sBigMax) == UCHAR_MAX); // saturated
 
-  std::same_as<unsigned char> decltype(auto) _ = std::saturate_cast<unsigned char>(uBigMax);
+  { [[maybe_unused]] std::same_as<unsigned char> decltype(auto) _ = std::saturate_cast<unsigned char>(uBigMax); }
   assert(std::saturate_cast<unsigned char>(    uZero) == O_UC);
   assert(std::saturate_cast<unsigned char>(  uBigMax) == UCHAR_MAX); // saturated
 
   // unsigned short
 
-  std::same_as<unsigned short int> decltype(auto) _ = std::saturate_cast<unsigned short int>(SCHAR_MAX);
+  { [[maybe_unused]] std::same_as<unsigned short int> decltype(auto) _ = std::saturate_cast<unsigned short int>(SCHAR_MAX); }
   assert(std::saturate_cast<unsigned short int>(SCHAR_MIN) == O_US);
   assert(std::saturate_cast<unsigned short int>(      O_C) == O_US);
   assert(std::saturate_cast<unsigned short int>(SCHAR_MAX) == static_cast<unsigned short int>(SCHAR_MAX));
 
-  std::same_as<unsigned short int> decltype(auto) _ = std::saturate_cast<unsigned short int>(UCHAR_MAX);
+  { [[maybe_unused]] std::same_as<unsigned short int> decltype(auto) _ = std::saturate_cast<unsigned short int>(UCHAR_MAX); }
   assert(std::saturate_cast<unsigned short int>(     O_UC) == O_US);
   assert(std::saturate_cast<unsigned short int>(UCHAR_MAX) == static_cast<unsigned short int>(UCHAR_MAX));
 
-  std::same_as<unsigned short int> decltype(auto) _ = std::saturate_cast<unsigned short int>(SCHAR_MIN);
+  { [[maybe_unused]] std::same_as<unsigned short int> decltype(auto) _ = std::saturate_cast<unsigned short int>(SCHAR_MIN); }
   assert(std::saturate_cast<unsigned short int>( SHRT_MIN) == O_US);
   assert(std::saturate_cast<unsigned short int>(      O_S) == O_US);
   assert(std::saturate_cast<unsigned short int>( SHRT_MAX) == static_cast<unsigned short int>(SHRT_MAX));
 
-  std::same_as<unsigned short int> decltype(auto) _ = std::saturate_cast<unsigned short int>(UCHAR_MAX);
+  { [[maybe_unused]] std::same_as<unsigned short int> decltype(auto) _ = std::saturate_cast<unsigned short int>(UCHAR_MAX); }
   assert(std::saturate_cast<unsigned short int>(     O_US) == O_US);
   assert(std::saturate_cast<unsigned short int>(USHRT_MAX) == USHRT_MAX);
 
-  std::same_as<unsigned short int> decltype(auto) _ = std::saturate_cast<unsigned short int>(sBigMax);
+  { [[maybe_unused]] std::same_as<unsigned short int> decltype(auto) _ = std::saturate_cast<unsigned short int>(sBigMax); }
   assert(std::saturate_cast<unsigned short int>(  sBigMin) == O_US);      // saturated
   assert(std::saturate_cast<unsigned short int>(    sZero) == O_US);
   assert(std::saturate_cast<unsigned short int>(  sBigMax) == USHRT_MAX); // saturated
 
-  std::same_as<unsigned short int> decltype(auto) _ = std::saturate_cast<unsigned short int>(uBigMax);
+  { [[maybe_unused]] std::same_as<unsigned short int> decltype(auto) _ = std::saturate_cast<unsigned short int>(uBigMax); }
   assert(std::saturate_cast<unsigned short int>(    uZero) == O_US);
   assert(std::saturate_cast<unsigned short int>(  uBigMax) == USHRT_MAX); // saturated
 
   // unsigned int
 
-  std::same_as<unsigned int> decltype(auto) _ = std::saturate_cast<unsigned int>(SCHAR_MAX);
+  { [[maybe_unused]] std::same_as<unsigned int> decltype(auto) _ = std::saturate_cast<unsigned int>(SCHAR_MAX); }
   assert(std::saturate_cast<unsigned int>(SCHAR_MIN) == O_US);
   assert(std::saturate_cast<unsigned int>(     O_UC) == 0U);
   assert(std::saturate_cast<unsigned int>(SCHAR_MAX) == static_cast<unsigned int>(SCHAR_MAX));
 
-  std::same_as<unsigned int> decltype(auto) _ = std::saturate_cast<unsigned int>(UCHAR_MAX);
+  { [[maybe_unused]] std::same_as<unsigned int> decltype(auto) _ = std::saturate_cast<unsigned int>(UCHAR_MAX); }
   assert(std::saturate_cast<unsigned int>(     O_UC) == 0U);
   assert(std::saturate_cast<unsigned int>(UCHAR_MAX) == static_cast<unsigned int>(UCHAR_MAX));
 
-  std::same_as<unsigned int> decltype(auto) _ = std::saturate_cast<unsigned int>(INT_MAX);
+  { [[maybe_unused]] std::same_as<unsigned int> decltype(auto) _ = std::saturate_cast<unsigned int>(INT_MAX); }
   assert(std::saturate_cast<unsigned int>(  INT_MIN) == 0U);
   assert(std::saturate_cast<unsigned int>(        0) == 0U);
   assert(std::saturate_cast<unsigned int>(  INT_MAX) == static_cast<unsigned int>(INT_MAX));
 
-  std::same_as<unsigned int> decltype(auto) _ = std::saturate_cast<unsigned int>(UINT_MAX);
+  { [[maybe_unused]] std::same_as<unsigned int> decltype(auto) _ = std::saturate_cast<unsigned int>(UINT_MAX); }
   assert(std::saturate_cast<unsigned int>(       0U) == 0U);
   assert(std::saturate_cast<unsigned int>( UINT_MAX) == UINT_MAX);
 
-  std::same_as<unsigned int> decltype(auto) _ = std::saturate_cast<unsigned int>(sBigMax);
+  { [[maybe_unused]] std::same_as<unsigned int> decltype(auto) _ = std::saturate_cast<unsigned int>(sBigMax); }
   assert(std::saturate_cast<unsigned int>(  sBigMin) == 0U);       // saturated
   assert(std::saturate_cast<unsigned int>(    sZero) == 0U);
   assert(std::saturate_cast<unsigned int>(  sBigMax) == UINT_MAX); // saturated
-
-  std::same_as<unsigned int> decltype(auto) _ = std::saturate_cast<unsigned int>(uBigMax);
+  
+  { [[maybe_unused]] std::same_as<unsigned int> decltype(auto) _ = std::saturate_cast<unsigned int>(uBigMax); }
   assert(std::saturate_cast<unsigned int>(    uZero) == 0U);
   assert(std::saturate_cast<unsigned int>(  uBigMax) == UINT_MAX);  // saturated
 
   // unsigned long
 
-  std::same_as<unsigned long int> decltype(auto) _ = std::saturate_cast<unsigned long int>(SCHAR_MAX);
+  { [[maybe_unused]] std::same_as<unsigned long int> decltype(auto) _ = std::saturate_cast<unsigned long int>(SCHAR_MAX); }
   assert(std::saturate_cast<unsigned long int>(SCHAR_MIN) == 0UL);
   assert(std::saturate_cast<unsigned long int>(      O_C) == 0UL);
   assert(std::saturate_cast<unsigned long int>(SCHAR_MAX) == static_cast<unsigned long int>(SCHAR_MAX));
 
-  std::same_as<unsigned long int> decltype(auto) _ = std::saturate_cast<unsigned long int>(UCHAR_MAX);
+  { [[maybe_unused]] std::same_as<unsigned long int> decltype(auto) _ = std::saturate_cast<unsigned long int>(UCHAR_MAX); }
   assert(std::saturate_cast<unsigned long int>(     O_UC) == 0UL);
   assert(std::saturate_cast<unsigned long int>(UCHAR_MAX) == static_cast<unsigned long int>(UCHAR_MAX));
 
-  std::same_as<unsigned long int> decltype(auto) _ = std::saturate_cast<unsigned long int>(LONG_MAX);
+  { [[maybe_unused]] std::same_as<unsigned long int> decltype(auto) _ = std::saturate_cast<unsigned long int>(LONG_MAX); }
   assert(std::saturate_cast<unsigned long int>( LONG_MIN) == 0UL);
   assert(std::saturate_cast<unsigned long int>(       0L) == 0UL);
   assert(std::saturate_cast<unsigned long int>( LONG_MAX) == static_cast<unsigned long int>(LONG_MAX));
 
-  std::same_as<unsigned long int> decltype(auto) _ = std::saturate_cast<unsigned long int>(ULONG_MAX);
+  { [[maybe_unused]] std::same_as<unsigned long int> decltype(auto) _ = std::saturate_cast<unsigned long int>(ULONG_MAX); }
   assert(std::saturate_cast<unsigned long int>(      0UL) == 0UL);
   assert(std::saturate_cast<unsigned long int>(ULONG_MAX) == ULONG_MAX);
 
-  std::same_as<unsigned long int> decltype(auto) _ = std::saturate_cast<unsigned long int>(sBigMax);
+  { [[maybe_unused]] std::same_as<unsigned long int> decltype(auto) _ = std::saturate_cast<unsigned long int>(sBigMax); }
   assert(std::saturate_cast<unsigned long int>(  sBigMin) == 0UL);       // saturated
   assert(std::saturate_cast<unsigned long int>(    sZero) == 0UL);
   assert(std::saturate_cast<unsigned long int>(  sBigMax) == (sizeof(UIntT) > sizeof(unsigned long int) ? ULONG_MAX : LONG_MAX)); // saturated depending on underlying types
 
-  std::same_as<unsigned long int> decltype(auto) _ = std::saturate_cast<unsigned long int>(uBigMax);
+  { [[maybe_unused]] std::same_as<unsigned long int> decltype(auto) _ = std::saturate_cast<unsigned long int>(uBigMax); }
   assert(std::saturate_cast<unsigned long int>(    uZero) == 0UL);
   assert(std::saturate_cast<unsigned long int>(  uBigMax) == ULONG_MAX); // saturated
 
   // unsigned long long
 
-  std::same_as<unsigned long long int> decltype(auto) _ = std::saturate_cast<unsigned long long int>(SCHAR_MAX);
+  { [[maybe_unused]] std::same_as<unsigned long long int> decltype(auto) _ = std::saturate_cast<unsigned long long int>(SCHAR_MAX); }
   assert(std::saturate_cast<unsigned long long int>( SCHAR_MIN) == 0ULL);
   assert(std::saturate_cast<unsigned long long int>(       O_C) == 0ULL);
   assert(std::saturate_cast<unsigned long long int>( SCHAR_MAX) == static_cast<unsigned long long int>(SCHAR_MAX));
 
-  std::same_as<unsigned long long  int> decltype(auto) _ = std::saturate_cast<unsigned long long int>(UCHAR_MAX);
+  { [[maybe_unused]] std::same_as<unsigned long long  int> decltype(auto) _ = std::saturate_cast<unsigned long long int>(UCHAR_MAX); }
   assert(std::saturate_cast<unsigned long long int>(      O_UC) == 0ULL);
   assert(std::saturate_cast<unsigned long long int>( UCHAR_MAX) == static_cast<unsigned long long int>(UCHAR_MAX));
 
-  std::same_as<unsigned long long int> decltype(auto) _ = std::saturate_cast<unsigned long long int>(LLONG_MAX);
+  { [[maybe_unused]] std::same_as<unsigned long long int> decltype(auto) _ = std::saturate_cast<unsigned long long int>(LLONG_MAX); }
   assert(std::saturate_cast<unsigned long long int>( LLONG_MIN) == 0ULL);
   assert(std::saturate_cast<unsigned long long int>(       0LL) == 0ULL);
   assert(std::saturate_cast<unsigned long long int>( LLONG_MAX) == static_cast<unsigned long long int>(LLONG_MAX));
 
-  std::same_as<unsigned long long int> decltype(auto) _ = std::saturate_cast<unsigned long long int>(ULLONG_MAX);
+  { [[maybe_unused]] std::same_as<unsigned long long int> decltype(auto) _ = std::saturate_cast<unsigned long long int>(ULLONG_MAX); }
   assert(std::saturate_cast<unsigned long long int>(      0ULL) == 0ULL);
   assert(std::saturate_cast<unsigned long long int>(ULLONG_MAX) == ULLONG_MAX);
 
 #ifndef TEST_HAS_NO_INT128
-  std::same_as<unsigned long long int> decltype(auto) _ = std::saturate_cast<unsigned long long int>(sBigMax);
+  { [[maybe_unused]] std::same_as<unsigned long long int> decltype(auto) _ = std::saturate_cast<unsigned long long int>(sBigMax); }
   assert(std::saturate_cast<unsigned long long int>(   sBigMin) == 0ULL);       // (128-bit) saturated
   assert(std::saturate_cast<unsigned long long int>(     sZero) == 0ULL);
   assert(std::saturate_cast<unsigned long long int>(   sBigMax) == ULLONG_MAX); // (128-bit) saturated
 
-  std::same_as<unsigned long long int> decltype(auto) _ = std::saturate_cast<unsigned long long int>(uBigMax);
+  { [[maybe_unused]] std::same_as<unsigned long long int> decltype(auto) _ = std::saturate_cast<unsigned long long int>(uBigMax); }
   assert(std::saturate_cast<unsigned long long int>(     uZero) == 0ULL);
   assert(std::saturate_cast<unsigned long long int>(   uBigMax) == ULLONG_MAX); // (128-bit) saturated
 
-  std::same_as<__uint128_t> decltype(auto) _ = std::saturate_cast<__uint128_t>(SCHAR_MIN);
+  { [[maybe_unused]] std::same_as<__uint128_t> decltype(auto) _ = std::saturate_cast<__uint128_t>(SCHAR_MIN); }
   assert(std::saturate_cast<__uint128_t>(SCHAR_MIN) == uZero);
   assert(std::saturate_cast<__uint128_t>(      O_C) == uZero);
   assert(std::saturate_cast<__uint128_t>(SCHAR_MAX) == static_cast<__uint128_t>(SCHAR_MAX));
 
-  std::same_as<__uint128_t> decltype(auto) _ = std::saturate_cast<__uint128_t>(UCHAR_MAX);
+  { [[maybe_unused]] std::same_as<__uint128_t> decltype(auto) _ = std::saturate_cast<__uint128_t>(UCHAR_MAX); }
   assert(std::saturate_cast<__uint128_t>(     O_UC) == uZero);
   assert(std::saturate_cast<__uint128_t>(UCHAR_MAX) == static_cast<__uint128_t>(UCHAR_MAX));
 
-  std::same_as<__uint128_t> decltype(auto) _ = std::saturate_cast<__uint128_t>(sBigMax);
+  { [[maybe_unused]] std::same_as<__uint128_t> decltype(auto) _ = std::saturate_cast<__uint128_t>(sBigMax); }
   assert(std::saturate_cast<__uint128_t>(  sBigMin) == uZero); // saturated
   assert(std::saturate_cast<__uint128_t>(    sZero) == uZero);
   assert(std::saturate_cast<__uint128_t>(  sBigMax) == static_cast<__uint128_t>(sBigMax));
 
-  std::same_as<__uint128_t> decltype(auto) _ = std::saturate_cast<__uint128_t>(uBigMax);
+  { [[maybe_unused]] std::same_as<__uint128_t> decltype(auto) _ = std::saturate_cast<__uint128_t>(uBigMax); }
   assert(std::saturate_cast<__uint128_t>(    uZero) == uZero);
   assert(std::saturate_cast<__uint128_t>(  uBigMax) == uBigMax);
 #endif
diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/sub_sat.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/sub_sat.pass.cpp
index fe4255c1f7a6b8..d7bdf2c0271acf 100644
--- a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/sub_sat.pass.cpp
+++ b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/sub_sat.pass.cpp
@@ -26,7 +26,8 @@ constexpr bool test_signed() {
   constexpr auto minVal = std::numeric_limits<IntegerT>::min();
   constexpr auto maxVal = std::numeric_limits<IntegerT>::max();
 
-  std::same_as<IntegerT> decltype(auto) _ = std::sub_sat(minVal, maxVal);
+  // TODO(LLVM-20) remove [[maybe_unused]] since all supported compilers support "Placeholder variables with no name"
+  [[maybe_unused]] std::same_as<IntegerT> decltype(auto) _ = std::sub_sat(minVal, maxVal);
 
   static_assert(noexcept(std::sub_sat(minVal, maxVal)));
 
@@ -88,7 +89,8 @@ constexpr bool test_unsigned() {
   constexpr auto minVal = std::numeric_limits<IntegerT>::min();
   constexpr auto maxVal = std::numeric_limits<IntegerT>::max();
 
-  std::same_as<IntegerT> decltype(auto) _ = std::sub_sat(minVal, maxVal);
+  // TODO(LLVM-20) remove [[maybe_unused]] since all supported compilers support "Placeholder variables with no name"
+  [[maybe_unused]] std::same_as<IntegerT> decltype(auto) _ = std::sub_sat(minVal, maxVal);
 
   static_assert(noexcept(std::sub_sat(minVal, maxVal)));
 
diff --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.copy.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.copy.pass.cpp
index 32560bf8fac35b..9e78596929fb62 100644
--- a/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.copy.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.copy.pass.cpp
@@ -121,10 +121,13 @@ constexpr bool test() {
   }
 
   {
+    // TODO(LLVM 20): Remove once we drop support for Clang 17
+#if defined(TEST_CLANG_VER) && TEST_CLANG_VER >= 1800
     // https://github.com/llvm/llvm-project/issues/92676
     std::expected<Any, int> e1;
     auto e2 = e1;
     assert(e2.has_value());
+#endif
   }
 
   return true;
diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg/visit.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg/visit.pass.cpp
index 20e0a5ed66bd05..829b74121b9c6b 100644
--- a/libcxx/test/std/utilities/format/format.arguments/format.arg/visit.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.arguments/format.arg/visit.pass.cpp
@@ -9,6 +9,7 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
 // UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
 // The tested functionality needs deducing this.
+// UNSUPPORTED: clang-17
 // XFAIL: apple-clang
 
 // <format>
diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg/visit.return_type.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg/visit.return_type.pass.cpp
index 8a79dd4d50f20d..874d609432f221 100644
--- a/libcxx/test/std/utilities/format/format.arguments/format.arg/visit.return_type.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.arguments/format.arg/visit.return_type.pass.cpp
@@ -9,6 +9,7 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
 // UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
 // The tested functionality needs deducing this.
+// UNSUPPORTED: clang-17
 // XFAIL: apple-clang
 
 // <format>
diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg/visit_format_arg.deprecated.verify.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg/visit_format_arg.deprecated.verify.cpp
index 146ceba58872e2..e3e3e9a19e122f 100644
--- a/libcxx/test/std/utilities/format/format.arguments/format.arg/visit_format_arg.deprecated.verify.cpp
+++ b/libcxx/test/std/utilities/format/format.arguments/format.arg/visit_format_arg.deprecated.verify.cpp
@@ -8,6 +8,7 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
 // UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
+// UNSUPPORTED: clang-17
 // XFAIL: apple-clang
 
 // <format>
diff --git a/libcxx/test/std/utilities/meta/meta.rel/is_virtual_base_of.pass.cpp b/libcxx/test/std/utilities/meta/meta.rel/is_virtual_base_of.pass.cpp
index f443d2030961d1..6b34d56e2c6f45 100644
--- a/libcxx/test/std/utilities/meta/meta.rel/is_virtual_base_of.pass.cpp
+++ b/libcxx/test/std/utilities/meta/meta.rel/is_virtual_base_of.pass.cpp
@@ -9,7 +9,7 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
 
 // These compilers don't support __builtin_is_virtual_base_of yet.
-// UNSUPPORTED: clang-18, clang-19, gcc-14, apple-clang-16, apple-clang-17
+// UNSUPPORTED: clang-17, clang-18, clang-19, gcc-14, apple-clang-16, apple-clang-17
 
 // <type_traits>
 
diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/nttp.equivalence.compile.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/nttp.equivalence.compile.pass.cpp
index f5fd5a674882bd..db45a56feb88aa 100644
--- a/libcxx/test/std/utilities/utility/pairs/pairs.pair/nttp.equivalence.compile.pass.cpp
+++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/nttp.equivalence.compile.pass.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: clang-17
 
 // <utility>
 
diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/nttp.verify.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/nttp.verify.cpp
index 499ba6b243bed4..ac081495a62052 100644
--- a/libcxx/test/std/utilities/utility/pairs/pairs.pair/nttp.verify.cpp
+++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/nttp.verify.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: clang-17
 
 // <utility>
 
diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp
index 8a8d41547fbec1..bea6d949924bd8 100644
--- a/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp
@@ -8,6 +8,7 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
 // The tested functionality needs deducing this.
+// UNSUPPORTED: clang-17
 // XFAIL: apple-clang
 
 // <variant>
diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp
index f68112d30fc35d..0da23fd58ccaa7 100644
--- a/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp
@@ -8,6 +8,7 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
 // The tested functionality needs deducing this.
+// UNSUPPORTED: clang-17
 // XFAIL: apple-clang
 
 // <variant>
diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp
index 8093af0aba587c..7429cdf80facaa 100644
--- a/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp
@@ -8,6 +8,7 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
 // The tested functionality needs deducing this.
+// UNSUPPORTED: clang-17
 // XFAIL: apple-clang
 
 // <variant>



More information about the libcxx-commits mailing list