[v7,5/6] c++, libstdc++: implement __is_void built-in trait

Message ID 20230612224909.21188-6-kmatsui@cs.washington.edu
State Superseded
Headers
Series c++, libstdc++: get std::is_object to dispatch to new built-in traits |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 success Testing passed

Commit Message

Ken Matsui June 12, 2023, 10:47 p.m. UTC
  This patch implements built-in trait for std::is_void. Since the new built-in
name is __is_void, to avoid unintentional macro replacement, this patch also
involves the removal of the existing __is_void in helper_functions.h and
cpp_type_traits.h and renaming __is_void to ____is_void in the test file,
pr46567.C.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_void.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_VOID.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/tm/pr46567.C (__is_void): Rename to ...
	(____is_void): ... this.
	* g++.dg/ext/has-builtin-1.C: Test existence of __is_void.
	* g++.dg/ext/is_void.C: New test.

libstdc++-v3/ChangeLog:

	* include/debug/helper_functions.h (_DiffTraits): Stop using
	__is_void.
	* include/bits/cpp_type_traits.h (__is_void): Remove unused __is_void.
	* include/std/type_traits (is_void_v): Use __is_void built-in
	trait.

Signed-off-by: Ken Matsui <kmatsui@cs.washington.edu>
---
 gcc/cp/constraint.cc                          |  3 ++
 gcc/cp/cp-trait.def                           |  1 +
 gcc/cp/semantics.cc                           |  4 +++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      |  3 ++
 gcc/testsuite/g++.dg/ext/is_void.C            | 35 +++++++++++++++++++
 gcc/testsuite/g++.dg/tm/pr46567.C             |  6 ++--
 libstdc++-v3/include/bits/cpp_type_traits.h   | 15 --------
 libstdc++-v3/include/debug/helper_functions.h |  5 ++-
 libstdc++-v3/include/std/type_traits          |  6 ++++
 9 files changed, 57 insertions(+), 21 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_void.C
  

Comments

Patrick Palka June 20, 2023, 4 p.m. UTC | #1
On Mon, 12 Jun 2023, Ken Matsui via Libstdc++ wrote:

> This patch implements built-in trait for std::is_void. Since the new built-in
> name is __is_void, to avoid unintentional macro replacement, this patch also
> involves the removal of the existing __is_void in helper_functions.h and
> cpp_type_traits.h and renaming __is_void to ____is_void in the test file,
> pr46567.C.

Hmm, I suspect an __is_void built-in won't show an improvement over
the current is_void implementation in terms of four explicit specializations.
And given the __is_void name conflict in cpp_type_traits.h (which means
GCC trunk will reject older libstdc++ headers at least until we get
smarter about how we recognize built-ins), I'm leaning towards not
implementing an __is_void built-in for now.

In that case we should probably define a built-in for is_object since
we can no longer implement it solely in terms of other built-ins, and
fortunately the name __is_object seems to never have been used in
libstdc++ so we won't have to deal with any name conflicts unlike with
__is_void.

Jonathan, what do you think?

