https://gcc.gnu.org/g:bc8f5424977b74e107543b34af00768cdbb3a3cf

commit r16-1653-gbc8f5424977b74e107543b34af00768cdbb3a3cf
Author: Patrick Palka <ppa...@redhat.com>
Date:   Tue Jun 24 09:33:25 2025 -0400

    libstdc++: Unnecessary type completion in __is_complete_or_unbounded 
[PR120717]
    
    When checking __is_complete_or_unbounded on a reference to incomplete
    type, we overeagerly try to instantiate/complete the referenced type
    which besides being unnecessary may also produce an unexpected
    -Wsfinae-incomplete warning (added in r16-1527) if the referenced type
    is later defined.
    
    This patch fixes this by effectively restricting the sizeof check to
    object (except unknown-bound array) types.  In passing simplify the
    implementation by using is_object instead of is_function/reference/void
    and introducing a __maybe_complete_object_type helper.
    
            PR libstdc++/120717
    
    libstdc++-v3/ChangeLog:
    
            * include/std/type_traits (__maybe_complete_object_type): New
            helper trait, factored out from ...
            (__is_complete_or_unbounded): ... here.  Only check sizeof on a
            __maybe_complete_object_type type.  Fix formatting.
            * testsuite/20_util/is_complete_or_unbounded/120717.cc: New test.
    
    Reviewed-by: Tomasz KamiƄski <tkami...@redhat.com>
    Co-authored-by: Jonathan Wakely <jwak...@redhat.com>
    Reviewed-by: Jonathan Wakely <jwak...@redhat.com>

Diff:
---
 libstdc++-v3/include/std/type_traits               | 39 ++++++++++++----------
 .../20_util/is_complete_or_unbounded/120717.cc     | 20 +++++++++++
 2 files changed, 42 insertions(+), 17 deletions(-)

diff --git a/libstdc++-v3/include/std/type_traits 
b/libstdc++-v3/include/std/type_traits
index abff9f880001..055411195f17 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -280,11 +280,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Forward declarations
   template<typename>
-    struct is_reference;
-  template<typename>
-    struct is_function;
-  template<typename>
-    struct is_void;
+    struct is_object;
   template<typename>
     struct remove_cv;
   template<typename>
@@ -294,21 +290,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename>
     struct __is_array_unknown_bounds;
 
+  // An object type which is not an unbounded array.
+  // It might still be an incomplete type, but if this is false_type
+  // then we can be certain it's not a complete object type.
+  template<typename _Tp>
+    using __maybe_complete_object_type
+      = __and_<is_object<_Tp>, __not_<__is_array_unknown_bounds<_Tp>>>;
+
   // Helper functions that return false_type for incomplete classes,
   // incomplete unions and arrays of known bound from those.
 
-  template <typename _Tp, size_t = sizeof(_Tp)>
-    constexpr true_type __is_complete_or_unbounded(__type_identity<_Tp>)
-    { return {}; }
-
-  template <typename _TypeIdentity,
-      typename _NestedType = typename _TypeIdentity::type>
-    constexpr typename __or_<
-      is_reference<_NestedType>,
-      is_function<_NestedType>,
-      is_void<_NestedType>,
-      __is_array_unknown_bounds<_NestedType>
-    >::type __is_complete_or_unbounded(_TypeIdentity)
+  // More specialized overload for complete object types (returning true_type).
+  template<typename _Tp,
+          typename = __enable_if_t<__maybe_complete_object_type<_Tp>::value>,
+          size_t = sizeof(_Tp)>
+    constexpr true_type
+    __is_complete_or_unbounded(__type_identity<_Tp>)
+    { return {}; };
+
+  // Less specialized overload for reference and unknown-bound array types
+  // (returning true_type), and incomplete types (returning false_type).
+  template<typename _TypeIdentity,
+          typename _NestedType = typename _TypeIdentity::type>
+    constexpr typename __not_<__maybe_complete_object_type<_NestedType>>::type
+    __is_complete_or_unbounded(_TypeIdentity)
     { return {}; }
 
   // __remove_cv_t (std::remove_cv_t for C++11).
diff --git a/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/120717.cc 
b/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/120717.cc
new file mode 100644
index 000000000000..4c07683d494e
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/120717.cc
@@ -0,0 +1,20 @@
+// PR libstdc++/120717
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-Wsfinae-incomplete" }
+
+#include <type_traits>
+
+// Verify __is_complete_or_unbounded doesn't try to instantiate the underlying
+// type of a reference or array of unknown bound.
+template<class T> struct A { static_assert(false, "do not instantiate"); };
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<A<int>&>{}),
 "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<A<int>&&>{}),
 "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<A<int>[]>{}),
 "");
+
+// Verify __is_complete_or_unbounded doesn't produce unexpected
+// -Wsfinae-incomplete warnings.
+struct B;
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<B&>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<B&&>{}), 
"");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<B[]>{}), 
"");
+struct B { }; // { dg-bogus "-Wsfinae-incomplete" }

Reply via email to