diff --git a/libcxx/docs/Status/Cxx17Issues.csv b/libcxx/docs/Status/Cxx17Issues.csv
index d09b37f1d3900..3ca3e22845cfd 100644
--- a/libcxx/docs/Status/Cxx17Issues.csv
+++ b/libcxx/docs/Status/Cxx17Issues.csv
@@ -252,6 +252,7 @@
 "`LWG2760 <https://wg21.link/LWG2760>`__","non-const basic_string::data should not invalidate iterators","2016-11 (Issaquah)","|Complete|","",""
 "`LWG2765 <https://wg21.link/LWG2765>`__","Did LWG 1123 go too far?","2016-11 (Issaquah)","|Complete|","",""
 "`LWG2767 <https://wg21.link/LWG2767>`__","not_fn call_wrapper can form invalid types","2016-11 (Issaquah)","|Complete|","",""
+"`LWG2770 <https://wg21.link/LWG2770>`__","``tuple_size<const T>`` specialization is not SFINAE compatible and breaks decomposition declarations","2016-11 (Issaquah)","|Complete|","21",""
 "`LWG2771 <https://wg21.link/LWG2771>`__","Broken Effects of some basic_string::compare functions in terms of basic_string_view","2016-11 (Issaquah)","|Complete|","",""
 "`LWG2773 <https://wg21.link/LWG2773>`__","Making std::ignore constexpr","2016-11 (Issaquah)","|Complete|","",""
 "`LWG2777 <https://wg21.link/LWG2777>`__","basic_string_view::copy should use char_traits::copy","2016-11 (Issaquah)","|Complete|","",""
diff --git a/libcxx/include/__tuple/tuple_size.h b/libcxx/include/__tuple/tuple_size.h
index 27d57eb56ba6b..035ffa3655bc1 100644
--- a/libcxx/include/__tuple/tuple_size.h
+++ b/libcxx/include/__tuple/tuple_size.h
@@ -32,20 +32,17 @@ template <class _Tp, class...>
 using __enable_if_tuple_size_imp _LIBCPP_NODEBUG = _Tp;
 
 template <class _Tp>
-struct _LIBCPP_TEMPLATE_VIS tuple_size<__enable_if_tuple_size_imp< const _Tp,
-                                                                   __enable_if_t<!is_volatile<_Tp>::value>,
-                                                                   integral_constant<size_t, sizeof(tuple_size<_Tp>)>>>
+struct _LIBCPP_TEMPLATE_VIS tuple_size<
+    __enable_if_tuple_size_imp<const _Tp, __enable_if_t<!is_volatile<_Tp>::value>, decltype(tuple_size<_Tp>::value)>>
     : public integral_constant<size_t, tuple_size<_Tp>::value> {};
 
 template <class _Tp>
-struct _LIBCPP_TEMPLATE_VIS tuple_size<__enable_if_tuple_size_imp< volatile _Tp,
-                                                                   __enable_if_t<!is_const<_Tp>::value>,
-                                                                   integral_constant<size_t, sizeof(tuple_size<_Tp>)>>>
+struct _LIBCPP_TEMPLATE_VIS tuple_size<
+    __enable_if_tuple_size_imp<volatile _Tp, __enable_if_t<!is_const<_Tp>::value>, decltype(tuple_size<_Tp>::value)>>
     : public integral_constant<size_t, tuple_size<_Tp>::value> {};
 
 template <class _Tp>
-struct _LIBCPP_TEMPLATE_VIS
-tuple_size<__enable_if_tuple_size_imp<const volatile _Tp, integral_constant<size_t, sizeof(tuple_size<_Tp>)>>>
+struct _LIBCPP_TEMPLATE_VIS tuple_size<__enable_if_tuple_size_imp<const volatile _Tp, decltype(tuple_size<_Tp>::value)>>
     : public integral_constant<size_t, tuple_size<_Tp>::value> {};
 
 #else
diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_incomplete.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_incomplete.pass.cpp
index a2cb2e989a571..bef4486d586b3 100644
--- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_incomplete.pass.cpp
+++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_incomplete.pass.cpp
@@ -45,9 +45,11 @@ void test_complete() {
 template <class T>
 void test_incomplete() {
   static_assert(!is_complete<T>(), "");
-  static_assert(!is_complete<const T>(), "");
-  static_assert(!is_complete<volatile T>(), "");
-  static_assert(!is_complete<const volatile T>(), "");
+  // https://cplusplus.github.io/LWG/issue4040
+  // It is controversial whether these specializations are incomplete.
+  LIBCPP_STATIC_ASSERT(!is_complete<const T>(), "");
+  LIBCPP_STATIC_ASSERT(!is_complete<volatile T>(), "");
+  LIBCPP_STATIC_ASSERT(!is_complete<const volatile T>(), "");
 }
 
 
diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_incomplete.verify.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_incomplete.verify.cpp
index 532ccd730ffc1..cc6af820c930b 100644
--- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_incomplete.verify.cpp
+++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_incomplete.verify.cpp
@@ -23,6 +23,8 @@
 struct Dummy1 {};
 struct Dummy2 {};
 struct Dummy3 {};
+struct Dummy4 {};
+struct Dummy5 {};
 
 template <>
 struct std::tuple_size<Dummy1> {
@@ -39,6 +41,16 @@ struct std::tuple_size<Dummy2> {
 template <>
 struct std::tuple_size<Dummy3> {};
 
+template <>
+struct std::tuple_size<Dummy4> {
+  void value();
+};
+
+template <>
+struct std::tuple_size<Dummy5> {
+  size_t value;
+};
+
 void f() {
   // Test that tuple_size<const T> is not incomplete when tuple_size<T>::value
   // is well-formed but not a constant expression.
@@ -53,9 +65,21 @@ void f() {
     (void)std::tuple_size<const Dummy2>::value; // expected-note {{here}}
   }
   // Test that tuple_size<const T> generates an error when tuple_size<T> is
-  // complete but ::value isn't a constant expression convertible to size_t.
+  // complete but has no ::value member.
+  {
+    // expected-error@*:* 1 {{implicit instantiation of undefined template}}
+    (void)std::tuple_size<const Dummy3>::value;
+  }
+  // Test that tuple_size<const T> generates an error when tuple_size<T> has
+  // the ::value member but tuple_size<T>::value is ill-formed.
+  {
+    // expected-error@*:* 1 {{implicit instantiation of undefined template}}
+    (void)std::tuple_size<const Dummy4>::value;
+  }
+  // Test that tuple_size<const T> generates an error when tuple_size<T> has
+  // the ::value member which is non-static.
   {
-    // expected-error@*:* 1 {{no member named 'value'}}
-    (void)std::tuple_size<const Dummy3>::value; // expected-note {{here}}
+    // expected-error@*:* 1 {{invalid use of non-static data member 'value'}}
+    (void)std::tuple_size<const Dummy5>::value; // expected-note {{here}}
   }
 }
diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_structured_bindings.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_structured_bindings.pass.cpp
index 2324da3ad5f3c..77dcd034001aa 100644
--- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_structured_bindings.pass.cpp
+++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_structured_bindings.pass.cpp
@@ -109,6 +109,36 @@ void test_decomp_array() {
   }
 }
 
+struct TestLWG2770 {
+  int n;
+};
+
+template <>
+struct std::tuple_size<TestLWG2770> {};
+
+void test_lwg_2770() {
+  {
+    auto [n] = TestLWG2770{42};
+    assert(n == 42);
+  }
+  {
+    const auto [n] = TestLWG2770{42};
+    assert(n == 42);
+  }
+  {
+    TestLWG2770 s{42};
+    auto& [n] = s;
+    assert(n == 42);
+    assert(&n == &s.n);
+  }
+  {
+    const TestLWG2770 s{42};
+    auto& [n] = s;
+    assert(n == 42);
+    assert(&n == &s.n);
+  }
+}
+
 struct Test {
   int x;
 };
@@ -136,16 +166,49 @@ struct std::tuple_size<Test> {
 void test_after_tuple_size_specialization() {
   Test const t{99};
   auto& [p] = t;
-  assert(p == -1);
+  // https://cplusplus.github.io/LWG/issue4040
+  // It is controversial whether std::tuple_size<const Test> is instantiated here or before.
+  (void)p;
+  LIBCPP_ASSERT(p == -1);
+}
+
+#if TEST_STD_VER >= 26 && __cpp_structured_bindings >= 202411L
+struct InvalidWhenNoCv1 {};
+
+template <>
+struct std::tuple_size<InvalidWhenNoCv1> {};
+
+struct InvalidWhenNoCv2 {};
+
+template <>
+struct std::tuple_size<InvalidWhenNoCv2> {
+  void value();
+};
+
+template <class = void>
+void test_decomp_as_empty_pack() {
+  {
+    const auto [... pack] = InvalidWhenNoCv1{};
+    static_assert(sizeof...(pack) == 0);
+  }
+  {
+    const auto [... pack] = InvalidWhenNoCv2{};
+    static_assert(sizeof...(pack) == 0);
+  }
 }
+#endif
 
 int main(int, char**) {
   test_decomp_user_type();
   test_decomp_tuple();
   test_decomp_pair();
   test_decomp_array();
+  test_lwg_2770();
   test_before_tuple_size_specialization();
   test_after_tuple_size_specialization();
+#if TEST_STD_VER >= 26 && __cpp_structured_bindings >= 202411L
+  test_decomp_as_empty_pack();
+#endif
 
   return 0;
 }