> 
> gcc/cp/ChangeLog:
> 
> 	* cp-trait.def: Define __is_void.
> 	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_VOID.
> 	* semantics.cc (trait_expr_value): Likewise.
> 	(finish_trait_expr): Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/tm/pr46567.C (__is_void): Rename to ...
> 	(____is_void): ... this.
> 	* g++.dg/ext/has-builtin-1.C: Test existence of __is_void.
> 	* g++.dg/ext/is_void.C: New test.
> 
> libstdc++-v3/ChangeLog:
> 
> 	* include/debug/helper_functions.h (_DiffTraits): Stop using
> 	__is_void.
> 	* include/bits/cpp_type_traits.h (__is_void): Remove unused __is_void.
> 	* include/std/type_traits (is_void_v): Use __is_void built-in
> 	trait.
> 
> Signed-off-by: Ken Matsui <kmatsui@cs.washington.edu>
> ---
>  gcc/cp/constraint.cc                          |  3 ++
>  gcc/cp/cp-trait.def                           |  1 +
>  gcc/cp/semantics.cc                           |  4 +++
>  gcc/testsuite/g++.dg/ext/has-builtin-1.C      |  3 ++
>  gcc/testsuite/g++.dg/ext/is_void.C            | 35 +++++++++++++++++++
>  gcc/testsuite/g++.dg/tm/pr46567.C             |  6 ++--
>  libstdc++-v3/include/bits/cpp_type_traits.h   | 15 --------
>  libstdc++-v3/include/debug/helper_functions.h |  5 ++-
>  libstdc++-v3/include/std/type_traits          |  6 ++++
>  9 files changed, 57 insertions(+), 21 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_void.C
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index 927605c6cb7..e8cd98eb2c7 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -3757,6 +3757,9 @@ diagnose_trait_expr (tree expr, tree args)
>      case CPTK_IS_FUNCTION:
>        inform (loc, "  %qT is not a function", t1);
>        break;
> +    case CPTK_IS_VOID:
> +      inform (loc, "  %qT is not a void type", t1);
> +      break;
>      case CPTK_IS_AGGREGATE:
>        inform (loc, "  %qT is not an aggregate", t1);
>        break;
> diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
> index 3cd3babc242..8e76668f6ed 100644
> --- a/gcc/cp/cp-trait.def
> +++ b/gcc/cp/cp-trait.def
> @@ -84,6 +84,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
>  DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
>  DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
>  DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
> +DEFTRAIT_EXPR (IS_VOID, "__is_void", 1)
>  DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
>  DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
>  /* FIXME Added space to avoid direct usage in GCC 13.  */
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index b976633645a..c4d44413dce 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -12075,6 +12075,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
>      case CPTK_IS_FUNCTION:
>        return type_code1 == FUNCTION_TYPE;
>  
> +    case CPTK_IS_VOID:
> +      return VOID_TYPE_P (type1);
> +
>      case CPTK_IS_FINAL:
>        return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1);
>  
> @@ -12297,6 +12300,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
>      case CPTK_IS_SAME:
>      case CPTK_IS_REFERENCE:
>      case CPTK_IS_FUNCTION:
> +    case CPTK_IS_VOID:
>        break;
>  
>      case CPTK_IS_LAYOUT_COMPATIBLE:
> diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> index 90eb00ebf2d..b96cc9e6f50 100644
> --- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> +++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> @@ -152,3 +152,6 @@
>  #if !__has_builtin (__is_function)
>  # error "__has_builtin (__is_function) failed"
>  #endif
> +#if !__has_builtin (__is_void)
> +# error "__has_builtin (__is_void) failed"
> +#endif
> diff --git a/gcc/testsuite/g++.dg/ext/is_void.C b/gcc/testsuite/g++.dg/ext/is_void.C
> new file mode 100644
> index 00000000000..707f0d6875b
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/is_void.C
> @@ -0,0 +1,35 @@
> +// { dg-do compile { target c++11 } }
> +
> +#include <testsuite_tr1.h>
> +
> +using namespace __gnu_test;
> +
> +#define SA(X) static_assert((X),#X)
> +#define SA_TEST_CATEGORY(TRAIT, TYPE, EXPECT)	\
> +  SA(TRAIT(TYPE) == EXPECT);					\
> +  SA(TRAIT(const TYPE) == EXPECT);				\
> +  SA(TRAIT(volatile TYPE) == EXPECT);			\
> +  SA(TRAIT(const volatile TYPE) == EXPECT)
> +
> +SA_TEST_CATEGORY(__is_void, void, true);
> +
> +SA_TEST_CATEGORY(__is_void, char, false);
> +SA_TEST_CATEGORY(__is_void, signed char, false);
> +SA_TEST_CATEGORY(__is_void, unsigned char, false);
> +SA_TEST_CATEGORY(__is_void, wchar_t, false);
> +SA_TEST_CATEGORY(__is_void, short, false);
> +SA_TEST_CATEGORY(__is_void, unsigned short, false);
> +SA_TEST_CATEGORY(__is_void, int, false);
> +SA_TEST_CATEGORY(__is_void, unsigned int, false);
> +SA_TEST_CATEGORY(__is_void, long, false);
> +SA_TEST_CATEGORY(__is_void, unsigned long, false);
> +SA_TEST_CATEGORY(__is_void, long long, false);
> +SA_TEST_CATEGORY(__is_void, unsigned long long, false);
> +SA_TEST_CATEGORY(__is_void, float, false);
> +SA_TEST_CATEGORY(__is_void, double, false);
> +SA_TEST_CATEGORY(__is_void, long double, false);
> +
> +// Sanity check.
> +SA_TEST_CATEGORY(__is_void, ClassType, false);
> +SA_TEST_CATEGORY(__is_void, IncompleteClass, false);
> +SA_TEST_CATEGORY(__is_void, IncompleteUnion, false);
> diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
> index 6d791484448..e689e293bd4 100644
> --- a/gcc/testsuite/g++.dg/tm/pr46567.C
> +++ b/gcc/testsuite/g++.dg/tm/pr46567.C
> @@ -72,13 +72,13 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
>        typedef __true_type __type;
>      };
>    template<typename _Tp>
> -    struct __is_void
> +    struct ____is_void
>      {
>        enum { __value = 0 };
>        typedef __false_type __type;
>      };
>    template<>
> -    struct __is_void<void>
> +    struct ____is_void<void>
>      {
>        enum { __value = 1 };
>        typedef __true_type __type;
> @@ -222,7 +222,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
>      { };
>    template<typename _Tp>
>      struct __is_fundamental
> -    : public __traitor<__is_void<_Tp>, __is_arithmetic<_Tp> >
> +    : public __traitor<____is_void<_Tp>, __is_arithmetic<_Tp> >
>      { };
>    template<typename _Tp>
>      struct __is_scalar
> diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
> index 4312f32a4e0..d329bc5b208 100644
> --- a/libstdc++-v3/include/bits/cpp_type_traits.h
> +++ b/libstdc++-v3/include/bits/cpp_type_traits.h
> @@ -105,21 +105,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        typedef __true_type __type;
>      };
>  
> -  // Holds if the template-argument is a void type.
> -  template<typename _Tp>
> -    struct __is_void
> -    {
> -      enum { __value = 0 };
> -      typedef __false_type __type;
> -    };
> -
> -  template<>
> -    struct __is_void<void>
> -    {
> -      enum { __value = 1 };
> -      typedef __true_type __type;
> -    };
> -
>    //
>    // Integer types
>    //
> diff --git a/libstdc++-v3/include/debug/helper_functions.h b/libstdc++-v3/include/debug/helper_functions.h
> index dccf8e9e5e6..66b4e9e1ecf 100644
> --- a/libstdc++-v3/include/debug/helper_functions.h
> +++ b/libstdc++-v3/include/debug/helper_functions.h
> @@ -66,13 +66,12 @@ namespace __gnu_debug
>        typedef
>  	typename std::iterator_traits<_Iterator>::difference_type _ItDiffType;
>  
> -      template<typename _DiffType,
> -	       typename = typename std::__is_void<_DiffType>::__type>
> +      template<typename _DiffType, typename = _DiffType>
>  	struct _DiffTraits
>  	{ typedef _DiffType __type; };
>  
>        template<typename _DiffType>
> -	struct _DiffTraits<_DiffType, std::__true_type>
> +	struct _DiffTraits<_DiffType, void>
>  	{ typedef std::ptrdiff_t __type; };
>  
>        typedef typename _DiffTraits<_ItDiffType>::__type _DiffType;
> diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
> index 954b57518de..780fcc00135 100644
> --- a/libstdc++-v3/include/std/type_traits
> +++ b/libstdc++-v3/include/std/type_traits
> @@ -3166,8 +3166,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>     * @{
>     * @ingroup variable_templates
>     */
> +#if __has_builtin(__is_void)
> +template <typename _Tp>
> +  inline constexpr bool is_void_v = __is_void(_Tp);
> +#else
>  template <typename _Tp>
>    inline constexpr bool is_void_v = is_void<_Tp>::value;
> +#endif

We should instead optimize this the way we do for the class template, by
defining 4 explicit specializations of is_void_v.

> +
>  template <typename _Tp>
>    inline constexpr bool is_null_pointer_v = is_null_pointer<_Tp>::value;
>  template <typename _Tp>
> -- 
> 2.41.0
> 
>
  

Patch

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 927605c6cb7..e8cd98eb2c7 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3757,6 +3757,9 @@  diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_FUNCTION:
       inform (loc, "  %qT is not a function", t1);
       break;
+    case CPTK_IS_VOID:
+      inform (loc, "  %qT is not a void type", t1);
+      break;
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 3cd3babc242..8e76668f6ed 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -84,6 +84,7 @@  DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
 DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
+DEFTRAIT_EXPR (IS_VOID, "__is_void", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 /* FIXME Added space to avoid direct usage in GCC 13.  */
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index b976633645a..c4d44413dce 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12075,6 +12075,9 @@  trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_FUNCTION:
       return type_code1 == FUNCTION_TYPE;
 
+    case CPTK_IS_VOID:
+      return VOID_TYPE_P (type1);
+
     case CPTK_IS_FINAL:
       return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1);
 
@@ -12297,6 +12300,7 @@  finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_FUNCTION:
+    case CPTK_IS_VOID:
       break;
 
     case CPTK_IS_LAYOUT_COMPATIBLE:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 90eb00ebf2d..b96cc9e6f50 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -152,3 +152,6 @@ 
 #if !__has_builtin (__is_function)
 # error "__has_builtin (__is_function) failed"
 #endif
+#if !__has_builtin (__is_void)
+# error "__has_builtin (__is_void) failed"
+#endif
diff --git a/gcc/testsuite/g++.dg/ext/is_void.C b/gcc/testsuite/g++.dg/ext/is_void.C
new file mode 100644
index 00000000000..707f0d6875b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_void.C
@@ -0,0 +1,35 @@ 
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+#define SA_TEST_CATEGORY(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);					\
+  SA(TRAIT(const TYPE) == EXPECT);				\
+  SA(TRAIT(volatile TYPE) == EXPECT);			\
+  SA(TRAIT(const volatile TYPE) == EXPECT)
+
+SA_TEST_CATEGORY(__is_void, void, true);
+
+SA_TEST_CATEGORY(__is_void, char, false);
+SA_TEST_CATEGORY(__is_void, signed char, false);
+SA_TEST_CATEGORY(__is_void, unsigned char, false);
+SA_TEST_CATEGORY(__is_void, wchar_t, false);
+SA_TEST_CATEGORY(__is_void, short, false);
+SA_TEST_CATEGORY(__is_void, unsigned short, false);
+SA_TEST_CATEGORY(__is_void, int, false);
+SA_TEST_CATEGORY(__is_void, unsigned int, false);
+SA_TEST_CATEGORY(__is_void, long, false);
+SA_TEST_CATEGORY(__is_void, unsigned long, false);
+SA_TEST_CATEGORY(__is_void, long long, false);
+SA_TEST_CATEGORY(__is_void, unsigned long long, false);
+SA_TEST_CATEGORY(__is_void, float, false);
+SA_TEST_CATEGORY(__is_void, double, false);
+SA_TEST_CATEGORY(__is_void, long double, false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_void, ClassType, false);
+SA_TEST_CATEGORY(__is_void, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_void, IncompleteUnion, false);
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index 6d791484448..e689e293bd4 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -72,13 +72,13 @@  namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef __true_type __type;
     };
   template<typename _Tp>
-    struct __is_void
+    struct ____is_void
     {
       enum { __value = 0 };
       typedef __false_type __type;
     };
   template<>
-    struct __is_void<void>
+    struct ____is_void<void>
     {
       enum { __value = 1 };
       typedef __true_type __type;
@@ -222,7 +222,7 @@  namespace std __attribute__ ((__visibility__ ("default"))) {
     { };
   template<typename _Tp>
     struct __is_fundamental
-    : public __traitor<__is_void<_Tp>, __is_arithmetic<_Tp> >
+    : public __traitor<____is_void<_Tp>, __is_arithmetic<_Tp> >
     { };
   template<typename _Tp>
     struct __is_scalar
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 4312f32a4e0..d329bc5b208 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -105,21 +105,6 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       typedef __true_type __type;
     };
 
-  // Holds if the template-argument is a void type.
-  template<typename _Tp>
-    struct __is_void
-    {
-      enum { __value = 0 };
-      typedef __false_type __type;
-    };
-
-  template<>
-    struct __is_void<void>
-    {
-      enum { __value = 1 };
-      typedef __true_type __type;
-    };
-
   //
   // Integer types
   //
diff --git a/libstdc++-v3/include/debug/helper_functions.h b/libstdc++-v3/include/debug/helper_functions.h
index dccf8e9e5e6..66b4e9e1ecf 100644
--- a/libstdc++-v3/include/debug/helper_functions.h
+++ b/libstdc++-v3/include/debug/helper_functions.h
@@ -66,13 +66,12 @@  namespace __gnu_debug
       typedef
 	typename std::iterator_traits<_Iterator>::difference_type _ItDiffType;
 
-      template<typename _DiffType,
-	       typename = typename std::__is_void<_DiffType>::__type>
+      template<typename _DiffType, typename = _DiffType>
 	struct _DiffTraits
 	{ typedef _DiffType __type; };
 
       template<typename _DiffType>
-	struct _DiffTraits<_DiffType, std::__true_type>
+	struct _DiffTraits<_DiffType, void>
 	{ typedef std::ptrdiff_t __type; };
 
       typedef typename _DiffTraits<_ItDiffType>::__type _DiffType;
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 954b57518de..780fcc00135 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3166,8 +3166,14 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
    * @{
    * @ingroup variable_templates
    */
+#if __has_builtin(__is_void)
+template <typename _Tp>
+  inline constexpr bool is_void_v = __is_void(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_void_v = is_void<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_null_pointer_v = is_null_pointer<_Tp>::value;
 template <typename _Tp>